muya 2.5.4 → 2.5.6

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.
Files changed (123) hide show
  1. package/{src/__tests__ → __tests__}/bench.test.tsx +4 -4
  2. package/{src/__tests__ → __tests__}/compare.test.tsx +8 -6
  3. package/{src/__tests__ → __tests__}/create.test.tsx +2 -2
  4. package/{src/utils/__tests__ → __tests__}/is.test.ts +3 -3
  5. package/{src/__tests__ → __tests__}/scheduler.test.tsx +1 -1
  6. package/{src/__tests__ → __tests__}/select.test.tsx +5 -5
  7. package/{src/utils/__tests__ → __tests__}/shallow.test.ts +1 -1
  8. package/{src/__tests__ → __tests__}/use-value-loadable.test.tsx +3 -3
  9. package/{src/__tests__ → __tests__}/use-value.test.tsx +8 -8
  10. package/build.ts +67 -0
  11. package/dist/cjs/index.js +14 -0
  12. package/dist/esm/create.js +1 -0
  13. package/dist/esm/debug/development-tools.js +1 -0
  14. package/dist/esm/index.js +1 -0
  15. package/dist/esm/scheduler.js +1 -0
  16. package/dist/esm/select.js +1 -0
  17. package/{types → dist/types}/create-state.d.ts +1 -0
  18. package/dist/types/create-state.d.ts.map +1 -0
  19. package/{types → dist/types}/create.d.ts +2 -4
  20. package/dist/types/create.d.ts.map +1 -0
  21. package/dist/types/debug/development-tools.d.ts +13 -0
  22. package/dist/types/debug/development-tools.d.ts.map +1 -0
  23. package/{types → dist/types}/index.d.ts +3 -1
  24. package/dist/types/index.d.ts.map +1 -0
  25. package/dist/types/scheduler.d.ts +25 -0
  26. package/dist/types/scheduler.d.ts.map +1 -0
  27. package/{types → dist/types}/select.d.ts +1 -0
  28. package/dist/types/select.d.ts.map +1 -0
  29. package/{types → dist/types}/types.d.ts +1 -0
  30. package/dist/types/types.d.ts.map +1 -0
  31. package/{types → dist/types}/use-value-loadable.d.ts +1 -0
  32. package/dist/types/use-value-loadable.d.ts.map +1 -0
  33. package/{types → dist/types}/use-value.d.ts +2 -1
  34. package/dist/types/use-value.d.ts.map +1 -0
  35. package/{types → dist/types}/utils/common.d.ts +1 -0
  36. package/dist/types/utils/common.d.ts.map +1 -0
  37. package/{types → dist/types}/utils/create-emitter.d.ts +1 -0
  38. package/dist/types/utils/create-emitter.d.ts.map +1 -0
  39. package/{types → dist/types}/utils/id.d.ts +1 -0
  40. package/dist/types/utils/id.d.ts.map +1 -0
  41. package/{types → dist/types}/utils/is.d.ts +1 -0
  42. package/dist/types/utils/is.d.ts.map +1 -0
  43. package/{types → dist/types}/utils/shallow.d.ts +1 -0
  44. package/dist/types/utils/shallow.d.ts.map +1 -0
  45. package/package.json +31 -8
  46. package/src/create.ts +7 -2
  47. package/src/debug/development-tools.ts +5 -40
  48. package/src/index.ts +2 -1
  49. package/src/scheduler.ts +77 -71
  50. package/src/select.ts +7 -2
  51. package/src/use-value.ts +1 -1
  52. package/tsconfig.build.json +12 -0
  53. package/cjs/index.js +0 -1
  54. package/esm/__tests__/test-utils.js +0 -1
  55. package/esm/create.js +0 -1
  56. package/esm/debug/development-tools.js +0 -1
  57. package/esm/index.js +0 -1
  58. package/esm/scheduler.js +0 -1
  59. package/esm/select.js +0 -1
  60. package/esm/sqlite/__tests__/create-sqlite.test.js +0 -1
  61. package/esm/sqlite/__tests__/map-deque.test.js +0 -1
  62. package/esm/sqlite/__tests__/table.test.js +0 -1
  63. package/esm/sqlite/__tests__/tokenizer.test.js +0 -1
  64. package/esm/sqlite/__tests__/where.test.js +0 -1
  65. package/esm/sqlite/create-sqlite.js +0 -1
  66. package/esm/sqlite/index.js +0 -1
  67. package/esm/sqlite/table/backend.js +0 -1
  68. package/esm/sqlite/table/bun-backend.js +0 -1
  69. package/esm/sqlite/table/index.js +0 -1
  70. package/esm/sqlite/table/map-deque.js +0 -1
  71. package/esm/sqlite/table/table.js +0 -43
  72. package/esm/sqlite/table/table.types.js +0 -0
  73. package/esm/sqlite/table/tokenizer.js +0 -1
  74. package/esm/sqlite/table/where.js +0 -1
  75. package/esm/sqlite/use-sqlite-count.js +0 -1
  76. package/esm/sqlite/use-sqlite.js +0 -1
  77. package/esm/utils/__tests__/is.test.js +0 -1
  78. package/esm/utils/__tests__/shallow.test.js +0 -1
  79. package/src/sqlite/__tests__/create-sqlite.test.ts +0 -264
  80. package/src/sqlite/__tests__/map-deque.test.ts +0 -61
  81. package/src/sqlite/__tests__/table.test.ts +0 -351
  82. package/src/sqlite/__tests__/tokenizer.test.ts +0 -43
  83. package/src/sqlite/__tests__/use-slite-count.test.tsx +0 -96
  84. package/src/sqlite/__tests__/use-sqlite.more.test.tsx +0 -637
  85. package/src/sqlite/__tests__/use-sqlite.test.tsx +0 -1008
  86. package/src/sqlite/__tests__/where.test.ts +0 -234
  87. package/src/sqlite/create-sqlite.ts +0 -164
  88. package/src/sqlite/index.ts +0 -4
  89. package/src/sqlite/table/backend.ts +0 -21
  90. package/src/sqlite/table/bun-backend.ts +0 -47
  91. package/src/sqlite/table/index.ts +0 -6
  92. package/src/sqlite/table/map-deque.ts +0 -29
  93. package/src/sqlite/table/table.ts +0 -353
  94. package/src/sqlite/table/table.types.ts +0 -129
  95. package/src/sqlite/table/tokenizer.ts +0 -35
  96. package/src/sqlite/table/where.ts +0 -207
  97. package/src/sqlite/use-sqlite-count.ts +0 -69
  98. package/src/sqlite/use-sqlite.ts +0 -250
  99. package/types/__tests__/test-utils.d.ts +0 -25
  100. package/types/debug/development-tools.d.ts +0 -8
  101. package/types/scheduler.d.ts +0 -20
  102. package/types/sqlite/create-sqlite.d.ts +0 -31
  103. package/types/sqlite/index.d.ts +0 -4
  104. package/types/sqlite/table/backend.d.ts +0 -20
  105. package/types/sqlite/table/bun-backend.d.ts +0 -6
  106. package/types/sqlite/table/index.d.ts +0 -6
  107. package/types/sqlite/table/map-deque.d.ts +0 -5
  108. package/types/sqlite/table/table.d.ts +0 -21
  109. package/types/sqlite/table/table.types.d.ts +0 -91
  110. package/types/sqlite/table/tokenizer.d.ts +0 -11
  111. package/types/sqlite/table/where.d.ts +0 -37
  112. package/types/sqlite/use-sqlite-count.d.ts +0 -17
  113. package/types/sqlite/use-sqlite.d.ts +0 -39
  114. /package/{src/__tests__ → __tests__}/test-utils.ts +0 -0
  115. /package/{esm → dist/esm}/create-state.js +0 -0
  116. /package/{esm → dist/esm}/types.js +0 -0
  117. /package/{esm → dist/esm}/use-value-loadable.js +0 -0
  118. /package/{esm → dist/esm}/use-value.js +0 -0
  119. /package/{esm → dist/esm}/utils/common.js +0 -0
  120. /package/{esm → dist/esm}/utils/create-emitter.js +0 -0
  121. /package/{esm → dist/esm}/utils/id.js +0 -0
  122. /package/{esm → dist/esm}/utils/is.js +0 -0
  123. /package/{esm → dist/esm}/utils/shallow.js +0 -0
@@ -1,353 +0,0 @@
1
- /* eslint-disable prefer-destructuring */
2
- /* eslint-disable sonarjs/different-types-comparison */
3
- /* eslint-disable sonarjs/cognitive-complexity */
4
- /* eslint-disable @typescript-eslint/no-shadow */
5
- /* eslint-disable no-shadow */
6
- import type { Backend } from './backend'
7
- import type {
8
- Table,
9
- DbOptions,
10
- DocType,
11
- Key,
12
- SearchOptions,
13
- MutationResult,
14
- GroupByResult,
15
- GroupByOptions,
16
- DotPath,
17
- GetFieldType,
18
- } from './table.types'
19
- import { unicodeTokenizer, type FtsTokenizerOptions } from './tokenizer'
20
- import type { Where } from './where'
21
- import { getWhereQuery } from './where'
22
-
23
- const DELETE_IN_CHUNK = 500
24
- export const DEFAULT_PAGE_SIZE = 100
25
-
26
- /**
27
- * Convert a dot-separated path to a JSON path
28
- * @param dot The dot-separated path string
29
- * @returns The JSON path string
30
- */
31
- export function toJsonPath(dot: string) {
32
- return '$.' + dot
33
- }
34
-
35
- /**
36
- * Get a nested value from an object using a dot-separated path
37
- * @param object The object to retrieve the value from
38
- * @param path The dot-separated path string
39
- * @returns The value at the specified path, or undefined if not found
40
- */
41
- export function getByPath<T extends object>(object: T, path: string): unknown {
42
- if (!object || !path) return undefined
43
- // eslint-disable-next-line unicorn/no-array-reduce
44
- return path.split('.').reduce<unknown>((accumulator, key) => {
45
- if (typeof accumulator === 'object' && accumulator !== null && key in (accumulator as Record<string, unknown>)) {
46
- return (accumulator as Record<string, unknown>)[key]
47
- }
48
- return
49
- }, object)
50
- }
51
-
52
- /**
53
- * Create and initialize a table in the database with the specified options
54
- * @param options The options for creating the table, including table name, indexes, backend, and key
55
- * @returns A promise that resolves to the created Table instance
56
- */
57
- export async function createTable<Document extends DocType>(options: DbOptions<Document>): Promise<Table<Document>> {
58
- const { backend, tableName, indexes, key, disablePragmaOptimization } = options
59
- const hasUserKey = key !== undefined
60
-
61
- if (!disablePragmaOptimization) {
62
- await backend.execute(`PRAGMA journal_mode=WAL;`)
63
- await backend.execute(`PRAGMA synchronous=NORMAL;`)
64
- await backend.execute(`PRAGMA temp_store=MEMORY;`)
65
- await backend.execute(`PRAGMA cache_size=-20000;`)
66
- }
67
-
68
- // Base JSON table
69
- if (hasUserKey) {
70
- await backend.execute(`
71
- CREATE TABLE IF NOT EXISTS ${tableName} (
72
- key TEXT PRIMARY KEY,
73
- data TEXT NOT NULL
74
- );
75
- `)
76
- } else {
77
- await backend.execute(`
78
- CREATE TABLE IF NOT EXISTS ${tableName} (
79
- data TEXT NOT NULL
80
- );
81
- `)
82
- }
83
-
84
- // Track FTS fields and map dot paths to valid SQLite column names
85
- let ftsTokenizer: string | undefined | FtsTokenizerOptions
86
- const ftsFields: string[] = []
87
- const ftsFieldMap: Record<string, string> = {} // dot path -> column name
88
-
89
- for (const index of indexes ?? []) {
90
- if (typeof index === 'string' && index.startsWith('fts:')) {
91
- const path = index.slice(4)
92
- const col = path.replaceAll('.', '_')
93
- ftsFields.push(path)
94
- ftsFieldMap[path] = col
95
- } else if (typeof index === 'object' && index.type === 'fts') {
96
- const path = index.path
97
- const col = path.replaceAll('.', '_')
98
- ftsFields.push(path)
99
- ftsFieldMap[path] = col
100
- if (index.tokenizer) {
101
- if (!ftsTokenizer) {
102
- ftsTokenizer = index.tokenizer
103
- } else if (ftsTokenizer !== index.tokenizer) {
104
- throw new Error(`Conflicting FTS tokenizers: already using "${ftsTokenizer}", got "${index.tokenizer}"`)
105
- }
106
- }
107
- } else {
108
- const idx = String(index)
109
- await backend.execute(
110
- `CREATE INDEX IF NOT EXISTS idx_${tableName}_${idx.replaceAll(/\W/g, '_')}
111
- ON ${tableName} (json_extract(data, '${toJsonPath(idx)}'));`,
112
- )
113
- }
114
- }
115
-
116
- // Create FTS table + triggers
117
- if (ftsFields.length > 0) {
118
- let tokenizerSpec: string
119
- if (typeof ftsTokenizer === 'object') {
120
- tokenizerSpec = unicodeTokenizer(ftsTokenizer)
121
- } else if (ftsTokenizer === undefined) {
122
- tokenizerSpec = '"unicode61", "remove_diacritics=1"'
123
- } else {
124
- tokenizerSpec = ftsTokenizer
125
- }
126
- // Use mapped column names for FTS columns
127
- const ftsColumns = ftsFields.map((f) => ftsFieldMap[f]).join(', ')
128
- const query = `
129
- CREATE VIRTUAL TABLE IF NOT EXISTS ${tableName}_fts
130
- USING fts5(${ftsColumns}, tokenize=${tokenizerSpec});
131
- `
132
-
133
- await backend.execute(query)
134
-
135
- // Insert trigger
136
- await backend.execute(`
137
- CREATE TRIGGER IF NOT EXISTS ${tableName}_ai
138
- AFTER INSERT ON ${tableName}
139
- BEGIN
140
- INSERT INTO ${tableName}_fts(rowid, ${ftsColumns})
141
- VALUES (
142
- new.rowid,
143
- ${ftsFields.map((f) => `json_extract(new.data, '${toJsonPath(f)}')`).join(', ')}
144
- );
145
- END;
146
- `)
147
-
148
- // Delete trigger
149
- await backend.execute(`
150
- CREATE TRIGGER IF NOT EXISTS ${tableName}_ad
151
- AFTER DELETE ON ${tableName}
152
- BEGIN
153
- DELETE FROM ${tableName}_fts WHERE rowid = old.rowid;
154
- END;
155
- `)
156
-
157
- // Update trigger
158
- await backend.execute(`
159
- CREATE TRIGGER IF NOT EXISTS ${tableName}_au
160
- AFTER UPDATE ON ${tableName}
161
- BEGIN
162
- UPDATE ${tableName}_fts
163
- SET ${ftsFields.map((f) => `${ftsFieldMap[f]}=json_extract(new.data, '${toJsonPath(f)}')`).join(', ')}
164
- WHERE rowid = old.rowid;
165
- END;
166
- `)
167
- }
168
-
169
- /**
170
- * Get the value of the configured key from a document
171
- * @param document The document to extract the key from
172
- * @returns The value of the key, or undefined if not found or no key is configured
173
- */
174
- function getKeyFromDocument(document: Document): Key | undefined {
175
- if (!hasUserKey) return undefined
176
- return getByPath(document, String(key)) as Key | undefined
177
- }
178
-
179
- const table: Table<Document> = {
180
- backend,
181
-
182
- async set(document, backendOverride) {
183
- const db = backendOverride ?? backend
184
- const json = JSON.stringify(document)
185
-
186
- if (hasUserKey) {
187
- const id = getKeyFromDocument(document)
188
- if (id === undefined || id === null) {
189
- throw new Error(`Document is missing the configured key "${String(key)}".`)
190
- }
191
-
192
- const existing = await db.select<Array<{ key: string }>>(`SELECT key FROM ${tableName} WHERE key = ?`, [id])
193
-
194
- if (existing.length > 0) {
195
- await db.execute(`UPDATE ${tableName} SET data = ? WHERE key = ?`, [json, id])
196
- return { key: id, op: 'update', document }
197
- } else {
198
- await db.execute(`INSERT INTO ${tableName} (key, data) VALUES (?, ?)`, [id, json])
199
- return { key: id, op: 'insert', document }
200
- }
201
- }
202
-
203
- await db.execute(`INSERT INTO ${tableName} (data) VALUES (?)`, [json])
204
- const rows = await db.select<Array<{ id: number }>>(`SELECT last_insert_rowid() AS id`)
205
- const rowid = rows[0]?.id
206
- if (typeof rowid !== 'number') throw new Error('Failed to retrieve last_insert_rowid()')
207
- return { key: rowid, op: 'insert', document }
208
- },
209
-
210
- async get<Selected = Document>(
211
- keyValue: Key,
212
- selector: (document: Document, meta: { rowId: number; key: Key }) => Selected = (d) => d as unknown as Selected,
213
- ) {
214
- const whereKey = hasUserKey ? `key = ?` : `rowid = ?`
215
- const result = await backend.select<Array<{ data: string; rowid: number }>>(
216
- `SELECT rowid, data FROM ${tableName} WHERE ${whereKey}`,
217
- [keyValue],
218
- )
219
- if (result.length === 0) return
220
- const { data, rowid } = result[0]
221
- const document = JSON.parse(data) as Document
222
- const logicalKey = hasUserKey ? (getKeyFromDocument(document) ?? rowid) : rowid
223
- return selector(document, { rowId: rowid, key: logicalKey }) as Selected
224
- },
225
-
226
- async delete(keyValue: Key, backendOverride?: Backend) {
227
- const db = backendOverride ?? backend
228
- const whereKey = hasUserKey ? `key = ?` : `rowid = ?`
229
- await db.execute(`DELETE FROM ${tableName} WHERE ${whereKey}`, [keyValue])
230
- const changed = await backend.select<Array<{ c: number }>>(`SELECT changes() AS c`)
231
- if ((changed[0]?.c ?? 0) > 0) return { key: keyValue, op: 'delete' }
232
- return
233
- },
234
-
235
- async *search<Selected = Document>(options: SearchOptions<Document, Selected> = {}): AsyncIterableIterator<Selected> {
236
- const {
237
- sortBy,
238
- order = 'asc',
239
- limit,
240
- offset = 0,
241
- where,
242
- select = (document) => document as unknown as Selected,
243
- pageSize = DEFAULT_PAGE_SIZE,
244
- } = options
245
-
246
- const whereSql = getWhereQuery<Document>(where, tableName)
247
- const baseQuery = `SELECT rowid, data FROM ${tableName} ${whereSql}`
248
-
249
- let yielded = 0
250
- let currentOffset = offset
251
- while (true) {
252
- let query = baseQuery
253
-
254
- if (sortBy) {
255
- query += ` ORDER BY json_extract(data, '${toJsonPath(String(sortBy))}') COLLATE NOCASE ${order.toUpperCase()}`
256
- } else {
257
- query += hasUserKey ? ` ORDER BY key COLLATE NOCASE ${order.toUpperCase()}` : ` ORDER BY rowid ${order.toUpperCase()}`
258
- }
259
-
260
- const batchLimit = limit ? Math.min(pageSize, limit - yielded) : pageSize
261
- query += ` LIMIT ${batchLimit} OFFSET ${currentOffset}`
262
-
263
- const results = await backend.select<Array<{ rowid: number; data: string }>>(query)
264
- if (results.length === 0) break
265
-
266
- for (const { rowid, data } of results) {
267
- if (limit && yielded >= limit) return
268
- const document = JSON.parse(data) as Document
269
- const logicalKey = hasUserKey ? (getKeyFromDocument(document) ?? rowid) : rowid
270
- // Pass both rowId and logicalKey
271
- yield select(document, { rowId: rowid, key: logicalKey }) as Selected
272
- yielded++
273
- }
274
-
275
- if (results.length < batchLimit || (limit && yielded >= limit)) break
276
- currentOffset += results.length
277
- }
278
- },
279
-
280
- async count(options: { where?: Where<Document> } = {}) {
281
- const whereSql = getWhereQuery<Document>(options.where, tableName)
282
- const query = `SELECT COUNT(*) as count FROM ${tableName} ${whereSql}`
283
- const result = await backend.select<Array<{ count: number }>>(query)
284
- return result[0]?.count ?? 0
285
- },
286
-
287
- async deleteBy(where: Where<Document>) {
288
- const whereSql = getWhereQuery<Document>(where, tableName)
289
- const keyCol = hasUserKey ? 'key' : 'rowid'
290
- const results: MutationResult<Document>[] = []
291
-
292
- await backend.transaction(async (tx) => {
293
- const rows = await tx.select<Array<{ k: Key }>>(`SELECT ${keyCol} AS k FROM ${tableName} ${whereSql}`)
294
- if (rows.length === 0) return
295
-
296
- const allKeys = rows.map((r) => r.k)
297
- for (let index = 0; index < allKeys.length; index += DELETE_IN_CHUNK) {
298
- const chunk = allKeys.slice(index, index + DELETE_IN_CHUNK)
299
- const placeholders = chunk.map(() => '?').join(',')
300
- await tx.execute(`DELETE FROM ${tableName} WHERE ${keyCol} IN (${placeholders})`, chunk as unknown[])
301
- }
302
-
303
- for (const k of allKeys) results.push({ key: k, op: 'delete', document: undefined })
304
- })
305
-
306
- return results
307
- },
308
-
309
- async clear() {
310
- await backend.execute(`DELETE FROM ${tableName}`)
311
- },
312
-
313
- async groupBy<Field extends DotPath<Document>>(
314
- field: Field,
315
- options: GroupByOptions<Document> = {},
316
- ): Promise<Array<GroupByResult<GetFieldType<Document, Field>>>> {
317
- const whereSql = getWhereQuery<Document>(options.where, tableName)
318
- const jsonPath = toJsonPath(String(field))
319
- const query = `
320
- SELECT json_extract(data, '${jsonPath}') AS groupKey, COUNT(*) AS count
321
- FROM ${tableName}
322
- ${whereSql}
323
- GROUP BY groupKey
324
- `
325
- type FieldType = GetFieldType<Document, Field>
326
- const results = await backend.select<Array<{ groupKey: FieldType; count: number }>>(query)
327
- return results.map((row) => ({ key: row.groupKey, count: row.count }))
328
- },
329
-
330
- async batchSet(documents: Document[]) {
331
- const mutations: MutationResult<Document>[] = []
332
- await backend.transaction(async (tx) => {
333
- for (const document of documents) {
334
- const m = await table.set(document, tx)
335
- mutations.push(m)
336
- }
337
- })
338
- return mutations
339
- },
340
- async batchDelete(keys: Key[]) {
341
- const mutations: MutationResult<Document>[] = []
342
- await backend.transaction(async (tx) => {
343
- for (const key of keys) {
344
- const m = await table.delete(key, tx)
345
- if (m) mutations.push(m)
346
- }
347
- })
348
- return mutations
349
- },
350
- }
351
-
352
- return table
353
- }
@@ -1,129 +0,0 @@
1
- import type { Backend } from './backend'
2
- import type { FtsTokenizerOptions } from './tokenizer'
3
- import type { Where } from './where'
4
-
5
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
- export type DocType = { [key: string]: any }
7
- export type KeyTypeAvailable = 'string' | 'number'
8
-
9
- export interface SqlSeachOptions<Document extends DocType> {
10
- readonly sortBy?: DotPath<Document>
11
- readonly order?: 'asc' | 'desc'
12
- readonly limit?: number
13
- readonly offset?: number
14
- readonly where?: Where<Document>
15
- readonly pageSize?: number
16
- }
17
-
18
- // Expand all nested keys into dot-paths
19
- export type DotPrefix<T extends string> = T extends '' ? '' : `.${T}`
20
-
21
- type Previous = [never, 0, 1, 2, 3, 4, 5]
22
-
23
- type DotPathRaw<T, D extends number = 5> = [D] extends [never]
24
- ? never
25
- : T extends object
26
- ? {
27
- [K in Extract<keyof T, string>]: T[K] extends object ? K | `${K}.${DotPathRaw<T[K], Previous[D]>}` : K
28
- }[Extract<keyof T, string>]
29
- : never
30
-
31
- export type DotPath<T> = DotPathRaw<MakeAllFieldAsRequired<T>>
32
-
33
- /**
34
- * Extract the value type at a given dot path
35
- * e.g., GetFieldType<{ user: { name: string } }, 'user.name'> = string
36
- */
37
- export type GetFieldType<T, Path extends string> = Path extends `${infer First}.${infer Rest}`
38
- ? First extends keyof T
39
- ? GetFieldType<T[First], Rest>
40
- : never
41
- : Path extends keyof T
42
- ? T[Path]
43
- : never
44
-
45
- // Built-in FTS5 tokenizers
46
- export type FtsTokenizer =
47
- | 'porter' // English stemming
48
- | 'simple' // basic ASCII tokenizer
49
- | 'icu' // requires SQLite compiled with ICU extension
50
- | 'unicode61' // Unicode-aware tokenizer with diacritic removal and custom token chars
51
- | FtsTokenizerOptions
52
-
53
- export interface FtsType<Document extends DocType> {
54
- readonly type: 'fts'
55
- readonly path: DotPath<Document>
56
- readonly tokenizer?: FtsTokenizer
57
- }
58
- export type IndexDeclaration<Document extends DocType> =
59
- | DotPath<Document> // normal JSON path index
60
- | `fts:${DotPath<Document>}` // full-text index
61
- | FtsType<Document> // full-text index with options
62
-
63
- export interface DbOptions<Document extends DocType> {
64
- readonly tableName: string
65
- readonly indexes?: Array<IndexDeclaration<Document>>
66
- readonly backend: Backend
67
- readonly key?: DotPath<Document>
68
- readonly disablePragmaOptimization?: boolean
69
- }
70
-
71
- export interface SearchOptions<Document extends DocType, Selected = Document> extends SqlSeachOptions<Document> {
72
- readonly select?: (document: Document, meta: { rowId: number; key: Key }) => Selected
73
- }
74
-
75
- interface DbNotGeneric {
76
- readonly backend: Backend
77
- }
78
-
79
- export type Key = string | number
80
-
81
- export type MutationOp = 'insert' | 'update' | 'delete'
82
-
83
- interface MutationResultBase<T> {
84
- key: Key
85
- op: MutationOp
86
- document?: T
87
- }
88
- interface MutationResultDelete<T> extends MutationResultBase<T> {
89
- key: Key
90
- op: 'delete'
91
- }
92
-
93
- interface MutationResultUpdateInsert<T> extends MutationResultBase<T> {
94
- key: Key
95
- op: 'update' | 'insert'
96
- document: T
97
- }
98
-
99
- export type MutationResult<T> = MutationResultDelete<T> | MutationResultUpdateInsert<T>
100
-
101
- export interface GroupByResult<K> {
102
- readonly key: K
103
- readonly count: number
104
- }
105
-
106
- export interface GroupByOptions<Document extends DocType> {
107
- readonly where?: Where<Document>
108
- }
109
-
110
- export interface Table<Document extends DocType> extends DbNotGeneric {
111
- readonly set: (document: Document, backendOverride?: Backend) => Promise<MutationResult<Document>>
112
- readonly batchSet: (documents: Document[]) => Promise<MutationResult<Document>[]>
113
- readonly batchDelete: (keys: Key[]) => Promise<MutationResult<Document>[]>
114
- readonly get: <Selected = Document>(key: Key, selector?: (document: Document) => Selected) => Promise<Selected | undefined>
115
-
116
- readonly delete: (key: Key, backendOverride?: Backend) => Promise<MutationResult<Document> | undefined>
117
- readonly search: <Selected = Document>(options?: SearchOptions<Document, Selected>) => AsyncIterableIterator<Selected>
118
- readonly count: (options?: { where?: Where<Document> }) => Promise<number>
119
- readonly deleteBy: (where: Where<Document>) => Promise<MutationResult<Document>[]>
120
- readonly clear: () => Promise<void>
121
- readonly groupBy: <Field extends DotPath<Document>>(
122
- field: Field,
123
- options?: GroupByOptions<Document>,
124
- ) => Promise<Array<GroupByResult<GetFieldType<Document, Field>>>>
125
- }
126
-
127
- export type MakeAllFieldAsRequired<T> = {
128
- [K in keyof T]-?: T[K] extends object ? MakeAllFieldAsRequired<T[K]> : T[K]
129
- }
@@ -1,35 +0,0 @@
1
- export interface FtsTokenizerOptions {
2
- readonly removeDiacritics?: 0 | 1 | 2
3
- readonly tokenChars?: string
4
- readonly separators?: string
5
- }
6
-
7
- /**
8
- * Create a custom FTS5 tokenizer string based on the provided options
9
- * @param options Options to customize the tokenizer
10
- * @returns A string representing the FTS5 tokenizer configuration
11
- */
12
- export function unicodeTokenizer(options: FtsTokenizerOptions = {}): string {
13
- const { removeDiacritics, tokenChars, separators } = options
14
- const parts: string[] = []
15
-
16
- if (removeDiacritics !== undefined) {
17
- parts.push(`"remove_diacritics=${removeDiacritics}"`)
18
- }
19
- if (tokenChars && tokenChars.length > 0) {
20
- parts.push(`"tokenchars='${tokenChars.replaceAll("'", "''")}'"`)
21
- }
22
- if (separators && separators.length > 0) {
23
- parts.push(`"separators='${separators.replaceAll("'", "''")}'"`)
24
- }
25
-
26
- // 👉 return correct SQLite syntax
27
- if (parts.length === 0) {
28
- return '"unicode61"'
29
- }
30
- const hasParts = parts.length > 0
31
- if (!hasParts) {
32
- return '"unicode61"'
33
- }
34
- return `"unicode61", ${parts.join(', ')}`
35
- }