1460 lines
46 KiB
TypeScript
1460 lines
46 KiB
TypeScript
import { IndexedDb, IndexedDbDatabase, IndexedDbTable, IndexedDbVersion } from "@effect/platform-browser"
|
|
import { afterEach, assert, describe, it } from "@effect/vitest"
|
|
import {
|
|
Array,
|
|
Context,
|
|
DateTime,
|
|
Effect,
|
|
Fiber,
|
|
Layer,
|
|
Option,
|
|
Schema,
|
|
SchemaGetter,
|
|
SchemaIssue,
|
|
Stream
|
|
} from "effect"
|
|
import { IDBKeyRange, indexedDB } from "fake-indexeddb"
|
|
|
|
const databaseName = "db"
|
|
|
|
const layerFakeIndexedDb = Layer.succeed(
|
|
IndexedDb.IndexedDb,
|
|
IndexedDb.make({ indexedDB, IDBKeyRange })
|
|
)
|
|
|
|
const provideDb = (database: IndexedDbDatabase.Any) =>
|
|
Effect.provide(
|
|
database.layer(databaseName).pipe(Layer.provide(layerFakeIndexedDb))
|
|
)
|
|
|
|
afterEach(() => {
|
|
indexedDB.deleteDatabase(databaseName)
|
|
})
|
|
|
|
class Table1 extends IndexedDbTable.make({
|
|
name: "todo",
|
|
schema: Schema.Struct({
|
|
id: Schema.Number,
|
|
title: Schema.String,
|
|
count: Schema.Number,
|
|
completed: Schema.Boolean
|
|
}),
|
|
keyPath: "id",
|
|
indexes: { titleIndex: "title", countIndex: "count", titleCount: ["title", "count"] }
|
|
}) {}
|
|
|
|
class User extends Schema.Class<User>("User")({
|
|
id: Schema.Number,
|
|
name: Schema.String,
|
|
email: Schema.String,
|
|
createdAt: Schema.DateTimeUtcFromMillis
|
|
}) {}
|
|
|
|
class ProductSchema extends Schema.Class<ProductSchema>("ProductSchema")({
|
|
key: IndexedDb.AutoIncrement,
|
|
name: Schema.String,
|
|
price: Schema.Number
|
|
}) {}
|
|
|
|
class VerifyContext extends Context.Service<
|
|
VerifyContext,
|
|
{ readonly maxLength: number }
|
|
>()("VerifyContext") {}
|
|
|
|
const VerifyId = Schema.String.pipe(
|
|
Schema.decodeTo(Schema.String, {
|
|
encode: SchemaGetter.transformOrFail((s) =>
|
|
Effect.gen(function*() {
|
|
const { maxLength } = yield* VerifyContext
|
|
if (s.length > maxLength) {
|
|
return yield* Effect.fail(
|
|
new SchemaIssue.InvalidValue(Option.some(s), {
|
|
message: "Max length exceeded"
|
|
})
|
|
)
|
|
}
|
|
return s
|
|
})
|
|
),
|
|
decode: SchemaGetter.String()
|
|
})
|
|
)
|
|
|
|
const Table2 = IndexedDbTable.make({
|
|
name: "user",
|
|
schema: User,
|
|
keyPath: "id"
|
|
})
|
|
|
|
const Table3 = IndexedDbTable.make({
|
|
name: "product",
|
|
schema: ProductSchema,
|
|
keyPath: "price"
|
|
})
|
|
|
|
const Table4 = IndexedDbTable.make({
|
|
name: "price",
|
|
schema: Schema.Struct({
|
|
id: IndexedDb.AutoIncrement,
|
|
amount: Schema.Number
|
|
}),
|
|
keyPath: "id",
|
|
autoIncrement: true
|
|
})
|
|
|
|
const Table5 = IndexedDbTable.make({
|
|
name: "person",
|
|
schema: Schema.Struct({
|
|
firstName: Schema.String,
|
|
lastName: Schema.String,
|
|
age: Schema.Number
|
|
}),
|
|
keyPath: ["firstName", "lastName"]
|
|
})
|
|
|
|
const Table6 = IndexedDbTable.make({
|
|
name: "user-verify",
|
|
schema: Schema.Struct({ id: VerifyId }),
|
|
keyPath: "id"
|
|
})
|
|
|
|
const Table7 = IndexedDbTable.make({
|
|
name: "no-keypath",
|
|
schema: Schema.Struct({ username: Schema.String, index: Schema.Number })
|
|
})
|
|
|
|
class V1 extends IndexedDbVersion.make(
|
|
Table1,
|
|
Table2,
|
|
Table3,
|
|
Table4,
|
|
Table5,
|
|
Table6,
|
|
Table7
|
|
) {}
|
|
|
|
describe.sequential("IndexedDbQueryBuilder", () => {
|
|
describe("select", () => {
|
|
it.effect("select", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api
|
|
.from("todo")
|
|
.insert({ id: 1, title: "test", count: 1, completed: false })
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const from = api.from("todo")
|
|
const select = from.select()
|
|
const data = yield* select
|
|
|
|
assert.equal(from.table.tableName, "todo")
|
|
assert.equal(select.index, undefined)
|
|
assert.deepStrictEqual(select.from, from)
|
|
assert.deepStrictEqual(select.from.IDBKeyRange, IDBKeyRange)
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 1, title: "test", count: 1, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select with index", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api
|
|
.from("todo")
|
|
.insert({ id: 2, title: "test2", count: 2, completed: false })
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db
|
|
const from = api.from("todo")
|
|
const select = from.select("titleIndex")
|
|
const data = yield* select
|
|
|
|
assert.equal(from.table.tableName, "todo")
|
|
assert.equal(select.index, "titleIndex")
|
|
assert.deepStrictEqual(select.from, from)
|
|
assert.deepStrictEqual(select.from.IDBKeyRange, IDBKeyRange)
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 2, title: "test2", count: 2, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select equals", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
{
|
|
const api = yield* Db
|
|
const from = api.from("todo")
|
|
const select = from.select()
|
|
const equals = select.equals(2)
|
|
const data = yield* equals
|
|
|
|
assert.equal(from.table.tableName, "todo")
|
|
assert.equal(equals.index, undefined)
|
|
assert.deepStrictEqual(equals.from, from)
|
|
assert.deepStrictEqual(equals.from.IDBKeyRange, IDBKeyRange)
|
|
assert.equal(equals.only, 2)
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 2, title: "test2", count: 2, completed: false }
|
|
])
|
|
}
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select equals with index", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
{
|
|
const api = yield* Db
|
|
const from = api.from("todo")
|
|
const select = from.select("titleIndex")
|
|
const equals = select.equals("test3")
|
|
const data = yield* equals
|
|
|
|
assert.equal(from.table.tableName, "todo")
|
|
assert.equal(equals.index, "titleIndex")
|
|
assert.deepStrictEqual(equals.from, from)
|
|
assert.deepStrictEqual(equals.from.IDBKeyRange, IDBKeyRange)
|
|
assert.equal(equals.only, "test3")
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
}
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select gte", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").select().gte(2)
|
|
|
|
assert.equal(data.length, 2)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select gte with index", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").select("countIndex").gte(3)
|
|
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select lte", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
{
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").select().lte(2)
|
|
|
|
assert.equal(data.length, 2)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false }
|
|
])
|
|
}
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select gt", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").select().gt(2)
|
|
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select lt", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").select().lt(2)
|
|
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 1, title: "test1", count: 1, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select between", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false },
|
|
{ id: 4, title: "test4", count: 4, completed: false },
|
|
{ id: 5, title: "test5", count: 5, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").select().between(2, 3)
|
|
|
|
assert.equal(data.length, 2)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select between with exclude", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false },
|
|
{ id: 4, title: "test4", count: 4, completed: false },
|
|
{ id: 5, title: "test5", count: 5, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").select().between(2, 4, {
|
|
excludeLowerBound: true,
|
|
excludeUpperBound: true
|
|
})
|
|
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select limit", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false },
|
|
{ id: 4, title: "test4", count: 4, completed: false },
|
|
{ id: 5, title: "test5", count: 5, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").select().limit(2)
|
|
|
|
assert.equal(data.length, 2)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select offset", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false },
|
|
{ id: 4, title: "test4", count: 4, completed: false },
|
|
{ id: 5, title: "test5", count: 5, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").select().limit(2).offset(2)
|
|
|
|
assert.equal(data.length, 2)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 3, title: "test3", count: 3, completed: false },
|
|
{ id: 4, title: "test4", count: 4, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select limit with filters", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false },
|
|
{ id: 4, title: "test4", count: 4, completed: false },
|
|
{ id: 5, title: "test5", count: 5, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api
|
|
.from("todo")
|
|
.select("countIndex")
|
|
.gte(2)
|
|
.limit(2)
|
|
|
|
assert.equal(data.length, 2)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select first", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").select().first()
|
|
|
|
assert.deepStrictEqual(data, {
|
|
id: 1,
|
|
title: "test1",
|
|
count: 1,
|
|
completed: false
|
|
})
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("select first with filters", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api
|
|
.from("todo")
|
|
.select("titleIndex")
|
|
.equals("test2")
|
|
.first()
|
|
|
|
assert.deepStrictEqual(data, {
|
|
id: 2,
|
|
title: "test2",
|
|
count: 2,
|
|
completed: false
|
|
})
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
})
|
|
|
|
describe("modify", () => {
|
|
it.effect("insert", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api
|
|
.from("todo")
|
|
.insert({ id: 10, title: "insert1", count: 10, completed: true })
|
|
const data = yield* api.from("todo").select()
|
|
|
|
assert.equal(addedKey, 10)
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 10, title: "insert1", count: 10, completed: true }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("insert schema with context", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("user-verify")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api.from("user-verify").insert({ id: "abc" })
|
|
const data = yield* api.from("user-verify").select()
|
|
|
|
assert.equal(addedKey, "abc")
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [{ id: "abc" }])
|
|
}).pipe(
|
|
provideDb(Db),
|
|
Effect.provideService(
|
|
VerifyContext,
|
|
VerifyContext.of({ maxLength: 4 })
|
|
)
|
|
)
|
|
})
|
|
|
|
it.effect("insert with manual key required", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createObjectStore("user")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const createdAt = DateTime.nowUnsafe()
|
|
const addedKey = yield* api.from("user").insert({
|
|
id: 10,
|
|
name: "insert1",
|
|
email: "insert1@example.com",
|
|
createdAt
|
|
})
|
|
const addedAllKeys = yield* api.from("user").insertAll([
|
|
{
|
|
id: 11,
|
|
name: "insert2",
|
|
email: "insert2@example.com",
|
|
createdAt
|
|
},
|
|
{
|
|
id: 12,
|
|
name: "insert3",
|
|
email: "insert3@example.com",
|
|
createdAt
|
|
}
|
|
])
|
|
const data = yield* api.from("user").select()
|
|
|
|
assert.equal(addedKey, 10)
|
|
assert.deepStrictEqual(addedAllKeys, [11, 12])
|
|
assert.equal(data.length, 3)
|
|
assert.deepStrictEqual(data, [
|
|
new User({
|
|
id: 10,
|
|
name: "insert1",
|
|
email: "insert1@example.com",
|
|
createdAt
|
|
}),
|
|
new User({
|
|
id: 11,
|
|
name: "insert2",
|
|
email: "insert2@example.com",
|
|
createdAt
|
|
}),
|
|
new User({
|
|
id: 12,
|
|
name: "insert3",
|
|
email: "insert3@example.com",
|
|
createdAt
|
|
})
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("insert with manual multiple keys required", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createObjectStore("user")
|
|
yield* api.createObjectStore("person")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api.from("person").insert({
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
age: 30
|
|
})
|
|
const data = yield* api.from("person").select()
|
|
|
|
assert.deepStrictEqual(addedKey, ["John", "Doe"])
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ firstName: "John", lastName: "Doe", age: 30 }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("insert with manual key optional", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createObjectStore("user")
|
|
yield* api.createObjectStore("product")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api.from("product").insert({
|
|
key: 10,
|
|
name: "insert1",
|
|
price: 10
|
|
})
|
|
const data = yield* api.from("product").select()
|
|
|
|
assert.equal(addedKey, 10)
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [new ProductSchema({ key: 10, name: "insert1", price: 10 })])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("insert with auto-increment", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createObjectStore("user")
|
|
yield* api.createObjectStore("product")
|
|
yield* api.createObjectStore("price")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api
|
|
.from("price")
|
|
.insertAll([{ amount: 10 }, { amount: 20, id: 10 }, { amount: 30 }])
|
|
const data = yield* api.from("price").select()
|
|
|
|
assert.deepStrictEqual(addedKey, [1, 10, 11])
|
|
assert.equal(data.length, 3)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 1, amount: 10 },
|
|
{ id: 10, amount: 20 },
|
|
{ id: 11, amount: 30 }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("insert with auto-increment and get first", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createObjectStore("user")
|
|
yield* api.createObjectStore("product")
|
|
yield* api.createObjectStore("price")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api.from("price").insert({ amount: 10 })
|
|
const data = yield* api.from("price").select().first()
|
|
|
|
assert.equal(addedKey, 1)
|
|
assert.deepStrictEqual(data, { id: 1, amount: 10 })
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect(
|
|
"insert with auto-increment schema and different key path",
|
|
() => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("product")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api
|
|
.from("product")
|
|
.insert({ name: "insert1", price: 12, key: 10 })
|
|
const data = yield* api.from("product").select()
|
|
|
|
assert.equal(addedKey, 12)
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
new ProductSchema({ key: 10, name: "insert1", price: 12 })
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
}
|
|
)
|
|
|
|
it.effect("insert in no keypath table with manual key", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("no-keypath")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api
|
|
.from("no-keypath")
|
|
.insert({ username: "insert1", index: 12, key: "key" })
|
|
const data = yield* api.from("no-keypath").select()
|
|
|
|
assert.equal(addedKey, "key")
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ username: "insert1", index: 12, key: "key" }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("insertAll in no keypath table with manual key", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("no-keypath")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api.from("no-keypath").insertAll([
|
|
{ username: "insert1", index: 12, key: "key" },
|
|
{
|
|
username: "insert2",
|
|
index: 13,
|
|
key: "key2"
|
|
}
|
|
])
|
|
const data = yield* api.from("no-keypath").select()
|
|
|
|
assert.deepStrictEqual(addedKey, ["key", "key2"])
|
|
assert.equal(data.length, 2)
|
|
assert.deepStrictEqual(data, [
|
|
{ username: "insert1", index: 12, key: "key" },
|
|
{
|
|
username: "insert2",
|
|
index: 13,
|
|
key: "key2"
|
|
}
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("insertAll in no keypath table and get first", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("no-keypath")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api.from("no-keypath").insertAll([
|
|
{ username: "insert1", index: 12, key: "key" },
|
|
{
|
|
username: "insert2",
|
|
index: 13,
|
|
key: "key2"
|
|
}
|
|
])
|
|
const data = yield* api.from("no-keypath").select().first()
|
|
|
|
assert.deepStrictEqual(addedKey, ["key", "key2"])
|
|
assert.deepStrictEqual(data, {
|
|
username: "insert1",
|
|
index: 12,
|
|
key: "key"
|
|
})
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("insertAll in no keypath table and get limit", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("no-keypath")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api.from("no-keypath").insertAll([
|
|
{ username: "insert1", index: 12, key: "key" },
|
|
{
|
|
username: "insert2",
|
|
index: 13,
|
|
key: "key2"
|
|
}
|
|
])
|
|
const data = yield* api.from("no-keypath").select().limit(1)
|
|
|
|
assert.deepStrictEqual(addedKey, ["key", "key2"])
|
|
assert.deepStrictEqual(data, [
|
|
{ username: "insert1", index: 12, key: "key" }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect(
|
|
"insertAll in no keypath table with multiple types of keys",
|
|
() => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("no-keypath")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const date = new Date()
|
|
const arrayBuffer = new ArrayBuffer(10)
|
|
const addedKey = yield* api.from("no-keypath").insertAll([
|
|
{ username: "insert1", index: 12, key: "key" },
|
|
{
|
|
username: "insert2",
|
|
index: 13,
|
|
key: 14
|
|
},
|
|
{
|
|
username: "insert3",
|
|
index: 14,
|
|
key: date
|
|
},
|
|
{
|
|
username: "insert4",
|
|
index: 15,
|
|
key: arrayBuffer
|
|
},
|
|
{
|
|
username: "insert5",
|
|
index: 16,
|
|
key: [1, "key", date, arrayBuffer]
|
|
}
|
|
])
|
|
const data = yield* api.from("no-keypath").select()
|
|
|
|
// Returned data order not guaranteed
|
|
data.sort((a, b) => a.index - b.index)
|
|
|
|
assert.deepStrictEqual(addedKey, [
|
|
"key",
|
|
14,
|
|
date,
|
|
arrayBuffer,
|
|
[1, "key", date, arrayBuffer]
|
|
])
|
|
assert.deepStrictEqual(data, [
|
|
{ username: "insert1", index: 12, key: "key" },
|
|
{
|
|
username: "insert2",
|
|
index: 13,
|
|
key: 14
|
|
},
|
|
{ username: "insert3", index: 14, key: date },
|
|
{ username: "insert4", index: 15, key: arrayBuffer },
|
|
{
|
|
username: "insert5",
|
|
index: 16,
|
|
key: [1, "key", date, arrayBuffer]
|
|
}
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
}
|
|
)
|
|
|
|
it.effect("upsert", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api
|
|
.from("todo")
|
|
.insert({ id: 10, title: "insert1", count: 10, completed: true })
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKey = yield* api
|
|
.from("todo")
|
|
.upsert({ id: 10, title: "update1", count: -10, completed: false })
|
|
const data = yield* api.from("todo").select()
|
|
|
|
assert.equal(addedKey, 10)
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 10, title: "update1", count: -10, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("delete", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 10, title: "insert1", count: 10, completed: true },
|
|
{ id: 11, title: "insert2", count: 11, completed: true }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
yield* api.from("todo").delete().equals(10)
|
|
const data = yield* api.from("todo").select()
|
|
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 11, title: "insert2", count: 11, completed: true }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("delete with limit", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 10, title: "insert1", count: 10, completed: true },
|
|
{ id: 11, title: "insert2", count: 11, completed: true },
|
|
{ id: 12, title: "insert3", count: 12, completed: true }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
yield* api.from("todo").delete().limit(2)
|
|
const data = yield* api.from("todo").select()
|
|
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 12, title: "insert3", count: 12, completed: true }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("clear", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 10, title: "insert1", count: 10, completed: true },
|
|
{ id: 11, title: "insert2", count: 11, completed: true }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
yield* api.from("todo").clear
|
|
const data = yield* api.from("todo").select()
|
|
|
|
assert.equal(data.length, 0)
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
})
|
|
|
|
describe("modify all", () => {
|
|
it.effect("insertAll", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKeys = yield* api.from("todo").insertAll([
|
|
{ id: 10, title: "insert1", count: 10, completed: true },
|
|
{ id: 11, title: "insert2", count: 11, completed: true }
|
|
])
|
|
const data = yield* api.from("todo").select()
|
|
|
|
assert.deepStrictEqual(addedKeys, [10, 11])
|
|
assert.equal(data.length, 2)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 10, title: "insert1", count: 10, completed: true },
|
|
{ id: 11, title: "insert2", count: 11, completed: true }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("upsertAll", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 10, title: "insert1", count: 10, completed: true },
|
|
{ id: 11, title: "insert2", count: 11, completed: true }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKeys = yield* api.from("todo").upsertAll([
|
|
{ id: 10, title: "update1", count: -10, completed: false },
|
|
{ id: 11, title: "update2", count: -11, completed: false }
|
|
])
|
|
const data = yield* api.from("todo").select()
|
|
|
|
assert.deepStrictEqual(addedKeys, [10, 11])
|
|
assert.equal(data.length, 2)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 10, title: "update1", count: -10, completed: false },
|
|
{ id: 11, title: "update2", count: -11, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("upsertAll withTransaction", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 10, title: "insert1", count: 10, completed: true },
|
|
{ id: 11, title: "insert2", count: 11, completed: true }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKeys = yield* api.withTransaction({ tables: ["todo"], mode: "readwrite" })(
|
|
Effect.gen(function*() {
|
|
return yield* api.from("todo").upsertAll([
|
|
{ id: 10, title: "update1", count: -10, completed: false },
|
|
{ id: 11, title: "update2", count: -11, completed: false }
|
|
]).invalidate()
|
|
})
|
|
)
|
|
const data = yield* api.from("todo").select()
|
|
|
|
assert.deepStrictEqual(addedKeys, [10, 11])
|
|
assert.equal(data.length, 2)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 10, title: "update1", count: -10, completed: false },
|
|
{ id: 11, title: "update2", count: -11, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("upsertAll same key", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api
|
|
.from("todo")
|
|
.insert({ id: 10, title: "insert1", count: 10, completed: true })
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const addedKeys = yield* api.from("todo").upsertAll([
|
|
{ id: 10, title: "update1", count: -10, completed: false },
|
|
{ id: 10, title: "update2", count: -11, completed: false }
|
|
])
|
|
const data = yield* api.from("todo").select()
|
|
|
|
assert.deepStrictEqual(addedKeys, [10, 10])
|
|
assert.equal(data.length, 1)
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 10, title: "update2", count: -11, completed: false }
|
|
])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("clearAll", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api
|
|
.from("todo")
|
|
.insert({ id: 10, title: "insert1", count: 10, completed: true })
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
yield* api.clearAll
|
|
const data = yield* api.from("todo").select()
|
|
|
|
assert.equal(data.length, 0)
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
})
|
|
|
|
it.effect("count", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db.getQueryBuilder
|
|
const data = yield* api.from("todo").count()
|
|
|
|
assert.equal(data, 3)
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("count with filters", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db
|
|
const data = yield* api.from("todo").count("titleIndex").equals("test2")
|
|
|
|
assert.equal(data, 1)
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("filter", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db
|
|
const data = yield* api.from("todo").select().filter((v) => v.count === 2)
|
|
|
|
assert.deepStrictEqual(data, [{
|
|
id: 2,
|
|
title: "test2",
|
|
count: 2,
|
|
completed: false
|
|
}])
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("stream", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll(
|
|
Array.makeBy(1000, (i) => ({ id: i + 1, title: `test${i}`, count: i, completed: false }))
|
|
)
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db
|
|
const data = yield* api.from("todo").select().stream().pipe(
|
|
Stream.runCollect
|
|
)
|
|
assert.equal(data.length, 1000)
|
|
|
|
const data2 = yield* api.from("todo").select().limit(10).stream().pipe(
|
|
Stream.runCollect
|
|
)
|
|
assert.equal(data2.length, 10)
|
|
assert.equal(data2[0].id, 1)
|
|
|
|
const data3 = yield* api.from("todo").select().limit(10).offset(50).stream().pipe(
|
|
Stream.runCollect
|
|
)
|
|
assert.equal(data3.length, 10)
|
|
assert.equal(data3[0].id, 51)
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("reactive", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test3", count: 3, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db
|
|
const data = yield* api.from("todo").select().reactive().pipe(
|
|
Stream.take(2),
|
|
Stream.runCollect,
|
|
Effect.forkChild({ startImmediately: true })
|
|
)
|
|
yield* api.from("todo").insert({ id: 4, title: "test4", count: 4, completed: false }).invalidate()
|
|
yield* Fiber.join(data)
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
|
|
it.effect("compound query", () => {
|
|
class Db extends IndexedDbDatabase.make(
|
|
V1,
|
|
Effect.fn(function*(api) {
|
|
yield* api.createObjectStore("todo")
|
|
yield* api.createIndex("todo", "titleIndex")
|
|
yield* api.createIndex("todo", "countIndex")
|
|
yield* api.createIndex("todo", "titleCount")
|
|
yield* api.from("todo").insertAll([
|
|
{ id: 1, title: "test1", count: 1, completed: false },
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test2", count: 3, completed: false },
|
|
{ id: 4, title: "test3", count: 4, completed: false }
|
|
])
|
|
})
|
|
) {}
|
|
|
|
return Effect.gen(function*() {
|
|
const api = yield* Db
|
|
const data = yield* api.from("todo").select("titleCount").between(["test2"], ["test2", []])
|
|
assert.deepStrictEqual(data, [
|
|
{ id: 2, title: "test2", count: 2, completed: false },
|
|
{ id: 3, title: "test2", count: 3, completed: false }
|
|
])
|
|
|
|
const data2 = yield* api.from("todo").select("titleCount").equals(["test2", 3]).first()
|
|
assert.deepStrictEqual(data2, { id: 3, title: "test2", count: 3, completed: false })
|
|
}).pipe(provideDb(Db))
|
|
})
|
|
})
|