muya 2.4.94 → 2.4.95
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/esm/sqlite/create-sqlite.js +1 -1
- package/esm/sqlite/table/table.js +1 -1
- package/esm/sqlite/use-sqlite.js +1 -1
- package/package.json +1 -1
- package/src/sqlite/create-sqlite.ts +11 -11
- package/src/sqlite/table/table.ts +6 -6
- package/src/sqlite/table/table.types.ts +19 -5
- package/src/sqlite/use-sqlite.ts +2 -2
- package/types/sqlite/create-sqlite.d.ts +7 -7
- package/types/sqlite/table/table.types.d.ts +16 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
import{STATE_SCHEDULER as
|
|
1
|
+
import{STATE_SCHEDULER as u}from"../create";import{getId as m}from"../utils/id";import{createTable as d}from"./table/table";function p(l){let s;async function o(){if(!s){const{backend:e,...n}=l,t=e instanceof Promise?await e:e;s=await d({backend:t,...n})}return s}const i=m();u.add(i,{onScheduleDone(e){if(!e)return;const n=e,t={};for(const c of n)c.removedAll&&(t.removedAll=!0),c.mutations&&(t.mutations||(t.mutations=[]),t.mutations.push(...c.mutations));for(const c of r)c(t)}});function a(e){u.schedule(i,e)}const r=new Set;return{subscribe(e){return r.add(e),()=>r.delete(e)},async clear(){const e=await o();return a({removedAll:!0}),e.clear()},async set(e){const t=await(await o()).set(e);return a({mutations:[t]}),t},async batchSet(e){const t=await(await o()).batchSet(e);return a({mutations:t}),t},async delete(e){const t=await(await o()).delete(e);return t&&a({mutations:[t]}),t},async deleteBy(e){const t=await(await o()).deleteBy(e);return a({mutations:t}),t},async get(e,n){return(await o()).get(e,n)},async*search(e={}){const n=await o();for await(const t of n.search(e))yield t},async count(e){return await(await o()).count(e)}}}export{p as createSqliteState};
|
|
@@ -35,4 +35,4 @@ import{unicodeTokenizer as _}from"./tokenizer";import{getWhereQuery as g}from"./
|
|
|
35
35
|
SET ${T.map(r=>`${f[r]}=json_extract(new.data, '${m(r)}')`).join(", ")}
|
|
36
36
|
WHERE rowid = old.rowid;
|
|
37
37
|
END;
|
|
38
|
-
`)}function A(e){if(u)return M(e,String($))}const k={backend:s,async set(e,n){const o=n??s,r=JSON.stringify(e);if(u){const
|
|
38
|
+
`)}function A(e){if(u)return M(e,String($))}const k={backend:s,async set(e,n){const o=n??s,r=JSON.stringify(e);if(u){const i=A(e);if(i==null)throw new Error(`Document is missing the configured key "${String($)}".`);return(await o.select(`SELECT key FROM ${t} WHERE key = ?`,[i])).length>0?(await o.execute(`UPDATE ${t} SET data = ? WHERE key = ?`,[r,i]),{key:i,op:"update",document:e}):(await o.execute(`INSERT INTO ${t} (key, data) VALUES (?, ?)`,[i,r]),{key:i,op:"insert",document:e})}await o.execute(`INSERT INTO ${t} (data) VALUES (?)`,[r]);const c=(await o.select("SELECT last_insert_rowid() AS id"))[0]?.id;if(typeof c!="number")throw new Error("Failed to retrieve last_insert_rowid()");return{key:c,op:"insert",document:e}},async get(e,n=o=>o){const o=u?"key = ?":"rowid = ?",r=await s.select(`SELECT rowid, data FROM ${t} WHERE ${o}`,[e]);if(r.length===0)return;const{data:E,rowid:c}=r[0],i=JSON.parse(E),a=u?A(i)??c:c;return n(i,{rowId:c,key:a})},async delete(e){const n=u?"key = ?":"rowid = ?";if(await s.execute(`DELETE FROM ${t} WHERE ${n}`,[e]),((await s.select("SELECT changes() AS c"))[0]?.c??0)>0)return{key:e,op:"delete"}},async*search(e={}){const{sortBy:n,order:o="asc",limit:r,offset:E=0,where:c,select:i=w=>w,pageSize:a=C}=e,S=g(c,t),h=`SELECT rowid, data FROM ${t} ${S}`;let p=0,D=E;for(;;){let w=h;n?w+=` ORDER BY json_extract(data, '${m(String(n))}') COLLATE NOCASE ${o.toUpperCase()}`:w+=u?` ORDER BY key COLLATE NOCASE ${o.toUpperCase()}`:` ORDER BY rowid ${o.toUpperCase()}`;const I=r?Math.min(a,r-p):a;w+=` LIMIT ${I} OFFSET ${D}`;const R=await s.select(w);if(R.length===0)break;for(const{rowid:O,data:F}of R){if(r&&p>=r)return;const N=JSON.parse(F),b=u?A(N)??O:O;yield i(N,{rowId:O,key:b}),p++}if(R.length<I||r&&p>=r)break;D+=R.length}},async count(e={}){const n=g(e.where,t),o=`SELECT COUNT(*) as count FROM ${t} ${n}`;return(await s.select(o))[0]?.count??0},async deleteBy(e){const n=g(e,t),o=u?"key":"rowid",r=[];return await s.transaction(async E=>{const c=await E.select(`SELECT ${o} AS k FROM ${t} ${n}`);if(c.length===0)return;const i=c.map(a=>a.k);for(let a=0;a<i.length;a+=x){const S=i.slice(a,a+x),h=S.map(()=>"?").join(",");await E.execute(`DELETE FROM ${t} WHERE ${o} IN (${h})`,S)}for(const a of i)r.push({key:a,op:"delete",document:void 0})}),r},async clear(){await s.execute(`DELETE FROM ${t}`)},async batchSet(e){const n=[];return await s.transaction(async o=>{for(const r of e){const E=await k.set(r,o);n.push(E)}}),n}};return k}export{C as DEFAULT_PAGE_SIZE,G as createTable,M as getByPath,m as toJsonPath};
|
package/esm/sqlite/use-sqlite.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useCallback as
|
|
1
|
+
import{useCallback as y,useLayoutEffect as T,useReducer as C,useRef as w}from"react";import{DEFAULT_PAGE_SIZE as E}from"./table";import{shallow as K}from"../utils/shallow";const q=1e4;function F(d,k={},I=[]){const{select:f,pageSize:R=E}=k,e=w(null),[,A]=C(c=>c+1,0),t=w(new Map),g=w(null),L=y(()=>{const{select:c,...a}=k;g.current=d.search({select:(u,i)=>({doc:u,meta:i}),...a})},[d,...I]),m=y(()=>{e.current=[],t.current.clear(),L()},[L]),p=y(async c=>{e.current===null&&(e.current=[]),c===!0&&m();const{current:a}=g;if(!a)return!0;let u=!1;for(let i=0;i<R;i++){const o=await a.next();if(o.done){g.current=null,u=!0;break}t.current.has(o.value.meta.key)||(e.current.push(f?f(o.value.doc):o.value.doc),t.current.set(o.value.meta.key,e.current.length-1))}return e.current=[...e.current],u},[]),h=y(async()=>{const c=await p(!1);return A(),c},[p]);T(()=>{const c=d.subscribe(async a=>{const{mutations:u,removedAll:i}=a;if(i&&m(),!u)return;const o=e.current?.length??0;let D=o,S=!1;const b=new Set;for(const s of u){const{key:n,op:x,document:l}=s;switch(x){case"insert":{D+=1;break}case"delete":{if(e.current&&e.current.length>0&&t.current.has(n)){const r=t.current.get(n);if(r===void 0)break;b.add(r),S=!0}break}case"update":{if(t.current.has(n)){const r=t.current.get(n);if(r!==void 0&&e.current){const P=f?f(l):l,_=e.current[r];K(_,P)||(e.current[r]=P,e.current=[...e.current],S=!0)}}else{const r=await d.get(n,f);r&&(e.current=[...e.current??[],r],t.current.set(n,e.current.length-1),S=!0)}break}}}if(b.size>0&&e.current&&e.current.length>0){const s=new Map;e.current=e.current?.filter((x,l)=>!b.has(l));let n=0;for(const[x,l]of t.current)b.has(l)||(s.set(x,n),n++);t.current=s}const v=o!==D;if(v||S){if(v){await p(!0);let s=0;for(;(e.current?.length??0)<D&&s<q;)await p(!1),s++;s===q&&console.warn("Reached maximum iterations in fillNextPage loop. Possible duplicate or data issue.")}A()}});return()=>{c()}},[d]),T(()=>{m(),h()},I);const O=y(async()=>{m(),await h()},[h,m]);return[e.current,{nextPage:h,reset:O,keysIndex:t.current}]}export{F as useSqliteValue};
|
package/package.json
CHANGED
|
@@ -9,21 +9,21 @@ export interface CreateSqliteOptions<Document extends DocType> extends Omit<DbOp
|
|
|
9
9
|
readonly backend: Backend | Promise<Backend>
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export interface MutationItems {
|
|
13
|
-
mutations?: MutationResult[]
|
|
12
|
+
export interface MutationItems<Doc> {
|
|
13
|
+
mutations?: MutationResult<Doc>[]
|
|
14
14
|
removedAll?: boolean
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface SyncTable<Document extends DocType> {
|
|
18
|
-
readonly subscribe: (listener: (mutation: MutationItems) => void) => () => void
|
|
19
|
-
readonly set: (document: Document) => Promise<MutationResult
|
|
20
|
-
readonly batchSet: (documents: Document[]) => Promise<MutationResult[]>
|
|
18
|
+
readonly subscribe: (listener: (mutation: MutationItems<Document>) => void) => () => void
|
|
19
|
+
readonly set: (document: Document) => Promise<MutationResult<Document>>
|
|
20
|
+
readonly batchSet: (documents: Document[]) => Promise<MutationResult<Document>[]>
|
|
21
21
|
readonly get: <Selected = Document>(key: Key, selector?: (document: Document) => Selected) => Promise<Selected | undefined>
|
|
22
22
|
|
|
23
|
-
readonly delete: (key: Key) => Promise<MutationResult | undefined>
|
|
23
|
+
readonly delete: (key: Key) => Promise<MutationResult<Document> | undefined>
|
|
24
24
|
readonly search: <Selected = Document>(options?: SearchOptions<Document, Selected>) => AsyncIterableIterator<Selected>
|
|
25
25
|
readonly count: (options?: { where?: Where<Document> }) => Promise<number>
|
|
26
|
-
readonly deleteBy: (where: Where<Document>) => Promise<MutationResult[]>
|
|
26
|
+
readonly deleteBy: (where: Where<Document>) => Promise<MutationResult<Document>[]>
|
|
27
27
|
readonly clear: () => Promise<void>
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -53,8 +53,8 @@ export function createSqliteState<Document extends DocType>(options: CreateSqlit
|
|
|
53
53
|
if (!unknownItems) {
|
|
54
54
|
return
|
|
55
55
|
}
|
|
56
|
-
const items = unknownItems as MutationItems[]
|
|
57
|
-
const merged: MutationItems = {}
|
|
56
|
+
const items = unknownItems as MutationItems<Document>[]
|
|
57
|
+
const merged: MutationItems<Document> = {}
|
|
58
58
|
for (const item of items) {
|
|
59
59
|
if (item.removedAll) {
|
|
60
60
|
merged.removedAll = true
|
|
@@ -76,11 +76,11 @@ export function createSqliteState<Document extends DocType>(options: CreateSqlit
|
|
|
76
76
|
* Notify all subscribers of changes
|
|
77
77
|
* @param item The mutation items to notify subscribers about
|
|
78
78
|
*/
|
|
79
|
-
function handleChanges(item: MutationItems) {
|
|
79
|
+
function handleChanges(item: MutationItems<Document>) {
|
|
80
80
|
STATE_SCHEDULER.schedule(id, item)
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
const listeners = new Set<(mutation: MutationItems) => void>()
|
|
83
|
+
const listeners = new Set<(mutation: MutationItems<Document>) => void>()
|
|
84
84
|
|
|
85
85
|
const state: SyncTable<Document> = {
|
|
86
86
|
subscribe(listener) {
|
|
@@ -181,10 +181,10 @@ export async function createTable<Document extends DocType>(options: DbOptions<D
|
|
|
181
181
|
|
|
182
182
|
if (existing.length > 0) {
|
|
183
183
|
await db.execute(`UPDATE ${tableName} SET data = ? WHERE key = ?`, [json, id])
|
|
184
|
-
return { key: id, op: 'update' }
|
|
184
|
+
return { key: id, op: 'update', document }
|
|
185
185
|
} else {
|
|
186
186
|
await db.execute(`INSERT INTO ${tableName} (key, data) VALUES (?, ?)`, [id, json])
|
|
187
|
-
return { key: id, op: 'insert' }
|
|
187
|
+
return { key: id, op: 'insert', document }
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
|
@@ -192,7 +192,7 @@ export async function createTable<Document extends DocType>(options: DbOptions<D
|
|
|
192
192
|
const rows = await db.select<Array<{ id: number }>>(`SELECT last_insert_rowid() AS id`)
|
|
193
193
|
const rowid = rows[0]?.id
|
|
194
194
|
if (typeof rowid !== 'number') throw new Error('Failed to retrieve last_insert_rowid()')
|
|
195
|
-
return { key: rowid, op: 'insert' }
|
|
195
|
+
return { key: rowid, op: 'insert', document }
|
|
196
196
|
},
|
|
197
197
|
|
|
198
198
|
async get<Selected = Document>(
|
|
@@ -274,7 +274,7 @@ export async function createTable<Document extends DocType>(options: DbOptions<D
|
|
|
274
274
|
async deleteBy(where: Where<Document>) {
|
|
275
275
|
const whereSql = getWhereQuery<Document>(where, tableName)
|
|
276
276
|
const keyCol = hasUserKey ? 'key' : 'rowid'
|
|
277
|
-
const results: MutationResult[] = []
|
|
277
|
+
const results: MutationResult<Document>[] = []
|
|
278
278
|
|
|
279
279
|
await backend.transaction(async (tx) => {
|
|
280
280
|
const rows = await tx.select<Array<{ k: Key }>>(`SELECT ${keyCol} AS k FROM ${tableName} ${whereSql}`)
|
|
@@ -287,7 +287,7 @@ export async function createTable<Document extends DocType>(options: DbOptions<D
|
|
|
287
287
|
await tx.execute(`DELETE FROM ${tableName} WHERE ${keyCol} IN (${placeholders})`, chunk as unknown[])
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
for (const k of allKeys) results.push({ key: k, op: 'delete' })
|
|
290
|
+
for (const k of allKeys) results.push({ key: k, op: 'delete', document: undefined })
|
|
291
291
|
})
|
|
292
292
|
|
|
293
293
|
return results
|
|
@@ -298,7 +298,7 @@ export async function createTable<Document extends DocType>(options: DbOptions<D
|
|
|
298
298
|
},
|
|
299
299
|
|
|
300
300
|
async batchSet(documents: Document[]) {
|
|
301
|
-
const mutations: MutationResult[] = []
|
|
301
|
+
const mutations: MutationResult<Document>[] = []
|
|
302
302
|
await backend.transaction(async (tx) => {
|
|
303
303
|
for (const document of documents) {
|
|
304
304
|
const m = await table.set(document, tx)
|
|
@@ -67,20 +67,34 @@ interface DbNotGeneric {
|
|
|
67
67
|
export type Key = string | number
|
|
68
68
|
|
|
69
69
|
export type MutationOp = 'insert' | 'update' | 'delete'
|
|
70
|
-
|
|
70
|
+
|
|
71
|
+
interface MutationResultBase<T> {
|
|
71
72
|
key: Key
|
|
72
73
|
op: MutationOp
|
|
74
|
+
document?: T
|
|
75
|
+
}
|
|
76
|
+
interface MutationResultDelete<T> extends MutationResultBase<T> {
|
|
77
|
+
key: Key
|
|
78
|
+
op: 'delete'
|
|
73
79
|
}
|
|
74
80
|
|
|
81
|
+
interface MutationResultUpdateInsert<T> extends MutationResultBase<T> {
|
|
82
|
+
key: Key
|
|
83
|
+
op: 'update' | 'insert'
|
|
84
|
+
document: T
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type MutationResult<T> = MutationResultDelete<T> | MutationResultUpdateInsert<T>
|
|
88
|
+
|
|
75
89
|
export interface Table<Document extends DocType> extends DbNotGeneric {
|
|
76
|
-
readonly set: (document: Document, backendOverride?: Backend) => Promise<MutationResult
|
|
77
|
-
readonly batchSet: (documents: Document[]) => Promise<MutationResult[]>
|
|
90
|
+
readonly set: (document: Document, backendOverride?: Backend) => Promise<MutationResult<Document>>
|
|
91
|
+
readonly batchSet: (documents: Document[]) => Promise<MutationResult<Document>[]>
|
|
78
92
|
readonly get: <Selected = Document>(key: Key, selector?: (document: Document) => Selected) => Promise<Selected | undefined>
|
|
79
93
|
|
|
80
|
-
readonly delete: (key: Key) => Promise<MutationResult | undefined>
|
|
94
|
+
readonly delete: (key: Key) => Promise<MutationResult<Document> | undefined>
|
|
81
95
|
readonly search: <Selected = Document>(options?: SearchOptions<Document, Selected>) => AsyncIterableIterator<Selected>
|
|
82
96
|
readonly count: (options?: { where?: Where<Document> }) => Promise<number>
|
|
83
|
-
readonly deleteBy: (where: Where<Document>) => Promise<MutationResult[]>
|
|
97
|
+
readonly deleteBy: (where: Where<Document>) => Promise<MutationResult<Document>[]>
|
|
84
98
|
readonly clear: () => Promise<void>
|
|
85
99
|
}
|
|
86
100
|
|
package/src/sqlite/use-sqlite.ts
CHANGED
|
@@ -114,7 +114,7 @@ export function useSqliteValue<Document extends DocType, Selected = Document>(
|
|
|
114
114
|
let hasUpdate = false
|
|
115
115
|
const removeIndexes = new Set<number>()
|
|
116
116
|
for (const mutation of mutations) {
|
|
117
|
-
const { key, op } = mutation
|
|
117
|
+
const { key, op, document } = mutation
|
|
118
118
|
switch (op) {
|
|
119
119
|
case 'insert': {
|
|
120
120
|
newLength += 1
|
|
@@ -133,7 +133,7 @@ export function useSqliteValue<Document extends DocType, Selected = Document>(
|
|
|
133
133
|
if (keysIndex.current.has(key)) {
|
|
134
134
|
const index = keysIndex.current.get(key)
|
|
135
135
|
if (index !== undefined && itemsRef.current) {
|
|
136
|
-
const newItem =
|
|
136
|
+
const newItem = select ? select(document as Document) : (document as unknown as Selected)
|
|
137
137
|
const previousItem = itemsRef.current[index]
|
|
138
138
|
|
|
139
139
|
// 🆕 Only update & rerender if shallow comparison fails
|
|
@@ -4,21 +4,21 @@ import type { Where } from './table/where';
|
|
|
4
4
|
export interface CreateSqliteOptions<Document extends DocType> extends Omit<DbOptions<Document>, 'backend'> {
|
|
5
5
|
readonly backend: Backend | Promise<Backend>;
|
|
6
6
|
}
|
|
7
|
-
export interface MutationItems {
|
|
8
|
-
mutations?: MutationResult[];
|
|
7
|
+
export interface MutationItems<Doc> {
|
|
8
|
+
mutations?: MutationResult<Doc>[];
|
|
9
9
|
removedAll?: boolean;
|
|
10
10
|
}
|
|
11
11
|
export interface SyncTable<Document extends DocType> {
|
|
12
|
-
readonly subscribe: (listener: (mutation: MutationItems) => void) => () => void;
|
|
13
|
-
readonly set: (document: Document) => Promise<MutationResult
|
|
14
|
-
readonly batchSet: (documents: Document[]) => Promise<MutationResult[]>;
|
|
12
|
+
readonly subscribe: (listener: (mutation: MutationItems<Document>) => void) => () => void;
|
|
13
|
+
readonly set: (document: Document) => Promise<MutationResult<Document>>;
|
|
14
|
+
readonly batchSet: (documents: Document[]) => Promise<MutationResult<Document>[]>;
|
|
15
15
|
readonly get: <Selected = Document>(key: Key, selector?: (document: Document) => Selected) => Promise<Selected | undefined>;
|
|
16
|
-
readonly delete: (key: Key) => Promise<MutationResult | undefined>;
|
|
16
|
+
readonly delete: (key: Key) => Promise<MutationResult<Document> | undefined>;
|
|
17
17
|
readonly search: <Selected = Document>(options?: SearchOptions<Document, Selected>) => AsyncIterableIterator<Selected>;
|
|
18
18
|
readonly count: (options?: {
|
|
19
19
|
where?: Where<Document>;
|
|
20
20
|
}) => Promise<number>;
|
|
21
|
-
readonly deleteBy: (where: Where<Document>) => Promise<MutationResult[]>;
|
|
21
|
+
readonly deleteBy: (where: Where<Document>) => Promise<MutationResult<Document>[]>;
|
|
22
22
|
readonly clear: () => Promise<void>;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
@@ -44,20 +44,31 @@ interface DbNotGeneric {
|
|
|
44
44
|
}
|
|
45
45
|
export type Key = string | number;
|
|
46
46
|
export type MutationOp = 'insert' | 'update' | 'delete';
|
|
47
|
-
|
|
47
|
+
interface MutationResultBase<T> {
|
|
48
48
|
key: Key;
|
|
49
49
|
op: MutationOp;
|
|
50
|
+
document?: T;
|
|
50
51
|
}
|
|
52
|
+
interface MutationResultDelete<T> extends MutationResultBase<T> {
|
|
53
|
+
key: Key;
|
|
54
|
+
op: 'delete';
|
|
55
|
+
}
|
|
56
|
+
interface MutationResultUpdateInsert<T> extends MutationResultBase<T> {
|
|
57
|
+
key: Key;
|
|
58
|
+
op: 'update' | 'insert';
|
|
59
|
+
document: T;
|
|
60
|
+
}
|
|
61
|
+
export type MutationResult<T> = MutationResultDelete<T> | MutationResultUpdateInsert<T>;
|
|
51
62
|
export interface Table<Document extends DocType> extends DbNotGeneric {
|
|
52
|
-
readonly set: (document: Document, backendOverride?: Backend) => Promise<MutationResult
|
|
53
|
-
readonly batchSet: (documents: Document[]) => Promise<MutationResult[]>;
|
|
63
|
+
readonly set: (document: Document, backendOverride?: Backend) => Promise<MutationResult<Document>>;
|
|
64
|
+
readonly batchSet: (documents: Document[]) => Promise<MutationResult<Document>[]>;
|
|
54
65
|
readonly get: <Selected = Document>(key: Key, selector?: (document: Document) => Selected) => Promise<Selected | undefined>;
|
|
55
|
-
readonly delete: (key: Key) => Promise<MutationResult | undefined>;
|
|
66
|
+
readonly delete: (key: Key) => Promise<MutationResult<Document> | undefined>;
|
|
56
67
|
readonly search: <Selected = Document>(options?: SearchOptions<Document, Selected>) => AsyncIterableIterator<Selected>;
|
|
57
68
|
readonly count: (options?: {
|
|
58
69
|
where?: Where<Document>;
|
|
59
70
|
}) => Promise<number>;
|
|
60
|
-
readonly deleteBy: (where: Where<Document>) => Promise<MutationResult[]>;
|
|
71
|
+
readonly deleteBy: (where: Where<Document>) => Promise<MutationResult<Document>[]>;
|
|
61
72
|
readonly clear: () => Promise<void>;
|
|
62
73
|
}
|
|
63
74
|
export type MakeAllFieldAsRequired<T> = {
|