muya 2.5.3 → 2.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{src/__tests__ → __tests__}/bench.test.tsx +4 -4
- package/{src/__tests__ → __tests__}/compare.test.tsx +8 -6
- package/{src/__tests__ → __tests__}/create.test.tsx +2 -2
- package/{src/utils/__tests__ → __tests__}/is.test.ts +3 -3
- package/{src/__tests__ → __tests__}/scheduler.test.tsx +1 -1
- package/{src/__tests__ → __tests__}/select.test.tsx +5 -5
- package/{src/utils/__tests__ → __tests__}/shallow.test.ts +1 -1
- package/{src/__tests__ → __tests__}/use-value-loadable.test.tsx +3 -3
- package/{src/__tests__ → __tests__}/use-value.test.tsx +8 -8
- package/build.ts +67 -0
- package/dist/cjs/index.js +1 -0
- package/dist/esm/create.js +1 -0
- package/dist/esm/debug/development-tools.js +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/select.js +1 -0
- package/{types → dist/types}/create-state.d.ts +1 -0
- package/dist/types/create-state.d.ts.map +1 -0
- package/{types → dist/types}/create.d.ts +1 -0
- package/dist/types/create.d.ts.map +1 -0
- package/dist/types/debug/development-tools.d.ts +13 -0
- package/dist/types/debug/development-tools.d.ts.map +1 -0
- package/{types → dist/types}/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -0
- package/{types → dist/types}/scheduler.d.ts +1 -0
- package/dist/types/scheduler.d.ts.map +1 -0
- package/{types → dist/types}/select.d.ts +1 -0
- package/dist/types/select.d.ts.map +1 -0
- package/{types → dist/types}/types.d.ts +1 -0
- package/dist/types/types.d.ts.map +1 -0
- package/{types → dist/types}/use-value-loadable.d.ts +1 -0
- package/dist/types/use-value-loadable.d.ts.map +1 -0
- package/{types → dist/types}/use-value.d.ts +2 -1
- package/dist/types/use-value.d.ts.map +1 -0
- package/{types → dist/types}/utils/common.d.ts +1 -0
- package/dist/types/utils/common.d.ts.map +1 -0
- package/{types → dist/types}/utils/create-emitter.d.ts +1 -0
- package/dist/types/utils/create-emitter.d.ts.map +1 -0
- package/{types → dist/types}/utils/id.d.ts +1 -0
- package/dist/types/utils/id.d.ts.map +1 -0
- package/{types → dist/types}/utils/is.d.ts +1 -0
- package/dist/types/utils/is.d.ts.map +1 -0
- package/{types → dist/types}/utils/shallow.d.ts +1 -0
- package/dist/types/utils/shallow.d.ts.map +1 -0
- package/package.json +23 -8
- package/src/create-state.d.ts.map +1 -0
- package/src/create.d.ts.map +1 -0
- package/src/create.ts +7 -2
- package/src/debug/development-tools.d.ts.map +1 -0
- package/src/debug/development-tools.ts +5 -40
- package/src/index.d.ts.map +1 -0
- package/src/index.ts +2 -1
- package/src/scheduler.d.ts.map +1 -0
- package/src/select.d.ts.map +1 -0
- package/src/select.ts +7 -2
- package/src/types.d.ts.map +1 -0
- package/src/use-value-loadable.d.ts.map +1 -0
- package/src/use-value.d.ts.map +1 -0
- package/src/use-value.ts +1 -1
- package/src/utils/common.d.ts.map +1 -0
- package/src/utils/create-emitter.d.ts.map +1 -0
- package/src/utils/id.d.ts.map +1 -0
- package/src/utils/is.d.ts.map +1 -0
- package/src/utils/shallow.d.ts.map +1 -0
- package/tsconfig.build.json +12 -0
- package/cjs/index.js +0 -1
- package/esm/__tests__/test-utils.js +0 -1
- package/esm/create.js +0 -1
- package/esm/debug/development-tools.js +0 -1
- package/esm/index.js +0 -1
- package/esm/select.js +0 -1
- package/esm/sqlite/__tests__/create-sqlite.test.js +0 -1
- package/esm/sqlite/__tests__/map-deque.test.js +0 -1
- package/esm/sqlite/__tests__/table.test.js +0 -1
- package/esm/sqlite/__tests__/tokenizer.test.js +0 -1
- package/esm/sqlite/__tests__/where.test.js +0 -1
- package/esm/sqlite/create-sqlite.js +0 -1
- package/esm/sqlite/index.js +0 -1
- package/esm/sqlite/table/backend.js +0 -1
- package/esm/sqlite/table/bun-backend.js +0 -1
- package/esm/sqlite/table/index.js +0 -1
- package/esm/sqlite/table/map-deque.js +0 -1
- package/esm/sqlite/table/table.js +0 -43
- package/esm/sqlite/table/table.types.js +0 -0
- package/esm/sqlite/table/tokenizer.js +0 -1
- package/esm/sqlite/table/where.js +0 -1
- package/esm/sqlite/use-sqlite-count.js +0 -1
- package/esm/sqlite/use-sqlite.js +0 -1
- package/esm/utils/__tests__/is.test.js +0 -1
- package/esm/utils/__tests__/shallow.test.js +0 -1
- package/src/sqlite/__tests__/create-sqlite.test.ts +0 -264
- package/src/sqlite/__tests__/map-deque.test.ts +0 -61
- package/src/sqlite/__tests__/table.test.ts +0 -351
- package/src/sqlite/__tests__/tokenizer.test.ts +0 -43
- package/src/sqlite/__tests__/use-slite-count.test.tsx +0 -96
- package/src/sqlite/__tests__/use-sqlite.more.test.tsx +0 -637
- package/src/sqlite/__tests__/use-sqlite.test.tsx +0 -1008
- package/src/sqlite/__tests__/where.test.ts +0 -234
- package/src/sqlite/create-sqlite.ts +0 -164
- package/src/sqlite/index.ts +0 -4
- package/src/sqlite/table/backend.ts +0 -21
- package/src/sqlite/table/bun-backend.ts +0 -47
- package/src/sqlite/table/index.ts +0 -6
- package/src/sqlite/table/map-deque.ts +0 -29
- package/src/sqlite/table/table.ts +0 -353
- package/src/sqlite/table/table.types.ts +0 -129
- package/src/sqlite/table/tokenizer.ts +0 -35
- package/src/sqlite/table/where.ts +0 -207
- package/src/sqlite/use-sqlite-count.ts +0 -69
- package/src/sqlite/use-sqlite.ts +0 -250
- package/types/__tests__/test-utils.d.ts +0 -25
- package/types/debug/development-tools.d.ts +0 -8
- package/types/sqlite/create-sqlite.d.ts +0 -31
- package/types/sqlite/index.d.ts +0 -4
- package/types/sqlite/table/backend.d.ts +0 -20
- package/types/sqlite/table/bun-backend.d.ts +0 -6
- package/types/sqlite/table/index.d.ts +0 -6
- package/types/sqlite/table/map-deque.d.ts +0 -5
- package/types/sqlite/table/table.d.ts +0 -21
- package/types/sqlite/table/table.types.d.ts +0 -91
- package/types/sqlite/table/tokenizer.d.ts +0 -11
- package/types/sqlite/table/where.d.ts +0 -37
- package/types/sqlite/use-sqlite-count.d.ts +0 -17
- package/types/sqlite/use-sqlite.d.ts +0 -39
- /package/{src/__tests__ → __tests__}/test-utils.ts +0 -0
- /package/{esm → dist/esm}/create-state.js +0 -0
- /package/{esm → dist/esm}/scheduler.js +0 -0
- /package/{esm → dist/esm}/types.js +0 -0
- /package/{esm → dist/esm}/use-value-loadable.js +0 -0
- /package/{esm → dist/esm}/use-value.js +0 -0
- /package/{esm → dist/esm}/utils/common.js +0 -0
- /package/{esm → dist/esm}/utils/create-emitter.js +0 -0
- /package/{esm → dist/esm}/utils/id.js +0 -0
- /package/{esm → dist/esm}/utils/is.js +0 -0
- /package/{esm → dist/esm}/utils/shallow.js +0 -0
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import { createTable } from '../table'
|
|
2
|
-
import { bunMemoryBackend } from '../table/bun-backend'
|
|
3
|
-
import { type Where } from '../table/where'
|
|
4
|
-
|
|
5
|
-
describe('where clauses', () => {
|
|
6
|
-
const backend = bunMemoryBackend()
|
|
7
|
-
|
|
8
|
-
it('should handle where where array of conditions', async () => {
|
|
9
|
-
const tableNestedOptional = await createTable<{ id: string; content?: string }>({
|
|
10
|
-
backend,
|
|
11
|
-
tableName: 'TestTableNestedOptional',
|
|
12
|
-
key: 'id',
|
|
13
|
-
indexes: ['content'],
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
await tableNestedOptional.set({ id: '1', content: 'The quick brown fox' })
|
|
17
|
-
await tableNestedOptional.set({ id: '2', content: 'The jumps over the lazy dog' })
|
|
18
|
-
await tableNestedOptional.set({ id: '3' }) // No `content` field
|
|
19
|
-
|
|
20
|
-
const results: { id: string; content?: string }[] = []
|
|
21
|
-
for await (const doc of tableNestedOptional.search({
|
|
22
|
-
where: { content: { like: ['The%'] } },
|
|
23
|
-
})) {
|
|
24
|
-
results.push(doc)
|
|
25
|
-
}
|
|
26
|
-
expect(results.length).toBe(2)
|
|
27
|
-
expect(results[0].id).toBe('1')
|
|
28
|
-
})
|
|
29
|
-
it('should create nested index for optional nested fields', async () => {
|
|
30
|
-
type TestDoc = { id: string; info?: { content?: string } }
|
|
31
|
-
const tableNestedOptional = await createTable<TestDoc>({
|
|
32
|
-
backend,
|
|
33
|
-
tableName: 'TestTableNestedOptional',
|
|
34
|
-
key: 'id',
|
|
35
|
-
indexes: ['fts:info.content'],
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
await tableNestedOptional.set({ id: '1', info: { content: 'The quick brown fox' } })
|
|
39
|
-
await tableNestedOptional.set({ id: '2', info: { content: 'jumps over the lazy dog' } })
|
|
40
|
-
await tableNestedOptional.set({ id: '3' }) // No `info` field
|
|
41
|
-
|
|
42
|
-
const results: TestDoc[] = []
|
|
43
|
-
for await (const doc of tableNestedOptional.search({
|
|
44
|
-
where: { info: { content: { like: ['The%'] } } },
|
|
45
|
-
})) {
|
|
46
|
-
results.push(doc)
|
|
47
|
-
}
|
|
48
|
-
expect(results.length).toBe(1)
|
|
49
|
-
expect(results[0].id).toBe('1')
|
|
50
|
-
|
|
51
|
-
const results2: TestDoc[] = []
|
|
52
|
-
for await (const doc of tableNestedOptional.search({
|
|
53
|
-
where: { OR: [{ info: { content: { like: ['The%'] } } }, { info: { content: { like: ['jumps%'] } } }] },
|
|
54
|
-
})) {
|
|
55
|
-
results2.push(doc)
|
|
56
|
-
}
|
|
57
|
-
expect(results2.length).toBe(2)
|
|
58
|
-
|
|
59
|
-
const results3: TestDoc[] = []
|
|
60
|
-
for await (const doc of tableNestedOptional.search({
|
|
61
|
-
where: { info: { content: 'nonexistent' } },
|
|
62
|
-
})) {
|
|
63
|
-
results3.push(doc)
|
|
64
|
-
}
|
|
65
|
-
expect(results3.length).toBe(0)
|
|
66
|
-
})
|
|
67
|
-
it('should handle FTS queries', async () => {
|
|
68
|
-
const tableFts = await createTable<{ id: string; content: string }>({
|
|
69
|
-
backend,
|
|
70
|
-
tableName: 'TestTableFts',
|
|
71
|
-
key: 'id',
|
|
72
|
-
indexes: ['fts:content'],
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
await tableFts.set({ id: '1', content: 'The quick brown fox' })
|
|
76
|
-
await tableFts.set({ id: '2', content: 'Jumps over the lazy dog' })
|
|
77
|
-
await tableFts.set({ id: '3', content: 'Another document' })
|
|
78
|
-
|
|
79
|
-
const results: { id: string; content: string }[] = []
|
|
80
|
-
for await (const doc of tableFts.search({
|
|
81
|
-
where: { content: { fts: 'quick' } },
|
|
82
|
-
})) {
|
|
83
|
-
results.push(doc)
|
|
84
|
-
}
|
|
85
|
-
expect(results.length).toBe(1)
|
|
86
|
-
expect(results[0].id).toBe('1')
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('should handle nested where conditions', async () => {
|
|
90
|
-
const tableNested = await createTable<{ id: string; info: { content: string } }>({
|
|
91
|
-
backend,
|
|
92
|
-
tableName: 'TestTableNested',
|
|
93
|
-
key: 'id',
|
|
94
|
-
indexes: ['info.content'],
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
await tableNested.set({ id: '1', info: { content: 'Nested quick brown fox' } })
|
|
98
|
-
await tableNested.set({ id: '2', info: { content: 'Nested jumps over the lazy dog' } })
|
|
99
|
-
|
|
100
|
-
const results: { id: string; info: { content: string } }[] = []
|
|
101
|
-
for await (const doc of tableNested.search({
|
|
102
|
-
where: { info: { content: { like: 'Nested%' } } },
|
|
103
|
-
})) {
|
|
104
|
-
results.push(doc)
|
|
105
|
-
}
|
|
106
|
-
expect(results.length).toBe(2)
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('should handle complex operators', async () => {
|
|
110
|
-
const tableComplex = await createTable<{ id: string; value: number }>({
|
|
111
|
-
backend,
|
|
112
|
-
tableName: 'TestTableComplex',
|
|
113
|
-
key: 'id',
|
|
114
|
-
indexes: ['value'],
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
await tableComplex.set({ id: '1', value: 10 })
|
|
118
|
-
await tableComplex.set({ id: '2', value: 20 })
|
|
119
|
-
await tableComplex.set({ id: '3', value: 30 })
|
|
120
|
-
|
|
121
|
-
const results: { id: string; value: number }[] = []
|
|
122
|
-
for await (const doc of tableComplex.search({
|
|
123
|
-
where: { value: { gt: 15, lt: 25 } },
|
|
124
|
-
sortBy: 'value',
|
|
125
|
-
})) {
|
|
126
|
-
results.push(doc)
|
|
127
|
-
}
|
|
128
|
-
expect(results.length).toBe(1)
|
|
129
|
-
expect(results[0].id).toBe('2')
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
it('should handle NOT conditions', async () => {
|
|
133
|
-
const tableNot = await createTable<{ id: string; value: string }>({
|
|
134
|
-
backend,
|
|
135
|
-
tableName: 'TestTableNot',
|
|
136
|
-
key: 'id',
|
|
137
|
-
indexes: ['value'],
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
await tableNot.set({ id: '1', value: 'apple' })
|
|
141
|
-
await tableNot.set({ id: '2', value: 'banana' })
|
|
142
|
-
await tableNot.set({ id: '3', value: 'cherry' })
|
|
143
|
-
|
|
144
|
-
const results: { id: string; value: string }[] = []
|
|
145
|
-
for await (const doc of tableNot.search({
|
|
146
|
-
where: { NOT: { value: 'banana' } },
|
|
147
|
-
})) {
|
|
148
|
-
results.push(doc)
|
|
149
|
-
}
|
|
150
|
-
expect(results.length).toBe(2)
|
|
151
|
-
expect(results.map((doc) => doc.value)).toEqual(['apple', 'cherry'])
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
it('should handle AND conditions', async () => {
|
|
155
|
-
const tableAnd = await createTable<{ id: string; category: string; price: number }>({
|
|
156
|
-
backend,
|
|
157
|
-
tableName: 'TestTableAnd',
|
|
158
|
-
key: 'id',
|
|
159
|
-
indexes: ['category', 'price'],
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
await tableAnd.set({ id: '1', category: 'fruit', price: 10 })
|
|
163
|
-
await tableAnd.set({ id: '2', category: 'fruit', price: 20 })
|
|
164
|
-
await tableAnd.set({ id: '3', category: 'vegetable', price: 15 })
|
|
165
|
-
|
|
166
|
-
const results: { id: string; category: string; price: number }[] = []
|
|
167
|
-
for await (const doc of tableAnd.search({
|
|
168
|
-
where: { AND: [{ category: 'fruit' }, { price: { lt: 15 } }] },
|
|
169
|
-
})) {
|
|
170
|
-
results.push(doc)
|
|
171
|
-
}
|
|
172
|
-
expect(results.length).toBe(1)
|
|
173
|
-
expect(results[0].id).toBe('1')
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('should handle OR conditions', async () => {
|
|
177
|
-
const tableOr = await createTable<{ id: string; type: string }>({
|
|
178
|
-
backend,
|
|
179
|
-
tableName: 'TestTableOr',
|
|
180
|
-
key: 'id',
|
|
181
|
-
indexes: ['type'],
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
await tableOr.set({ id: '1', type: 'A' })
|
|
185
|
-
await tableOr.set({ id: '2', type: 'B' })
|
|
186
|
-
await tableOr.set({ id: '3', type: 'C' })
|
|
187
|
-
|
|
188
|
-
const results: { id: string; type: string }[] = []
|
|
189
|
-
for await (const doc of tableOr.search({
|
|
190
|
-
where: { OR: [{ type: 'A' }, { type: 'C' }] },
|
|
191
|
-
})) {
|
|
192
|
-
results.push(doc)
|
|
193
|
-
}
|
|
194
|
-
expect(results.length).toBe(2)
|
|
195
|
-
expect(results.map((doc) => doc.type)).toEqual(['A', 'C'])
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
it('should handle nested AND/OR/NOT conditions', async () => {
|
|
199
|
-
const tableNestedLogic = await createTable<{ id: string; category: string; price: number }>({
|
|
200
|
-
backend,
|
|
201
|
-
tableName: 'TestTableNestedLogic',
|
|
202
|
-
key: 'id',
|
|
203
|
-
indexes: ['category', 'price'],
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
await tableNestedLogic.set({ id: '1', category: 'fruit', price: 10 })
|
|
207
|
-
await tableNestedLogic.set({ id: '2', category: 'fruit', price: 20 })
|
|
208
|
-
await tableNestedLogic.set({ id: '3', category: 'fruit', price: 15 })
|
|
209
|
-
|
|
210
|
-
const whereClause: Where<{ category: string; price: number }> = {
|
|
211
|
-
AND: [
|
|
212
|
-
{ category: { is: 'fruit' } },
|
|
213
|
-
{
|
|
214
|
-
OR: [{ price: { lt: 15 } }, { price: { is: 15 } }],
|
|
215
|
-
},
|
|
216
|
-
],
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const allData: { id: string; category: string; price: number }[] = []
|
|
220
|
-
for await (const doc of tableNestedLogic.search({})) {
|
|
221
|
-
allData.push(doc)
|
|
222
|
-
}
|
|
223
|
-
expect(allData.length).toBe(3)
|
|
224
|
-
|
|
225
|
-
const results: { id: string; category: string; price: number }[] = []
|
|
226
|
-
for await (const doc of tableNestedLogic.search({
|
|
227
|
-
where: whereClause,
|
|
228
|
-
})) {
|
|
229
|
-
results.push(doc)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
expect(results.length).toBe(2)
|
|
233
|
-
})
|
|
234
|
-
})
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { STATE_SCHEDULER } from '../create'
|
|
2
|
-
import { getId } from '../utils/id'
|
|
3
|
-
import type { Backend } from './table'
|
|
4
|
-
import { createTable } from './table/table'
|
|
5
|
-
import type {
|
|
6
|
-
DbOptions,
|
|
7
|
-
DocType,
|
|
8
|
-
DotPath,
|
|
9
|
-
GetFieldType,
|
|
10
|
-
GroupByOptions,
|
|
11
|
-
GroupByResult,
|
|
12
|
-
Key,
|
|
13
|
-
MutationResult,
|
|
14
|
-
SearchOptions,
|
|
15
|
-
Table,
|
|
16
|
-
} from './table/table.types'
|
|
17
|
-
import type { Where } from './table/where'
|
|
18
|
-
|
|
19
|
-
export interface CreateSqliteOptions<Document extends DocType> extends Omit<DbOptions<Document>, 'backend'> {
|
|
20
|
-
readonly backend: Backend | Promise<Backend>
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface MutationItems<Doc> {
|
|
24
|
-
mutations?: MutationResult<Doc>[]
|
|
25
|
-
removedAll?: boolean
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface SyncTable<Document extends DocType> {
|
|
29
|
-
readonly subscribe: (listener: (mutation: MutationItems<Document>) => void) => () => void
|
|
30
|
-
readonly set: (document: Document) => Promise<MutationResult<Document>>
|
|
31
|
-
readonly batchSet: (documents: Document[]) => Promise<MutationResult<Document>[]>
|
|
32
|
-
readonly batchDelete: (keys: Key[]) => Promise<MutationResult<Document>[]>
|
|
33
|
-
readonly get: <Selected = Document>(key: Key, selector?: (document: Document) => Selected) => Promise<Selected | undefined>
|
|
34
|
-
|
|
35
|
-
readonly delete: (key: Key) => Promise<MutationResult<Document> | undefined>
|
|
36
|
-
readonly search: <Selected = Document>(options?: SearchOptions<Document, Selected>) => AsyncIterableIterator<Selected>
|
|
37
|
-
readonly count: (options?: { where?: Where<Document> }) => Promise<number>
|
|
38
|
-
readonly deleteBy: (where: Where<Document>) => Promise<MutationResult<Document>[]>
|
|
39
|
-
readonly clear: () => Promise<void>
|
|
40
|
-
readonly groupBy: <Field extends DotPath<Document>>(
|
|
41
|
-
field: Field,
|
|
42
|
-
options?: GroupByOptions<Document>,
|
|
43
|
-
) => Promise<Array<GroupByResult<GetFieldType<Document, Field>>>>
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Create a SyncTable that wraps a Table and provides reactive capabilities
|
|
48
|
-
* @param options Options to create the SyncTable, including the backend and table name
|
|
49
|
-
* @returns A SyncTable instance with methods to interact with the underlying Table and manage reactive searches
|
|
50
|
-
*/
|
|
51
|
-
export function createSqliteState<Document extends DocType>(options: CreateSqliteOptions<Document>): SyncTable<Document> {
|
|
52
|
-
let cachedTable: Table<Document> | undefined
|
|
53
|
-
/**
|
|
54
|
-
* Get or create the underlying table
|
|
55
|
-
* @returns The Table instance
|
|
56
|
-
*/
|
|
57
|
-
async function getTable() {
|
|
58
|
-
if (!cachedTable) {
|
|
59
|
-
const { backend, ...rest } = options
|
|
60
|
-
const resolvedBackend = backend instanceof Promise ? await backend : backend
|
|
61
|
-
cachedTable = await createTable<Document>({ backend: resolvedBackend, ...rest })
|
|
62
|
-
}
|
|
63
|
-
return cachedTable
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const id = getId()
|
|
67
|
-
STATE_SCHEDULER.add(id, {
|
|
68
|
-
onScheduleDone(unknownItems) {
|
|
69
|
-
if (!unknownItems) {
|
|
70
|
-
return
|
|
71
|
-
}
|
|
72
|
-
const items = unknownItems as MutationItems<Document>[]
|
|
73
|
-
const merged: MutationItems<Document> = {}
|
|
74
|
-
for (const item of items) {
|
|
75
|
-
if (item.removedAll) {
|
|
76
|
-
merged.removedAll = true
|
|
77
|
-
}
|
|
78
|
-
if (item.mutations) {
|
|
79
|
-
if (!merged.mutations) {
|
|
80
|
-
merged.mutations = []
|
|
81
|
-
}
|
|
82
|
-
merged.mutations.push(...item.mutations)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
for (const listener of listeners) {
|
|
86
|
-
listener(merged)
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Notify all subscribers of changes
|
|
93
|
-
* @param item The mutation items to notify subscribers about
|
|
94
|
-
*/
|
|
95
|
-
function handleChanges(item: MutationItems<Document>) {
|
|
96
|
-
STATE_SCHEDULER.schedule(id, item)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const listeners = new Set<(mutation: MutationItems<Document>) => void>()
|
|
100
|
-
|
|
101
|
-
const state: SyncTable<Document> = {
|
|
102
|
-
subscribe(listener) {
|
|
103
|
-
listeners.add(listener)
|
|
104
|
-
return () => listeners.delete(listener)
|
|
105
|
-
},
|
|
106
|
-
async clear() {
|
|
107
|
-
const table = await getTable()
|
|
108
|
-
handleChanges({ removedAll: true })
|
|
109
|
-
return table.clear()
|
|
110
|
-
},
|
|
111
|
-
async set(document) {
|
|
112
|
-
const table = await getTable()
|
|
113
|
-
const changes = await table.set(document)
|
|
114
|
-
handleChanges({ mutations: [changes] })
|
|
115
|
-
return changes
|
|
116
|
-
},
|
|
117
|
-
async batchSet(documents) {
|
|
118
|
-
const table = await getTable()
|
|
119
|
-
const changes = await table.batchSet(documents)
|
|
120
|
-
handleChanges({ mutations: changes })
|
|
121
|
-
return changes
|
|
122
|
-
},
|
|
123
|
-
async batchDelete(keys) {
|
|
124
|
-
const table = await getTable()
|
|
125
|
-
const changes = await table.batchDelete(keys)
|
|
126
|
-
handleChanges({ mutations: changes })
|
|
127
|
-
return changes
|
|
128
|
-
},
|
|
129
|
-
async delete(key) {
|
|
130
|
-
const table = await getTable()
|
|
131
|
-
const changes = await table.delete(key)
|
|
132
|
-
if (changes) {
|
|
133
|
-
handleChanges({ mutations: [changes] })
|
|
134
|
-
}
|
|
135
|
-
return changes
|
|
136
|
-
},
|
|
137
|
-
async deleteBy(where) {
|
|
138
|
-
const table = await getTable()
|
|
139
|
-
const changes = await table.deleteBy(where)
|
|
140
|
-
handleChanges({ mutations: changes })
|
|
141
|
-
return changes
|
|
142
|
-
},
|
|
143
|
-
async get(key, selector) {
|
|
144
|
-
const table = await getTable()
|
|
145
|
-
return table.get(key, selector)
|
|
146
|
-
},
|
|
147
|
-
async *search(searchOptions = {}) {
|
|
148
|
-
const table = await getTable()
|
|
149
|
-
for await (const item of table.search(searchOptions)) {
|
|
150
|
-
yield item
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
async count(countOptions) {
|
|
154
|
-
const table = await getTable()
|
|
155
|
-
return await table.count(countOptions)
|
|
156
|
-
},
|
|
157
|
-
async groupBy(field, groupByOptions) {
|
|
158
|
-
const table = await getTable()
|
|
159
|
-
return await table.groupBy(field, groupByOptions)
|
|
160
|
-
},
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return state
|
|
164
|
-
}
|
package/src/sqlite/index.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export const IN_MEMORY_DB = ':memory:'
|
|
2
|
-
|
|
3
|
-
export interface QueryResult {
|
|
4
|
-
/** The number of rows affected by the query. */
|
|
5
|
-
rowsAffected: number
|
|
6
|
-
/**
|
|
7
|
-
* The last inserted `id`.
|
|
8
|
-
*
|
|
9
|
-
* This value is not set for Postgres databases. If the
|
|
10
|
-
* last inserted id is required on Postgres, the `select` function
|
|
11
|
-
* must be used, with a `RETURNING` clause
|
|
12
|
-
* (`INSERT INTO todos (title) VALUES ($1) RETURNING id`).
|
|
13
|
-
*/
|
|
14
|
-
lastInsertId?: number
|
|
15
|
-
}
|
|
16
|
-
export interface Backend {
|
|
17
|
-
execute: (query: string, bindValues?: unknown[]) => Promise<QueryResult>
|
|
18
|
-
select: <T>(query: string, bindValues?: unknown[]) => Promise<T>
|
|
19
|
-
transaction: (callback: (tx: Backend) => Promise<void>) => Promise<void>
|
|
20
|
-
path: string
|
|
21
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { Database, type Statement } from 'bun:sqlite'
|
|
2
|
-
import type { Backend } from './backend'
|
|
3
|
-
import { MapDeque } from './map-deque'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Create an in-memory SQLite backend using Bun's SQLite implementation
|
|
7
|
-
* @returns A Backend instance for in-memory SQLite operations
|
|
8
|
-
*/
|
|
9
|
-
export function bunMemoryBackend(): Backend {
|
|
10
|
-
const db = Database.open(':memory:')
|
|
11
|
-
const prepares = new MapDeque<string, Statement>(100)
|
|
12
|
-
/**
|
|
13
|
-
* Get or prepare a SQLite statement, caching it for future use
|
|
14
|
-
* @param query The SQL query string
|
|
15
|
-
* @returns The prepared SQLite statement
|
|
16
|
-
*/
|
|
17
|
-
function getStatement(query: string): Statement {
|
|
18
|
-
if (prepares.has(query)) {
|
|
19
|
-
return prepares.get(query)!
|
|
20
|
-
}
|
|
21
|
-
const stmt = db.prepare(query)
|
|
22
|
-
prepares.set(query, stmt)
|
|
23
|
-
return stmt
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const backend: Backend = {
|
|
27
|
-
execute: async (query, params = []) => {
|
|
28
|
-
const q = getStatement(query)
|
|
29
|
-
const result = q.run(...(params as never[]))
|
|
30
|
-
return {
|
|
31
|
-
rowsAffected: result.changes,
|
|
32
|
-
changes: result.changes,
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
transaction: async (callback) => {
|
|
36
|
-
return db.transaction(() => callback(backend))()
|
|
37
|
-
},
|
|
38
|
-
path: db.filename,
|
|
39
|
-
select: async (query, params = []) => {
|
|
40
|
-
const q = getStatement(query)
|
|
41
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
-
const result = q.all(...(params as never[])) as Array<Record<string, any>>
|
|
43
|
-
return result as never
|
|
44
|
-
},
|
|
45
|
-
}
|
|
46
|
-
return backend
|
|
47
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export class MapDeque<K, V> extends Map<K, V> {
|
|
2
|
-
constructor(
|
|
3
|
-
private maxSize: number,
|
|
4
|
-
entries?: ReadonlyArray<readonly [K, V]> | null,
|
|
5
|
-
) {
|
|
6
|
-
super(entries)
|
|
7
|
-
if (this.maxSize <= 0) {
|
|
8
|
-
throw new RangeError('maxSize must be greater than 0')
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
override set(key: K, value: V): this {
|
|
13
|
-
if (this.has(key)) {
|
|
14
|
-
super.set(key, value)
|
|
15
|
-
return this
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (this.size >= this.maxSize) {
|
|
19
|
-
const firstKey = this.keys().next().value
|
|
20
|
-
if (firstKey !== undefined) {
|
|
21
|
-
this.delete(firstKey)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
super.set(key, value)
|
|
26
|
-
|
|
27
|
-
return this
|
|
28
|
-
}
|
|
29
|
-
}
|