tinybase 9.5.0 → 9.6.0-beta.1
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/@types/omni/index.d.ts +4 -0
- package/@types/omni/with-schemas/index.d.ts +4 -0
- package/@types/persisters/index.d.ts +8 -1
- package/@types/persisters/persister-better-sqlite3/index.d.ts +178 -0
- package/@types/persisters/persister-better-sqlite3/with-schemas/index.d.ts +202 -0
- package/@types/persisters/persister-capacitor-sqlite/index.d.ts +181 -0
- package/@types/persisters/persister-capacitor-sqlite/with-schemas/index.d.ts +205 -0
- package/@types/persisters/persister-indexed-db/index.d.ts +17 -9
- package/@types/persisters/persister-indexed-db/with-schemas/index.d.ts +18 -10
- package/@types/persisters/persister-libsql/index.d.ts +27 -0
- package/@types/persisters/persister-libsql/with-schemas/index.d.ts +27 -0
- package/@types/persisters/persister-pg/index.d.ts +197 -0
- package/@types/persisters/persister-pg/with-schemas/index.d.ts +222 -0
- package/@types/persisters/persister-supabase/index.d.ts +201 -0
- package/@types/persisters/persister-supabase/with-schemas/index.d.ts +217 -0
- package/@types/persisters/with-schemas/index.d.ts +8 -1
- package/@types/ui-react-dom/index.d.ts +10 -10
- package/@types/ui-react-dom/with-schemas/index.d.ts +10 -10
- package/@types/ui-react-dom-charts/index.d.ts +7 -7
- package/@types/ui-react-dom-charts/with-schemas/index.d.ts +7 -7
- package/@types/ui-react-inspector/index.d.ts +1 -1
- package/@types/ui-react-inspector/with-schemas/index.d.ts +1 -1
- package/@types/ui-solid-dom/index.d.ts +10 -10
- package/@types/ui-solid-dom/with-schemas/index.d.ts +10 -10
- package/@types/ui-solid-inspector/index.d.ts +1 -1
- package/@types/ui-solid-inspector/with-schemas/index.d.ts +1 -1
- package/@types/ui-svelte-dom/index.d.ts +10 -10
- package/@types/ui-svelte-dom/with-schemas/index.d.ts +10 -10
- package/@types/ui-svelte-inspector/index.d.ts +1 -1
- package/@types/ui-svelte-inspector/with-schemas/index.d.ts +1 -1
- package/agents.md +55 -2
- package/min/omni/index.js +1 -1
- package/min/omni/index.js.gz +0 -0
- package/min/omni/with-schemas/index.js +1 -1
- package/min/omni/with-schemas/index.js.gz +0 -0
- package/min/persisters/index.js +1 -1
- package/min/persisters/index.js.gz +0 -0
- package/min/persisters/persister-better-sqlite3/index.js +1 -0
- package/min/persisters/persister-better-sqlite3/index.js.gz +0 -0
- package/min/persisters/persister-better-sqlite3/with-schemas/index.js +1 -0
- package/min/persisters/persister-better-sqlite3/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-capacitor-sqlite/index.js +1 -0
- package/min/persisters/persister-capacitor-sqlite/index.js.gz +0 -0
- package/min/persisters/persister-capacitor-sqlite/with-schemas/index.js +1 -0
- package/min/persisters/persister-capacitor-sqlite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-cr-sqlite-wasm/index.js +1 -1
- package/min/persisters/persister-cr-sqlite-wasm/index.js.gz +0 -0
- package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +1 -1
- package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-durable-object-sql-storage/index.js +1 -1
- package/min/persisters/persister-durable-object-sql-storage/index.js.gz +0 -0
- package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js +1 -1
- package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-electric-sql/index.js +1 -1
- package/min/persisters/persister-electric-sql/index.js.gz +0 -0
- package/min/persisters/persister-electric-sql/with-schemas/index.js +1 -1
- package/min/persisters/persister-electric-sql/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-expo-sqlite/index.js +1 -1
- package/min/persisters/persister-expo-sqlite/index.js.gz +0 -0
- package/min/persisters/persister-expo-sqlite/with-schemas/index.js +1 -1
- package/min/persisters/persister-expo-sqlite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-indexed-db/index.js +1 -1
- package/min/persisters/persister-indexed-db/index.js.gz +0 -0
- package/min/persisters/persister-indexed-db/with-schemas/index.js +1 -1
- package/min/persisters/persister-indexed-db/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-libsql/index.js +1 -1
- package/min/persisters/persister-libsql/index.js.gz +0 -0
- package/min/persisters/persister-libsql/with-schemas/index.js +1 -1
- package/min/persisters/persister-libsql/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-pg/index.js +1 -0
- package/min/persisters/persister-pg/index.js.gz +0 -0
- package/min/persisters/persister-pg/with-schemas/index.js +1 -0
- package/min/persisters/persister-pg/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-pglite/index.js +1 -1
- package/min/persisters/persister-pglite/index.js.gz +0 -0
- package/min/persisters/persister-pglite/with-schemas/index.js +1 -1
- package/min/persisters/persister-pglite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-postgres/index.js +1 -1
- package/min/persisters/persister-postgres/index.js.gz +0 -0
- package/min/persisters/persister-postgres/with-schemas/index.js +1 -1
- package/min/persisters/persister-postgres/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-powersync/index.js +1 -1
- package/min/persisters/persister-powersync/index.js.gz +0 -0
- package/min/persisters/persister-powersync/with-schemas/index.js +1 -1
- package/min/persisters/persister-powersync/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-react-native-sqlite/index.js +1 -1
- package/min/persisters/persister-react-native-sqlite/index.js.gz +0 -0
- package/min/persisters/persister-react-native-sqlite/with-schemas/index.js +1 -1
- package/min/persisters/persister-react-native-sqlite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-bun/index.js +1 -1
- package/min/persisters/persister-sqlite-bun/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-bun/with-schemas/index.js +1 -1
- package/min/persisters/persister-sqlite-bun/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-wasm/index.js +1 -1
- package/min/persisters/persister-sqlite-wasm/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-wasm/with-schemas/index.js +1 -1
- package/min/persisters/persister-sqlite-wasm/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-sqlite3/index.js +1 -1
- package/min/persisters/persister-sqlite3/index.js.gz +0 -0
- package/min/persisters/persister-sqlite3/with-schemas/index.js +1 -1
- package/min/persisters/persister-sqlite3/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-supabase/index.js +1 -0
- package/min/persisters/persister-supabase/index.js.gz +0 -0
- package/min/persisters/persister-supabase/with-schemas/index.js +1 -0
- package/min/persisters/persister-supabase/with-schemas/index.js.gz +0 -0
- package/min/persisters/with-schemas/index.js +1 -1
- package/min/persisters/with-schemas/index.js.gz +0 -0
- package/omni/index.js +269 -34
- package/omni/with-schemas/index.js +269 -34
- package/package.json +164 -4
- package/persisters/index.js +23 -7
- package/persisters/persister-better-sqlite3/index.js +1767 -0
- package/persisters/persister-better-sqlite3/with-schemas/index.js +1767 -0
- package/persisters/persister-capacitor-sqlite/index.js +1769 -0
- package/persisters/persister-capacitor-sqlite/with-schemas/index.js +1769 -0
- package/persisters/persister-cr-sqlite-wasm/index.js +20 -6
- package/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +20 -6
- package/persisters/persister-durable-object-sql-storage/index.js +20 -7
- package/persisters/persister-durable-object-sql-storage/with-schemas/index.js +20 -7
- package/persisters/persister-electric-sql/index.js +20 -6
- package/persisters/persister-electric-sql/with-schemas/index.js +20 -6
- package/persisters/persister-expo-sqlite/index.js +20 -6
- package/persisters/persister-expo-sqlite/with-schemas/index.js +20 -6
- package/persisters/persister-indexed-db/index.js +48 -20
- package/persisters/persister-indexed-db/with-schemas/index.js +48 -20
- package/persisters/persister-libsql/index.js +20 -6
- package/persisters/persister-libsql/with-schemas/index.js +20 -6
- package/persisters/persister-pg/index.js +1905 -0
- package/persisters/persister-pg/with-schemas/index.js +1905 -0
- package/persisters/persister-pglite/index.js +20 -6
- package/persisters/persister-pglite/with-schemas/index.js +20 -6
- package/persisters/persister-postgres/index.js +20 -6
- package/persisters/persister-postgres/with-schemas/index.js +20 -6
- package/persisters/persister-powersync/index.js +27 -10
- package/persisters/persister-powersync/with-schemas/index.js +27 -10
- package/persisters/persister-react-native-sqlite/index.js +20 -6
- package/persisters/persister-react-native-sqlite/with-schemas/index.js +20 -6
- package/persisters/persister-sqlite-bun/index.js +20 -6
- package/persisters/persister-sqlite-bun/with-schemas/index.js +20 -6
- package/persisters/persister-sqlite-wasm/index.js +20 -6
- package/persisters/persister-sqlite-wasm/with-schemas/index.js +20 -6
- package/persisters/persister-sqlite3/index.js +20 -6
- package/persisters/persister-sqlite3/with-schemas/index.js +20 -6
- package/persisters/persister-supabase/index.js +883 -0
- package/persisters/persister-supabase/with-schemas/index.js +883 -0
- package/persisters/with-schemas/index.js +23 -7
- package/readme.md +14 -14
- package/releases.md +163 -66
|
@@ -0,0 +1,1767 @@
|
|
|
1
|
+
const getTypeOf = (thing) => typeof thing;
|
|
2
|
+
const TINYBASE = 'tinybase';
|
|
3
|
+
const EMPTY_STRING = '';
|
|
4
|
+
const COMMA = ',';
|
|
5
|
+
const DOT = '.';
|
|
6
|
+
const STRING = getTypeOf(EMPTY_STRING);
|
|
7
|
+
const TRUE = 'true';
|
|
8
|
+
const UNDEFINED = '\uFFFC';
|
|
9
|
+
const strSplit = (str, separator = EMPTY_STRING, limit) =>
|
|
10
|
+
str.split(separator, limit);
|
|
11
|
+
const strReplace = (str, searchValue, replaceValue) =>
|
|
12
|
+
str.replace(searchValue, replaceValue);
|
|
13
|
+
|
|
14
|
+
const promise = Promise;
|
|
15
|
+
const getIfNotFunction = (predicate) => (value, then, otherwise) =>
|
|
16
|
+
predicate(value)
|
|
17
|
+
? /* istanbul ignore next */
|
|
18
|
+
otherwise?.()
|
|
19
|
+
: then(value);
|
|
20
|
+
const GLOBAL = globalThis;
|
|
21
|
+
const THOUSAND = 1e3;
|
|
22
|
+
const startInterval = (callback, sec, immediate) => {
|
|
23
|
+
return setInterval(callback, sec * THOUSAND);
|
|
24
|
+
};
|
|
25
|
+
const stopInterval = (interval) => clearInterval(interval);
|
|
26
|
+
const isNullish = (thing) => thing == null;
|
|
27
|
+
const isUndefined = (thing) => thing === void 0;
|
|
28
|
+
const isNull = (thing) => thing === null;
|
|
29
|
+
const isTrue = (thing) => thing === true;
|
|
30
|
+
const isFalse = (thing) => thing === false;
|
|
31
|
+
const ifNotNullish = getIfNotFunction(isNullish);
|
|
32
|
+
const ifNotUndefined = getIfNotFunction(isUndefined);
|
|
33
|
+
const isString = (thing) => getTypeOf(thing) == STRING;
|
|
34
|
+
const isArray = (thing) => Array.isArray(thing);
|
|
35
|
+
const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
|
|
36
|
+
const size = (thing) => thing.length;
|
|
37
|
+
const isEmpty = (thing) => size(thing) == 0;
|
|
38
|
+
const test = (regex, subject) => regex.test(subject);
|
|
39
|
+
const noop = () => {};
|
|
40
|
+
const promiseNew = (resolver) => new promise(resolver);
|
|
41
|
+
const promiseAll = async (promises) => promise.all(promises);
|
|
42
|
+
const promiseResolve = () => promise.resolve();
|
|
43
|
+
|
|
44
|
+
const collSize = (coll) => coll?.size ?? 0;
|
|
45
|
+
const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
|
|
46
|
+
const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
|
|
47
|
+
const collValues = (coll) => [...(coll?.values() ?? [])];
|
|
48
|
+
const collClear = (coll) => coll.clear();
|
|
49
|
+
const collForEach = (coll, cb) => coll?.forEach(cb);
|
|
50
|
+
const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
|
|
51
|
+
|
|
52
|
+
const ERROR_STORE_TYPE = 0;
|
|
53
|
+
const ERROR_CONTENT = 1;
|
|
54
|
+
const errorNew = (code, details) =>
|
|
55
|
+
new Error(
|
|
56
|
+
TINYBASE +
|
|
57
|
+
':' +
|
|
58
|
+
code +
|
|
59
|
+
(isUndefined(details)
|
|
60
|
+
? EMPTY_STRING
|
|
61
|
+
: /* istanbul ignore next */
|
|
62
|
+
':' + details),
|
|
63
|
+
);
|
|
64
|
+
const errorThrow = (code, details) => {
|
|
65
|
+
throw errorNew(code, details);
|
|
66
|
+
};
|
|
67
|
+
const tryCatch = async (action, onError) => {
|
|
68
|
+
try {
|
|
69
|
+
return await action();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
/* istanbul ignore next */
|
|
72
|
+
onError?.(error);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const tryCatchIgnore = (action, onIgnoredError) =>
|
|
76
|
+
tryCatch(action, (error) => void tryCatch(() => onIgnoredError?.(error)));
|
|
77
|
+
const tryCatchSync = (action, onError) => {
|
|
78
|
+
try {
|
|
79
|
+
return action();
|
|
80
|
+
} catch (error) {
|
|
81
|
+
onError?.(error);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const tryFinally = (action, finallyAction) => {
|
|
85
|
+
try {
|
|
86
|
+
return action();
|
|
87
|
+
} finally {
|
|
88
|
+
finallyAction();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const tryFinallyAsync = async (action, finallyAction) => {
|
|
92
|
+
try {
|
|
93
|
+
return await action();
|
|
94
|
+
} finally {
|
|
95
|
+
await finallyAction();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const arrayHas = (array, value) => array.includes(value);
|
|
100
|
+
const arrayForEach = (array, cb) => array.forEach(cb);
|
|
101
|
+
const arrayJoin = (array, sep = EMPTY_STRING) => array.join(sep);
|
|
102
|
+
const arrayMap = (array, cb) => array.map(cb);
|
|
103
|
+
const arrayFilter = (array, cb) => array.filter(cb);
|
|
104
|
+
const arrayClear = (array, to = size(array)) => array.splice(0, to);
|
|
105
|
+
const arrayPush = (array, ...values) => array.push(...values);
|
|
106
|
+
const arrayShift = (array) => array.shift();
|
|
107
|
+
|
|
108
|
+
const SINGLE_ROW_ID = '_';
|
|
109
|
+
const DEFAULT_ROW_ID_COLUMN_NAME = '_id';
|
|
110
|
+
const SELECT = 'SELECT';
|
|
111
|
+
const WHERE = 'WHERE';
|
|
112
|
+
const TABLE = 'TABLE';
|
|
113
|
+
const INSERT = 'INSERT';
|
|
114
|
+
const DELETE = 'DELETE';
|
|
115
|
+
const UPDATE = 'UPDATE';
|
|
116
|
+
const ALTER_TABLE = 'ALTER ' + TABLE;
|
|
117
|
+
const FROM = 'FROM';
|
|
118
|
+
const DELETE_FROM = DELETE + ' ' + FROM;
|
|
119
|
+
const SELECT_STAR_FROM = SELECT + '*' + FROM;
|
|
120
|
+
const PRAGMA = 'pragma_';
|
|
121
|
+
const DATA_VERSION = 'data_version';
|
|
122
|
+
const SCHEMA_VERSION = 'schema_version';
|
|
123
|
+
const PRAGMA_TABLE = 'pragma_table_';
|
|
124
|
+
const CREATE = 'CREATE ';
|
|
125
|
+
const CREATE_TABLE = CREATE + TABLE;
|
|
126
|
+
const TABLE_NAME_PLACEHOLDER_REGEX = /\$tableName/g;
|
|
127
|
+
const getWrappedCommand = (executeCommand, onSqlCommand) =>
|
|
128
|
+
onSqlCommand
|
|
129
|
+
? async (sql, params) => {
|
|
130
|
+
onSqlCommand(sql, params);
|
|
131
|
+
return await executeCommand(sql, params);
|
|
132
|
+
}
|
|
133
|
+
: executeCommand;
|
|
134
|
+
const escapeId = (str) =>
|
|
135
|
+
arrayJoin(
|
|
136
|
+
arrayMap(strSplit(str, DOT), (part) => `"${strReplace(part, /"/g, '""')}"`),
|
|
137
|
+
DOT,
|
|
138
|
+
);
|
|
139
|
+
const escapeColumnNames = (...columnNames) =>
|
|
140
|
+
arrayJoin(arrayMap(columnNames, escapeId), COMMA);
|
|
141
|
+
const anonymousPlaceholder = () => '?';
|
|
142
|
+
const getPlaceholders = (array, getPlaceholder, offset = [1]) =>
|
|
143
|
+
arrayJoin(
|
|
144
|
+
arrayMap(array, () => getPlaceholder(offset)),
|
|
145
|
+
COMMA,
|
|
146
|
+
);
|
|
147
|
+
const getWhereCondition = (tableName, condition = TRUE) =>
|
|
148
|
+
WHERE + `(${replaceTableName(condition, escapeId(tableName))})`;
|
|
149
|
+
const replaceTableName = (condition, tableName) =>
|
|
150
|
+
strReplace(condition, TABLE_NAME_PLACEHOLDER_REGEX, tableName);
|
|
151
|
+
|
|
152
|
+
const object = Object;
|
|
153
|
+
const getPrototypeOf = (obj) => object.getPrototypeOf(obj);
|
|
154
|
+
const objEntries = object.entries;
|
|
155
|
+
const isObject = (obj) =>
|
|
156
|
+
!isNullish(obj) &&
|
|
157
|
+
ifNotNullish(
|
|
158
|
+
getPrototypeOf(obj),
|
|
159
|
+
(objPrototype) =>
|
|
160
|
+
objPrototype == object.prototype ||
|
|
161
|
+
isNullish(getPrototypeOf(objPrototype)),
|
|
162
|
+
|
|
163
|
+
/* istanbul ignore next */
|
|
164
|
+
() => true,
|
|
165
|
+
);
|
|
166
|
+
const objIds = object.keys;
|
|
167
|
+
const objFreeze = object.freeze;
|
|
168
|
+
const objMerge = (...objs) => object.assign(object.create(null), ...objs);
|
|
169
|
+
const objHas = (obj, id) => object.hasOwn(obj, id);
|
|
170
|
+
const objSet = (obj, id, value) => {
|
|
171
|
+
object.defineProperty(obj, id, {
|
|
172
|
+
configurable: true,
|
|
173
|
+
enumerable: true,
|
|
174
|
+
value,
|
|
175
|
+
writable: true,
|
|
176
|
+
});
|
|
177
|
+
return value;
|
|
178
|
+
};
|
|
179
|
+
const objNew = (entries = []) => {
|
|
180
|
+
const obj = object.create(null);
|
|
181
|
+
arrayForEach(entries, ([id, value]) => objSet(obj, id, value));
|
|
182
|
+
return obj;
|
|
183
|
+
};
|
|
184
|
+
const objDel = (obj, id) => {
|
|
185
|
+
delete obj[id];
|
|
186
|
+
return obj;
|
|
187
|
+
};
|
|
188
|
+
const objForEach = (obj, cb) =>
|
|
189
|
+
arrayForEach(objIds(obj), (id) => cb(obj[id], id));
|
|
190
|
+
const objToArray = (obj, cb) =>
|
|
191
|
+
arrayMap(objEntries(obj), ([id, value]) => cb(value, id));
|
|
192
|
+
const objMap = (obj, cb) => {
|
|
193
|
+
const mapped = objNew();
|
|
194
|
+
objForEach(obj, (value, id) => objSet(mapped, id, cb(value, id)));
|
|
195
|
+
return mapped;
|
|
196
|
+
};
|
|
197
|
+
const objValues = (obj) => object.values(obj);
|
|
198
|
+
const objSize = (obj) => size(objIds(obj));
|
|
199
|
+
const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
|
|
200
|
+
|
|
201
|
+
const map = Map;
|
|
202
|
+
const mapNew = (entries) => new map(entries);
|
|
203
|
+
const mapGet = (map2, key) => map2?.get(key);
|
|
204
|
+
const mapForEach = (map2, cb) =>
|
|
205
|
+
collForEach(map2, (value, key) => cb(key, value));
|
|
206
|
+
const mapMap = (coll, cb) => {
|
|
207
|
+
const mapped = [];
|
|
208
|
+
mapForEach(coll, (key, value) => arrayPush(mapped, cb(value, key)));
|
|
209
|
+
return mapped;
|
|
210
|
+
};
|
|
211
|
+
const mapSet = (map2, key, value) =>
|
|
212
|
+
isUndefined(value) ? (collDel(map2, key), map2) : map2?.set(key, value);
|
|
213
|
+
const mapEnsure = (map2, key, getDefaultValue, hadExistingValue) => {
|
|
214
|
+
let value = mapGet(map2, key);
|
|
215
|
+
if (collHas(map2, key)) {
|
|
216
|
+
hadExistingValue?.(value);
|
|
217
|
+
} else {
|
|
218
|
+
mapSet(map2, key, (value = getDefaultValue()));
|
|
219
|
+
}
|
|
220
|
+
return value;
|
|
221
|
+
};
|
|
222
|
+
const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
|
|
223
|
+
ifNotUndefined(
|
|
224
|
+
(ensureLeaf ? mapEnsure : mapGet)(
|
|
225
|
+
node,
|
|
226
|
+
path[p],
|
|
227
|
+
p > size(path) - 2 ? ensureLeaf : mapNew,
|
|
228
|
+
),
|
|
229
|
+
(nodeOrLeaf) => {
|
|
230
|
+
if (p > size(path) - 2) {
|
|
231
|
+
if (pruneLeaf?.(nodeOrLeaf)) {
|
|
232
|
+
mapSet(node, path[p]);
|
|
233
|
+
}
|
|
234
|
+
return nodeOrLeaf;
|
|
235
|
+
}
|
|
236
|
+
const leaf = visitTree(nodeOrLeaf, path, ensureLeaf, pruneLeaf, p + 1);
|
|
237
|
+
if (collIsEmpty(nodeOrLeaf)) {
|
|
238
|
+
mapSet(node, path[p]);
|
|
239
|
+
}
|
|
240
|
+
return leaf;
|
|
241
|
+
},
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
const setNew = (entryOrEntries) =>
|
|
245
|
+
new Set(
|
|
246
|
+
isArray(entryOrEntries) || isUndefined(entryOrEntries)
|
|
247
|
+
? entryOrEntries
|
|
248
|
+
: [entryOrEntries],
|
|
249
|
+
);
|
|
250
|
+
const setAdd = (set, value) => set?.add(value);
|
|
251
|
+
|
|
252
|
+
const COLUMN_NAME = 'ColumnName';
|
|
253
|
+
const STORE = 'store';
|
|
254
|
+
const JSON$1 = 'json';
|
|
255
|
+
const STORE_TABLE_NAME = STORE + 'TableName';
|
|
256
|
+
const STORE_ID_COLUMN_NAME = STORE + 'Id' + COLUMN_NAME;
|
|
257
|
+
const STORE_COLUMN_NAME = STORE + COLUMN_NAME;
|
|
258
|
+
const AUTO_LOAD_INTERVAL_SECONDS = 'autoLoadIntervalSeconds';
|
|
259
|
+
const ROW_ID_COLUMN_NAME = 'rowId' + COLUMN_NAME;
|
|
260
|
+
const TABLE_ID = 'tableId';
|
|
261
|
+
const TABLE_NAME = 'tableName';
|
|
262
|
+
const DELETE_EMPTY_COLUMNS = 'deleteEmptyColumns';
|
|
263
|
+
const DELETE_EMPTY_TABLE = 'deleteEmptyTable';
|
|
264
|
+
const CONDITION = 'condition';
|
|
265
|
+
const DEFAULT_CONFIG = {
|
|
266
|
+
mode: JSON$1,
|
|
267
|
+
[AUTO_LOAD_INTERVAL_SECONDS]: 1,
|
|
268
|
+
};
|
|
269
|
+
const DEFAULT_TABULAR_VALUES_CONFIG = {
|
|
270
|
+
load: 0,
|
|
271
|
+
save: 0,
|
|
272
|
+
[TABLE_NAME]: TINYBASE + '_values',
|
|
273
|
+
};
|
|
274
|
+
const getValuesIn = (config) => (isArray(config) ? config : void 0);
|
|
275
|
+
const hasValues = (config) => isTrue(config) || isArray(config);
|
|
276
|
+
const getDefaultedConfig = (configOrStoreTableName) =>
|
|
277
|
+
objMerge(
|
|
278
|
+
DEFAULT_CONFIG,
|
|
279
|
+
isString(configOrStoreTableName)
|
|
280
|
+
? {[STORE_TABLE_NAME]: configOrStoreTableName}
|
|
281
|
+
: (configOrStoreTableName ?? {}),
|
|
282
|
+
);
|
|
283
|
+
const getDefaultedTabularConfigMap = (
|
|
284
|
+
configsObj,
|
|
285
|
+
defaultObj,
|
|
286
|
+
tableField,
|
|
287
|
+
exclude,
|
|
288
|
+
then,
|
|
289
|
+
) => {
|
|
290
|
+
const configMap = mapNew();
|
|
291
|
+
objForEach(configsObj, (configObj, id) => {
|
|
292
|
+
const defaultedConfig = slice(
|
|
293
|
+
objValues(
|
|
294
|
+
objMerge(
|
|
295
|
+
defaultObj,
|
|
296
|
+
isString(configObj) ? {[tableField]: configObj} : configObj,
|
|
297
|
+
),
|
|
298
|
+
),
|
|
299
|
+
0,
|
|
300
|
+
objSize(defaultObj),
|
|
301
|
+
);
|
|
302
|
+
if (!isNull(defaultedConfig[0]) && !exclude(id, defaultedConfig[0])) {
|
|
303
|
+
then(id, defaultedConfig[0]);
|
|
304
|
+
mapSet(configMap, id, defaultedConfig);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
return configMap;
|
|
308
|
+
};
|
|
309
|
+
const getConfigStructures = (configOrStoreTableName) => {
|
|
310
|
+
const config = getDefaultedConfig(configOrStoreTableName);
|
|
311
|
+
const autoLoadIntervalSeconds = config[AUTO_LOAD_INTERVAL_SECONDS];
|
|
312
|
+
if (config.mode == JSON$1) {
|
|
313
|
+
const storeTableName = config[STORE_TABLE_NAME] ?? TINYBASE;
|
|
314
|
+
return [
|
|
315
|
+
1,
|
|
316
|
+
autoLoadIntervalSeconds,
|
|
317
|
+
[
|
|
318
|
+
storeTableName,
|
|
319
|
+
config[STORE_ID_COLUMN_NAME] ?? DEFAULT_ROW_ID_COLUMN_NAME,
|
|
320
|
+
config[STORE_COLUMN_NAME] ?? STORE,
|
|
321
|
+
],
|
|
322
|
+
setNew(storeTableName),
|
|
323
|
+
];
|
|
324
|
+
}
|
|
325
|
+
const {tables: {load = {}, save = {}} = {}, values = {}} = config;
|
|
326
|
+
const valuesConfigObj = objMerge(DEFAULT_TABULAR_VALUES_CONFIG, values);
|
|
327
|
+
const {load: valuesLoad, save: valuesSave} = valuesConfigObj;
|
|
328
|
+
const valuesConfig = [
|
|
329
|
+
hasValues(valuesLoad),
|
|
330
|
+
hasValues(valuesSave),
|
|
331
|
+
valuesConfigObj[TABLE_NAME],
|
|
332
|
+
getValuesIn(valuesLoad),
|
|
333
|
+
getValuesIn(valuesSave),
|
|
334
|
+
];
|
|
335
|
+
const valuesTable = valuesConfig[2];
|
|
336
|
+
const managedTableNames = setNew(valuesTable);
|
|
337
|
+
const excludedTableNames = setNew(valuesTable);
|
|
338
|
+
const tablesLoadConfig = getDefaultedTabularConfigMap(
|
|
339
|
+
load,
|
|
340
|
+
{
|
|
341
|
+
[TABLE_ID]: null,
|
|
342
|
+
[ROW_ID_COLUMN_NAME]: DEFAULT_ROW_ID_COLUMN_NAME,
|
|
343
|
+
[CONDITION]: TRUE,
|
|
344
|
+
},
|
|
345
|
+
TABLE_ID,
|
|
346
|
+
(tableName) => collHas(excludedTableNames, tableName),
|
|
347
|
+
(tableName) => setAdd(managedTableNames, tableName),
|
|
348
|
+
);
|
|
349
|
+
const tablesSaveConfig = getDefaultedTabularConfigMap(
|
|
350
|
+
save,
|
|
351
|
+
{
|
|
352
|
+
[TABLE_NAME]: null,
|
|
353
|
+
[ROW_ID_COLUMN_NAME]: DEFAULT_ROW_ID_COLUMN_NAME,
|
|
354
|
+
[DELETE_EMPTY_COLUMNS]: 0,
|
|
355
|
+
[DELETE_EMPTY_TABLE]: 0,
|
|
356
|
+
[CONDITION]: null,
|
|
357
|
+
},
|
|
358
|
+
TABLE_NAME,
|
|
359
|
+
(_, tableName) => collHas(excludedTableNames, tableName),
|
|
360
|
+
(_, tableName) => setAdd(managedTableNames, tableName),
|
|
361
|
+
);
|
|
362
|
+
mapForEach(
|
|
363
|
+
tablesSaveConfig,
|
|
364
|
+
(_, tableSaveConfig) =>
|
|
365
|
+
(tableSaveConfig[4] ??=
|
|
366
|
+
mapGet(tablesLoadConfig, tableSaveConfig[0])?.[2] ?? TRUE),
|
|
367
|
+
);
|
|
368
|
+
return [
|
|
369
|
+
0,
|
|
370
|
+
autoLoadIntervalSeconds,
|
|
371
|
+
[tablesLoadConfig, tablesSaveConfig, valuesConfig],
|
|
372
|
+
managedTableNames,
|
|
373
|
+
];
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
const jsonString = JSON.stringify;
|
|
377
|
+
const jsonParse = JSON.parse;
|
|
378
|
+
const jsonStringWithUndefined = (obj) =>
|
|
379
|
+
jsonString(obj, (_key, value) => (isUndefined(value) ? UNDEFINED : value));
|
|
380
|
+
const jsonParseWithUndefined = (str) =>
|
|
381
|
+
// JSON.parse reviver removes properties with undefined values
|
|
382
|
+
replaceUndefinedString(jsonParse(str));
|
|
383
|
+
const replaceUndefinedString = (obj) =>
|
|
384
|
+
obj === UNDEFINED
|
|
385
|
+
? void 0
|
|
386
|
+
: isArray(obj)
|
|
387
|
+
? arrayMap(obj, replaceUndefinedString)
|
|
388
|
+
: isObject(obj)
|
|
389
|
+
? objMap(obj, replaceUndefinedString)
|
|
390
|
+
: obj;
|
|
391
|
+
|
|
392
|
+
const INTEGER = /^\d+$/;
|
|
393
|
+
const getPoolFunctions = () => {
|
|
394
|
+
const pool = [];
|
|
395
|
+
let nextId = 0;
|
|
396
|
+
return [
|
|
397
|
+
(reuse) => (reuse ? arrayShift(pool) : null) ?? EMPTY_STRING + nextId++,
|
|
398
|
+
(id) => {
|
|
399
|
+
if (test(INTEGER, id) && size(pool) < 1e3) {
|
|
400
|
+
arrayPush(pool, id);
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
];
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
|
|
407
|
+
const leaves = [];
|
|
408
|
+
const deep = (node, p) =>
|
|
409
|
+
p == size(path)
|
|
410
|
+
? arrayPush(leaves, node)
|
|
411
|
+
: isNull(path[p])
|
|
412
|
+
? collForEach(node, (node2) => deep(node2, p + 1))
|
|
413
|
+
: arrayForEach([path[p], null], (id) => deep(mapGet(node, id), p + 1));
|
|
414
|
+
deep(deepIdSet, 0);
|
|
415
|
+
return leaves;
|
|
416
|
+
};
|
|
417
|
+
const getListenerFunctions = (getThing) => {
|
|
418
|
+
let thing;
|
|
419
|
+
const [getId, releaseId] = getPoolFunctions();
|
|
420
|
+
const allListeners = mapNew();
|
|
421
|
+
const addListener = (
|
|
422
|
+
listener,
|
|
423
|
+
idSetNode,
|
|
424
|
+
path,
|
|
425
|
+
pathGetters = [],
|
|
426
|
+
extraArgsGetter = () => [],
|
|
427
|
+
) => {
|
|
428
|
+
thing ??= getThing();
|
|
429
|
+
const id = getId(1);
|
|
430
|
+
mapSet(allListeners, id, [
|
|
431
|
+
listener,
|
|
432
|
+
idSetNode,
|
|
433
|
+
path,
|
|
434
|
+
pathGetters,
|
|
435
|
+
extraArgsGetter,
|
|
436
|
+
]);
|
|
437
|
+
setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
|
|
438
|
+
return id;
|
|
439
|
+
};
|
|
440
|
+
const callListenersImpl = (continueAfterError, idSetNode, ids, extraArgs) => {
|
|
441
|
+
let errorToThrow;
|
|
442
|
+
let failed = false;
|
|
443
|
+
arrayForEach(getWildcardedLeaves(idSetNode, ids), (set) =>
|
|
444
|
+
collForEach(set, (id) => {
|
|
445
|
+
const callListener2 = () =>
|
|
446
|
+
mapGet(allListeners, id)[0](thing, ...(ids ?? []), ...extraArgs);
|
|
447
|
+
if (continueAfterError) {
|
|
448
|
+
tryCatchSync(callListener2, (error) => {
|
|
449
|
+
if (!failed) {
|
|
450
|
+
errorToThrow = error;
|
|
451
|
+
}
|
|
452
|
+
failed = true;
|
|
453
|
+
});
|
|
454
|
+
} else {
|
|
455
|
+
callListener2();
|
|
456
|
+
}
|
|
457
|
+
}),
|
|
458
|
+
);
|
|
459
|
+
if (failed) {
|
|
460
|
+
throw errorToThrow;
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
const callListeners = (idSetNode, ids, ...extraArgs) =>
|
|
464
|
+
callListenersImpl(false, idSetNode, ids, extraArgs);
|
|
465
|
+
const callListenersThenThrow = (idSetNode, ids, ...extraArgs) =>
|
|
466
|
+
callListenersImpl(true, idSetNode, ids, extraArgs);
|
|
467
|
+
const delListener = (id) =>
|
|
468
|
+
ifNotUndefined(mapGet(allListeners, id), ([, idSetNode, idOrNulls]) => {
|
|
469
|
+
visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], void 0, (idSet) => {
|
|
470
|
+
collDel(idSet, id);
|
|
471
|
+
return collIsEmpty(idSet) ? 1 : 0;
|
|
472
|
+
});
|
|
473
|
+
mapSet(allListeners, id);
|
|
474
|
+
releaseId(id);
|
|
475
|
+
return idOrNulls;
|
|
476
|
+
});
|
|
477
|
+
const callListener = (id) =>
|
|
478
|
+
ifNotUndefined(
|
|
479
|
+
mapGet(allListeners, id),
|
|
480
|
+
([listener, , path = [], pathGetters, extraArgsGetter]) => {
|
|
481
|
+
const callWithIds = (...ids) => {
|
|
482
|
+
const index = size(ids);
|
|
483
|
+
if (index == size(path)) {
|
|
484
|
+
listener(thing, ...ids, ...extraArgsGetter(ids));
|
|
485
|
+
} else if (isNull(path[index])) {
|
|
486
|
+
arrayForEach(pathGetters[index]?.(...ids) ?? [], (id2) =>
|
|
487
|
+
callWithIds(...ids, id2),
|
|
488
|
+
);
|
|
489
|
+
} else {
|
|
490
|
+
callWithIds(...ids, path[index]);
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
callWithIds();
|
|
494
|
+
},
|
|
495
|
+
);
|
|
496
|
+
return [
|
|
497
|
+
addListener,
|
|
498
|
+
callListeners,
|
|
499
|
+
delListener,
|
|
500
|
+
callListener,
|
|
501
|
+
callListenersThenThrow,
|
|
502
|
+
];
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
const scheduleRunning = mapNew();
|
|
506
|
+
const scheduleActions = mapNew();
|
|
507
|
+
const scheduleReferences = mapNew();
|
|
508
|
+
const getStoreFunctions = (
|
|
509
|
+
persist = 1 /* StoreOnly */,
|
|
510
|
+
store,
|
|
511
|
+
isSynchronizer,
|
|
512
|
+
) =>
|
|
513
|
+
persist != 1 /* StoreOnly */ && store.isMergeable()
|
|
514
|
+
? [
|
|
515
|
+
1,
|
|
516
|
+
store.__[1],
|
|
517
|
+
() => store.__[2](!isSynchronizer),
|
|
518
|
+
([[changedTables], [changedValues]]) =>
|
|
519
|
+
!objIsEmpty(changedTables) || !objIsEmpty(changedValues),
|
|
520
|
+
store.setDefaultContent,
|
|
521
|
+
]
|
|
522
|
+
: persist != 2 /* MergeableStoreOnly */
|
|
523
|
+
? [
|
|
524
|
+
0,
|
|
525
|
+
store._[7],
|
|
526
|
+
store._[8],
|
|
527
|
+
([changedTables, changedValues]) =>
|
|
528
|
+
!objIsEmpty(changedTables) || !objIsEmpty(changedValues),
|
|
529
|
+
store.setContent,
|
|
530
|
+
]
|
|
531
|
+
: errorThrow(ERROR_STORE_TYPE);
|
|
532
|
+
const createCustomPersister = (
|
|
533
|
+
store,
|
|
534
|
+
getPersisted,
|
|
535
|
+
setPersisted,
|
|
536
|
+
addPersisterListener,
|
|
537
|
+
delPersisterListener,
|
|
538
|
+
onIgnoredError,
|
|
539
|
+
persist,
|
|
540
|
+
extra = {},
|
|
541
|
+
isSynchronizer = 0,
|
|
542
|
+
scheduleId = [],
|
|
543
|
+
) => {
|
|
544
|
+
let status = 0; /* Idle */
|
|
545
|
+
let loads = 0;
|
|
546
|
+
let saves = 0;
|
|
547
|
+
let autoLoadHandle;
|
|
548
|
+
let autoLoadPromise;
|
|
549
|
+
let autoLoadGeneration = 0;
|
|
550
|
+
let pendingAutoLoads = 0;
|
|
551
|
+
let pendingScheduledAutoLoads = 0;
|
|
552
|
+
let autoLoadAfterSaveGeneration = 0;
|
|
553
|
+
let autoSaveListenerId;
|
|
554
|
+
let autoSaveGeneration = 0;
|
|
555
|
+
let destroyed = 0;
|
|
556
|
+
let destroying;
|
|
557
|
+
let activeAction;
|
|
558
|
+
const scheduleOwner = {};
|
|
559
|
+
const extraDestroy = extra.destroy;
|
|
560
|
+
mapEnsure(scheduleRunning, scheduleId, () => 0);
|
|
561
|
+
mapEnsure(scheduleActions, scheduleId, () => []);
|
|
562
|
+
mapSet(
|
|
563
|
+
scheduleReferences,
|
|
564
|
+
scheduleId,
|
|
565
|
+
(mapGet(scheduleReferences, scheduleId) ?? 0) + 1,
|
|
566
|
+
);
|
|
567
|
+
const statusListeners = mapNew();
|
|
568
|
+
const [
|
|
569
|
+
isMergeableStore,
|
|
570
|
+
getContent,
|
|
571
|
+
getChanges,
|
|
572
|
+
hasChanges,
|
|
573
|
+
setDefaultContent,
|
|
574
|
+
] = getStoreFunctions(persist, store, isSynchronizer);
|
|
575
|
+
const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
|
|
576
|
+
() => persister,
|
|
577
|
+
);
|
|
578
|
+
const setStatus = (newStatus) => {
|
|
579
|
+
if (newStatus != status) {
|
|
580
|
+
status = newStatus;
|
|
581
|
+
callListeners(statusListeners, void 0, status);
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
const run = async () => {
|
|
585
|
+
/* istanbul ignore else */
|
|
586
|
+
if (!mapGet(scheduleRunning, scheduleId)) {
|
|
587
|
+
mapSet(scheduleRunning, scheduleId, 1);
|
|
588
|
+
const scheduledActions = mapGet(scheduleActions, scheduleId);
|
|
589
|
+
let actionIndex = 0;
|
|
590
|
+
await tryFinallyAsync(
|
|
591
|
+
async () => {
|
|
592
|
+
while (actionIndex < size(scheduledActions)) {
|
|
593
|
+
const scheduledAction = scheduledActions[actionIndex++];
|
|
594
|
+
scheduledAction[2] = void 0;
|
|
595
|
+
await scheduledAction[0]();
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
() => {
|
|
599
|
+
arrayClear(scheduledActions, actionIndex);
|
|
600
|
+
mapSet(scheduleRunning, scheduleId, 0);
|
|
601
|
+
pruneSchedule();
|
|
602
|
+
},
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
const pruneSchedule = () => {
|
|
607
|
+
if (
|
|
608
|
+
!mapGet(scheduleReferences, scheduleId) &&
|
|
609
|
+
!mapGet(scheduleRunning, scheduleId) &&
|
|
610
|
+
isEmpty(mapGet(scheduleActions, scheduleId) ?? [])
|
|
611
|
+
) {
|
|
612
|
+
mapSet(scheduleRunning, scheduleId);
|
|
613
|
+
mapSet(scheduleActions, scheduleId);
|
|
614
|
+
mapSet(scheduleReferences, scheduleId);
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
const setContentOrChanges = (contentOrChanges) => {
|
|
618
|
+
(isMergeableStore && isArray(contentOrChanges?.[0])
|
|
619
|
+
? contentOrChanges?.[2] === 1
|
|
620
|
+
? store.__[4]
|
|
621
|
+
: store.__[3]
|
|
622
|
+
: contentOrChanges?.[2] === 1
|
|
623
|
+
? store._[10]
|
|
624
|
+
: store._[9])(contentOrChanges);
|
|
625
|
+
};
|
|
626
|
+
const saveAfterMutated = async () => {
|
|
627
|
+
if (isAutoSaving() && store.__?.[0]?.()) {
|
|
628
|
+
await save();
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
const trackAutoLoadPromise = (newAutoLoadPromise) =>
|
|
632
|
+
tryFinallyAsync(
|
|
633
|
+
() => (autoLoadPromise = newAutoLoadPromise),
|
|
634
|
+
() => {
|
|
635
|
+
if (autoLoadPromise == newAutoLoadPromise) {
|
|
636
|
+
autoLoadPromise = void 0;
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
);
|
|
640
|
+
const load = async (initialContent) => {
|
|
641
|
+
/* istanbul ignore else */
|
|
642
|
+
if (status != 2 /* Saving */) {
|
|
643
|
+
await tryFinallyAsync(
|
|
644
|
+
async () => {
|
|
645
|
+
setStatus(1 /* Loading */);
|
|
646
|
+
loads++;
|
|
647
|
+
await schedule(() =>
|
|
648
|
+
tryCatch(
|
|
649
|
+
async () => {
|
|
650
|
+
const content = await getPersisted();
|
|
651
|
+
if (isArray(content)) {
|
|
652
|
+
setContentOrChanges(content);
|
|
653
|
+
} else if (isUndefined(content) && initialContent) {
|
|
654
|
+
setDefaultContent(initialContent);
|
|
655
|
+
} else if (!isUndefined(content)) {
|
|
656
|
+
errorThrow(ERROR_CONTENT, content);
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
(error) => {
|
|
660
|
+
onIgnoredError?.(error);
|
|
661
|
+
if (initialContent) {
|
|
662
|
+
setDefaultContent(initialContent);
|
|
663
|
+
}
|
|
664
|
+
},
|
|
665
|
+
),
|
|
666
|
+
);
|
|
667
|
+
},
|
|
668
|
+
() => setStatus(0 /* Idle */),
|
|
669
|
+
);
|
|
670
|
+
await saveAfterMutated();
|
|
671
|
+
}
|
|
672
|
+
return persister;
|
|
673
|
+
};
|
|
674
|
+
const runAutoLoadAfterSave = async () => {
|
|
675
|
+
const generation = autoLoadAfterSaveGeneration;
|
|
676
|
+
autoLoadAfterSaveGeneration = 0;
|
|
677
|
+
if (generation && generation == autoLoadGeneration && !destroyed) {
|
|
678
|
+
if (status == 2 /* Saving */) {
|
|
679
|
+
autoLoadAfterSaveGeneration = generation;
|
|
680
|
+
} else {
|
|
681
|
+
await load();
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
const startAutoLoad = async (initialContent) => {
|
|
686
|
+
const generation = ++autoLoadGeneration;
|
|
687
|
+
let initialLoadPending = true;
|
|
688
|
+
await stopAutoLoad(true);
|
|
689
|
+
if (generation == autoLoadGeneration && !destroyed) {
|
|
690
|
+
const listenerPromise = tryCatch(async () => {
|
|
691
|
+
const handle = await addPersisterListener(async (content, changes) => {
|
|
692
|
+
if (generation == autoLoadGeneration && !destroyed) {
|
|
693
|
+
if (changes || content) {
|
|
694
|
+
const shouldSchedule =
|
|
695
|
+
initialLoadPending ||
|
|
696
|
+
status == 2 /* Saving */ ||
|
|
697
|
+
!!pendingScheduledAutoLoads;
|
|
698
|
+
pendingAutoLoads++;
|
|
699
|
+
if (shouldSchedule) {
|
|
700
|
+
pendingScheduledAutoLoads++;
|
|
701
|
+
}
|
|
702
|
+
await tryFinallyAsync(
|
|
703
|
+
async () => {
|
|
704
|
+
setStatus(1 /* Loading */);
|
|
705
|
+
loads++;
|
|
706
|
+
await (shouldSchedule
|
|
707
|
+
? schedule(() => setContentOrChanges(changes ?? content))
|
|
708
|
+
: tryFinally(
|
|
709
|
+
() => setContentOrChanges(changes ?? content),
|
|
710
|
+
() => setStatus(0 /* Idle */),
|
|
711
|
+
));
|
|
712
|
+
},
|
|
713
|
+
() => {
|
|
714
|
+
if (shouldSchedule) {
|
|
715
|
+
pendingScheduledAutoLoads--;
|
|
716
|
+
}
|
|
717
|
+
if (!--pendingAutoLoads) {
|
|
718
|
+
setStatus(0 /* Idle */);
|
|
719
|
+
}
|
|
720
|
+
},
|
|
721
|
+
);
|
|
722
|
+
if (!pendingAutoLoads) {
|
|
723
|
+
await saveAfterMutated();
|
|
724
|
+
}
|
|
725
|
+
} else if (status == 2 /* Saving */) {
|
|
726
|
+
autoLoadAfterSaveGeneration = generation;
|
|
727
|
+
} else {
|
|
728
|
+
await load();
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
if (generation == autoLoadGeneration && !destroyed) {
|
|
733
|
+
autoLoadHandle = handle;
|
|
734
|
+
} else if (!isUndefined(handle)) {
|
|
735
|
+
await delPersisterListener(handle);
|
|
736
|
+
}
|
|
737
|
+
}, onIgnoredError);
|
|
738
|
+
await trackAutoLoadPromise(listenerPromise);
|
|
739
|
+
if (generation == autoLoadGeneration && !destroyed) {
|
|
740
|
+
await tryFinallyAsync(
|
|
741
|
+
() => load(initialContent),
|
|
742
|
+
() => {
|
|
743
|
+
initialLoadPending = false;
|
|
744
|
+
},
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return persister;
|
|
749
|
+
};
|
|
750
|
+
const stopAutoLoad = async (keepGeneration = false) => {
|
|
751
|
+
autoLoadAfterSaveGeneration = 0;
|
|
752
|
+
if (!keepGeneration) {
|
|
753
|
+
autoLoadGeneration++;
|
|
754
|
+
}
|
|
755
|
+
const listenerPromise = autoLoadPromise;
|
|
756
|
+
const handle = autoLoadHandle;
|
|
757
|
+
autoLoadHandle = void 0;
|
|
758
|
+
await trackAutoLoadPromise(
|
|
759
|
+
tryFinallyAsync(
|
|
760
|
+
async () => {
|
|
761
|
+
await listenerPromise;
|
|
762
|
+
},
|
|
763
|
+
async () => {
|
|
764
|
+
if (!isUndefined(handle)) {
|
|
765
|
+
await tryCatch(() => delPersisterListener(handle), onIgnoredError);
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
),
|
|
769
|
+
);
|
|
770
|
+
return persister;
|
|
771
|
+
};
|
|
772
|
+
const isAutoLoading = () => !isUndefined(autoLoadHandle);
|
|
773
|
+
const save = async (changes) => {
|
|
774
|
+
/* istanbul ignore else */
|
|
775
|
+
if (status != 1 /* Loading */) {
|
|
776
|
+
await tryFinallyAsync(
|
|
777
|
+
() =>
|
|
778
|
+
tryFinallyAsync(
|
|
779
|
+
async () => {
|
|
780
|
+
setStatus(2 /* Saving */);
|
|
781
|
+
saves++;
|
|
782
|
+
await schedule(() =>
|
|
783
|
+
tryCatch(
|
|
784
|
+
() => setPersisted(getContent, changes),
|
|
785
|
+
onIgnoredError,
|
|
786
|
+
),
|
|
787
|
+
);
|
|
788
|
+
},
|
|
789
|
+
() => setStatus(0 /* Idle */),
|
|
790
|
+
),
|
|
791
|
+
runAutoLoadAfterSave,
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
return persister;
|
|
795
|
+
};
|
|
796
|
+
const startAutoSave = async () => {
|
|
797
|
+
const generation = ++autoSaveGeneration;
|
|
798
|
+
await stopAutoSave(true);
|
|
799
|
+
if (generation == autoSaveGeneration && !destroyed) {
|
|
800
|
+
await save();
|
|
801
|
+
if (generation == autoSaveGeneration && !destroyed) {
|
|
802
|
+
autoSaveListenerId = store.addDidFinishTransactionListener(() => {
|
|
803
|
+
if (generation == autoSaveGeneration && !destroyed) {
|
|
804
|
+
const changes = getChanges();
|
|
805
|
+
if (hasChanges(changes)) {
|
|
806
|
+
void tryCatch(() => save(changes));
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
return persister;
|
|
813
|
+
};
|
|
814
|
+
const stopAutoSave = async (keepGeneration = false) => {
|
|
815
|
+
if (!keepGeneration) {
|
|
816
|
+
autoSaveGeneration++;
|
|
817
|
+
}
|
|
818
|
+
const listenerId = autoSaveListenerId;
|
|
819
|
+
autoSaveListenerId = void 0;
|
|
820
|
+
if (!isUndefined(listenerId)) {
|
|
821
|
+
store.delListener(listenerId);
|
|
822
|
+
}
|
|
823
|
+
return persister;
|
|
824
|
+
};
|
|
825
|
+
const isAutoSaving = () => !isUndefined(autoSaveListenerId);
|
|
826
|
+
const startAutoPersisting = async (
|
|
827
|
+
initialContent,
|
|
828
|
+
startSaveFirst = false,
|
|
829
|
+
) => {
|
|
830
|
+
const [call1, call2, stop1, stop2] = startSaveFirst
|
|
831
|
+
? [startAutoSave, startAutoLoad, stopAutoSave, stopAutoLoad]
|
|
832
|
+
: [startAutoLoad, startAutoSave, stopAutoLoad, stopAutoSave];
|
|
833
|
+
const start1 = call1(initialContent);
|
|
834
|
+
const generation1 = startSaveFirst
|
|
835
|
+
? autoSaveGeneration
|
|
836
|
+
: autoLoadGeneration;
|
|
837
|
+
await start1;
|
|
838
|
+
const start2 = call2(initialContent);
|
|
839
|
+
const generation2 = startSaveFirst
|
|
840
|
+
? autoLoadGeneration
|
|
841
|
+
: autoSaveGeneration;
|
|
842
|
+
try {
|
|
843
|
+
await start2;
|
|
844
|
+
} catch (error) {
|
|
845
|
+
if (
|
|
846
|
+
generation2 ==
|
|
847
|
+
(startSaveFirst ? autoLoadGeneration : autoSaveGeneration)
|
|
848
|
+
) {
|
|
849
|
+
await tryCatchIgnore(stop2);
|
|
850
|
+
}
|
|
851
|
+
if (
|
|
852
|
+
generation1 ==
|
|
853
|
+
(startSaveFirst ? autoSaveGeneration : autoLoadGeneration)
|
|
854
|
+
) {
|
|
855
|
+
await tryCatchIgnore(stop1);
|
|
856
|
+
}
|
|
857
|
+
throw error;
|
|
858
|
+
}
|
|
859
|
+
return persister;
|
|
860
|
+
};
|
|
861
|
+
const stopAutoPersisting = async (stopSaveFirst = false) => {
|
|
862
|
+
const [call1, call2] = stopSaveFirst
|
|
863
|
+
? [stopAutoSave, stopAutoLoad]
|
|
864
|
+
: [stopAutoLoad, stopAutoSave];
|
|
865
|
+
await tryFinallyAsync(
|
|
866
|
+
() => call1(),
|
|
867
|
+
async () => {
|
|
868
|
+
await call2();
|
|
869
|
+
},
|
|
870
|
+
);
|
|
871
|
+
return persister;
|
|
872
|
+
};
|
|
873
|
+
const getStatus = () => status;
|
|
874
|
+
const addStatusListener = (listener) =>
|
|
875
|
+
addListener(listener, statusListeners);
|
|
876
|
+
const delListener = (listenerId) => {
|
|
877
|
+
delListenerImpl(listenerId);
|
|
878
|
+
return store;
|
|
879
|
+
};
|
|
880
|
+
const schedule = async (...actions) => {
|
|
881
|
+
let failed = false;
|
|
882
|
+
let firstError;
|
|
883
|
+
const completion = promiseNew((resolve) =>
|
|
884
|
+
!isEmpty(actions)
|
|
885
|
+
? arrayPush(
|
|
886
|
+
mapGet(scheduleActions, scheduleId),
|
|
887
|
+
...arrayMap(actions, (action, index) => {
|
|
888
|
+
const last = index == size(actions) - 1;
|
|
889
|
+
return [
|
|
890
|
+
async () => {
|
|
891
|
+
let completeActiveAction;
|
|
892
|
+
activeAction = promiseNew(
|
|
893
|
+
(resolve2) => (completeActiveAction = resolve2),
|
|
894
|
+
);
|
|
895
|
+
await tryFinallyAsync(
|
|
896
|
+
async () => {
|
|
897
|
+
try {
|
|
898
|
+
await tryCatch(action, onIgnoredError);
|
|
899
|
+
} catch (error) {
|
|
900
|
+
if (!failed) {
|
|
901
|
+
failed = true;
|
|
902
|
+
firstError = error;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
if (last) {
|
|
906
|
+
resolve();
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
() => {
|
|
910
|
+
activeAction = void 0;
|
|
911
|
+
completeActiveAction();
|
|
912
|
+
},
|
|
913
|
+
);
|
|
914
|
+
},
|
|
915
|
+
last ? resolve : void 0,
|
|
916
|
+
scheduleOwner,
|
|
917
|
+
];
|
|
918
|
+
}),
|
|
919
|
+
)
|
|
920
|
+
: resolve(),
|
|
921
|
+
);
|
|
922
|
+
await run();
|
|
923
|
+
await completion;
|
|
924
|
+
if (failed) {
|
|
925
|
+
throw firstError;
|
|
926
|
+
}
|
|
927
|
+
return persister;
|
|
928
|
+
};
|
|
929
|
+
const getStore = () => store;
|
|
930
|
+
const destroy = async () => {
|
|
931
|
+
if (isUndefined(destroying)) {
|
|
932
|
+
destroyed = 1;
|
|
933
|
+
destroying = (async () => {
|
|
934
|
+
const scheduledActions = mapGet(scheduleActions, scheduleId);
|
|
935
|
+
const remainingActions = arrayFilter(
|
|
936
|
+
scheduledActions,
|
|
937
|
+
([, complete, owner]) => {
|
|
938
|
+
if (owner == scheduleOwner) {
|
|
939
|
+
complete?.();
|
|
940
|
+
return false;
|
|
941
|
+
}
|
|
942
|
+
return true;
|
|
943
|
+
},
|
|
944
|
+
);
|
|
945
|
+
const actionToAwait = activeAction;
|
|
946
|
+
arrayClear(scheduledActions);
|
|
947
|
+
arrayPush(scheduledActions, ...remainingActions);
|
|
948
|
+
await tryFinallyAsync(
|
|
949
|
+
() =>
|
|
950
|
+
tryFinallyAsync(
|
|
951
|
+
() => tryFinallyAsync(stopAutoPersisting, () => actionToAwait),
|
|
952
|
+
() => extraDestroy?.(),
|
|
953
|
+
),
|
|
954
|
+
() => {
|
|
955
|
+
const references =
|
|
956
|
+
(mapGet(scheduleReferences, scheduleId) ?? 1) - 1;
|
|
957
|
+
mapSet(scheduleReferences, scheduleId, references || void 0);
|
|
958
|
+
pruneSchedule();
|
|
959
|
+
},
|
|
960
|
+
);
|
|
961
|
+
})();
|
|
962
|
+
}
|
|
963
|
+
await destroying;
|
|
964
|
+
return persister;
|
|
965
|
+
};
|
|
966
|
+
const getStats = () => ({loads, saves});
|
|
967
|
+
const persister = {
|
|
968
|
+
load,
|
|
969
|
+
startAutoLoad,
|
|
970
|
+
stopAutoLoad,
|
|
971
|
+
isAutoLoading,
|
|
972
|
+
save,
|
|
973
|
+
startAutoSave,
|
|
974
|
+
stopAutoSave,
|
|
975
|
+
isAutoSaving,
|
|
976
|
+
startAutoPersisting,
|
|
977
|
+
stopAutoPersisting,
|
|
978
|
+
getStatus,
|
|
979
|
+
addStatusListener,
|
|
980
|
+
delListener,
|
|
981
|
+
schedule,
|
|
982
|
+
getStore,
|
|
983
|
+
getStats,
|
|
984
|
+
...extra,
|
|
985
|
+
destroy,
|
|
986
|
+
};
|
|
987
|
+
return objFreeze(persister);
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
const textEncoder = new GLOBAL.TextEncoder();
|
|
991
|
+
const getHash = (string) => {
|
|
992
|
+
let hash = 2166136261;
|
|
993
|
+
arrayForEach(textEncoder.encode(string), (char) => {
|
|
994
|
+
hash ^= char;
|
|
995
|
+
hash +=
|
|
996
|
+
(hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
|
|
997
|
+
});
|
|
998
|
+
return hash >>> 0;
|
|
999
|
+
};
|
|
1000
|
+
|
|
1001
|
+
const getCommandFunctions = (
|
|
1002
|
+
databaseExecuteCommand,
|
|
1003
|
+
managedTableNames,
|
|
1004
|
+
querySchema,
|
|
1005
|
+
columnType,
|
|
1006
|
+
getPlaceholder,
|
|
1007
|
+
upsert = defaultUpsert,
|
|
1008
|
+
encode,
|
|
1009
|
+
decode,
|
|
1010
|
+
executeTransaction,
|
|
1011
|
+
) => {
|
|
1012
|
+
const schemaMap = mapNew();
|
|
1013
|
+
const uniqueSchemaMap = mapNew();
|
|
1014
|
+
let executeCommand = databaseExecuteCommand;
|
|
1015
|
+
const canSelect = (tableName, rowIdColumnName) =>
|
|
1016
|
+
collHas(mapGet(schemaMap, tableName), rowIdColumnName);
|
|
1017
|
+
const refreshSchema = async () => {
|
|
1018
|
+
collClear(schemaMap);
|
|
1019
|
+
collClear(uniqueSchemaMap);
|
|
1020
|
+
arrayForEach(
|
|
1021
|
+
await querySchema(executeCommand, managedTableNames),
|
|
1022
|
+
({tn, cn, uq}) => {
|
|
1023
|
+
setAdd(mapEnsure(schemaMap, tn, setNew), cn);
|
|
1024
|
+
if (uq) {
|
|
1025
|
+
setAdd(mapEnsure(uniqueSchemaMap, tn, setNew), cn);
|
|
1026
|
+
}
|
|
1027
|
+
},
|
|
1028
|
+
);
|
|
1029
|
+
};
|
|
1030
|
+
const loadTable = async (
|
|
1031
|
+
tableName,
|
|
1032
|
+
rowIdColumnName,
|
|
1033
|
+
condition,
|
|
1034
|
+
contentSubIds,
|
|
1035
|
+
) => {
|
|
1036
|
+
const contentSubIdSet = isUndefined(contentSubIds)
|
|
1037
|
+
? void 0
|
|
1038
|
+
: setNew(contentSubIds);
|
|
1039
|
+
const includeContentSubId = (contentSubId) =>
|
|
1040
|
+
isUndefined(contentSubIdSet) || collHas(contentSubIdSet, contentSubId);
|
|
1041
|
+
return canSelect(tableName, rowIdColumnName)
|
|
1042
|
+
? objNew(
|
|
1043
|
+
arrayFilter(
|
|
1044
|
+
arrayMap(
|
|
1045
|
+
await executeCommand(
|
|
1046
|
+
SELECT_STAR_FROM +
|
|
1047
|
+
escapeId(tableName) +
|
|
1048
|
+
getWhereCondition(tableName, condition),
|
|
1049
|
+
),
|
|
1050
|
+
(row) => {
|
|
1051
|
+
const rowId = row[rowIdColumnName];
|
|
1052
|
+
const rowContent = decode
|
|
1053
|
+
? objMap(objDel(row, rowIdColumnName), decode)
|
|
1054
|
+
: objDel(row, rowIdColumnName);
|
|
1055
|
+
return [
|
|
1056
|
+
rowId,
|
|
1057
|
+
isUndefined(contentSubIdSet)
|
|
1058
|
+
? rowContent
|
|
1059
|
+
: objNew(
|
|
1060
|
+
arrayFilter(
|
|
1061
|
+
objToArray(
|
|
1062
|
+
rowContent,
|
|
1063
|
+
(cellOrValue, contentSubId) => [
|
|
1064
|
+
contentSubId,
|
|
1065
|
+
cellOrValue,
|
|
1066
|
+
],
|
|
1067
|
+
),
|
|
1068
|
+
([contentSubId]) => includeContentSubId(contentSubId),
|
|
1069
|
+
),
|
|
1070
|
+
),
|
|
1071
|
+
];
|
|
1072
|
+
},
|
|
1073
|
+
),
|
|
1074
|
+
(entry) => !isUndefined(entry[0]) && !objIsEmpty(entry[1]),
|
|
1075
|
+
),
|
|
1076
|
+
)
|
|
1077
|
+
: {};
|
|
1078
|
+
};
|
|
1079
|
+
const saveTable = async (
|
|
1080
|
+
tableName,
|
|
1081
|
+
rowIdColumnName,
|
|
1082
|
+
content,
|
|
1083
|
+
deleteEmptyColumns,
|
|
1084
|
+
deleteEmptyTable,
|
|
1085
|
+
partial = false,
|
|
1086
|
+
condition = TRUE,
|
|
1087
|
+
contentSubIds,
|
|
1088
|
+
) => {
|
|
1089
|
+
const contentSubIdSet = isUndefined(contentSubIds)
|
|
1090
|
+
? void 0
|
|
1091
|
+
: setNew(contentSubIds);
|
|
1092
|
+
const includeContentSubId = (contentSubId) =>
|
|
1093
|
+
isUndefined(contentSubIdSet) || collHas(contentSubIdSet, contentSubId);
|
|
1094
|
+
const settingColumnNameSet = setNew();
|
|
1095
|
+
objForEach(content ?? {}, (contentRow) =>
|
|
1096
|
+
arrayForEach(
|
|
1097
|
+
arrayFilter(objIds(contentRow ?? {}), includeContentSubId),
|
|
1098
|
+
(cellOrValueId) => setAdd(settingColumnNameSet, cellOrValueId),
|
|
1099
|
+
),
|
|
1100
|
+
);
|
|
1101
|
+
const settingColumnNames = collValues(settingColumnNameSet);
|
|
1102
|
+
if (
|
|
1103
|
+
isUndefined(contentSubIdSet) &&
|
|
1104
|
+
!partial &&
|
|
1105
|
+
deleteEmptyTable &&
|
|
1106
|
+
condition == TRUE &&
|
|
1107
|
+
isEmpty(settingColumnNames) &&
|
|
1108
|
+
collHas(schemaMap, tableName)
|
|
1109
|
+
) {
|
|
1110
|
+
await executeCommand('DROP ' + TABLE + escapeId(tableName));
|
|
1111
|
+
mapSet(schemaMap, tableName);
|
|
1112
|
+
mapSet(uniqueSchemaMap, tableName);
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
const currentColumnNames = mapGet(schemaMap, tableName);
|
|
1116
|
+
const unaccountedColumnNames = setNew(
|
|
1117
|
+
arrayFilter(
|
|
1118
|
+
collValues(currentColumnNames),
|
|
1119
|
+
(columnName) =>
|
|
1120
|
+
columnName == rowIdColumnName || includeContentSubId(columnName),
|
|
1121
|
+
),
|
|
1122
|
+
);
|
|
1123
|
+
if (!isEmpty(settingColumnNames)) {
|
|
1124
|
+
if (!collHas(schemaMap, tableName)) {
|
|
1125
|
+
await executeCommand(
|
|
1126
|
+
CREATE_TABLE +
|
|
1127
|
+
escapeId(tableName) +
|
|
1128
|
+
`(${escapeId(rowIdColumnName)}${columnType} PRIMARY KEY${arrayJoin(
|
|
1129
|
+
arrayMap(
|
|
1130
|
+
settingColumnNames,
|
|
1131
|
+
(settingColumnName) =>
|
|
1132
|
+
COMMA + escapeId(settingColumnName) + columnType,
|
|
1133
|
+
),
|
|
1134
|
+
)});`,
|
|
1135
|
+
);
|
|
1136
|
+
mapSet(
|
|
1137
|
+
schemaMap,
|
|
1138
|
+
tableName,
|
|
1139
|
+
setNew([rowIdColumnName, ...settingColumnNames]),
|
|
1140
|
+
);
|
|
1141
|
+
mapSet(uniqueSchemaMap, tableName, setNew([rowIdColumnName]));
|
|
1142
|
+
} else {
|
|
1143
|
+
await promiseAll(
|
|
1144
|
+
arrayMap(
|
|
1145
|
+
[rowIdColumnName, ...settingColumnNames],
|
|
1146
|
+
async (settingColumnName) => {
|
|
1147
|
+
if (!collDel(unaccountedColumnNames, settingColumnName)) {
|
|
1148
|
+
await executeCommand(
|
|
1149
|
+
ALTER_TABLE +
|
|
1150
|
+
escapeId(tableName) +
|
|
1151
|
+
'ADD' +
|
|
1152
|
+
escapeId(settingColumnName) +
|
|
1153
|
+
columnType,
|
|
1154
|
+
);
|
|
1155
|
+
setAdd(currentColumnNames, settingColumnName);
|
|
1156
|
+
}
|
|
1157
|
+
},
|
|
1158
|
+
),
|
|
1159
|
+
);
|
|
1160
|
+
if (
|
|
1161
|
+
upsert == defaultUpsert &&
|
|
1162
|
+
!collHas(mapGet(uniqueSchemaMap, tableName), rowIdColumnName)
|
|
1163
|
+
) {
|
|
1164
|
+
const indexName =
|
|
1165
|
+
TINYBASE +
|
|
1166
|
+
'_pk_' +
|
|
1167
|
+
getHash(jsonString([tableName, rowIdColumnName]));
|
|
1168
|
+
await executeCommand(
|
|
1169
|
+
'CREATE UNIQUE INDEX IF NOT EXISTS' +
|
|
1170
|
+
escapeId(indexName) +
|
|
1171
|
+
'ON' +
|
|
1172
|
+
escapeId(tableName) +
|
|
1173
|
+
`(${escapeId(rowIdColumnName)})`,
|
|
1174
|
+
);
|
|
1175
|
+
setAdd(
|
|
1176
|
+
mapEnsure(uniqueSchemaMap, tableName, setNew),
|
|
1177
|
+
rowIdColumnName,
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
await promiseAll([
|
|
1183
|
+
...(!partial && deleteEmptyColumns
|
|
1184
|
+
? arrayMap(
|
|
1185
|
+
collValues(unaccountedColumnNames),
|
|
1186
|
+
async (unaccountedColumnName) => {
|
|
1187
|
+
if (unaccountedColumnName != rowIdColumnName) {
|
|
1188
|
+
await executeCommand(
|
|
1189
|
+
ALTER_TABLE +
|
|
1190
|
+
escapeId(tableName) +
|
|
1191
|
+
'DROP' +
|
|
1192
|
+
escapeId(unaccountedColumnName),
|
|
1193
|
+
);
|
|
1194
|
+
collDel(currentColumnNames, unaccountedColumnName);
|
|
1195
|
+
}
|
|
1196
|
+
},
|
|
1197
|
+
)
|
|
1198
|
+
: []),
|
|
1199
|
+
]);
|
|
1200
|
+
if (partial) {
|
|
1201
|
+
if (isUndefined(content)) {
|
|
1202
|
+
if (isUndefined(contentSubIdSet)) {
|
|
1203
|
+
await executeCommand(
|
|
1204
|
+
DELETE_FROM +
|
|
1205
|
+
escapeId(tableName) +
|
|
1206
|
+
getWhereCondition(tableName, condition),
|
|
1207
|
+
);
|
|
1208
|
+
}
|
|
1209
|
+
} else {
|
|
1210
|
+
await promiseAll(
|
|
1211
|
+
objToArray(content, async (row, rowId) => {
|
|
1212
|
+
if (isUndefined(row)) {
|
|
1213
|
+
await executeCommand(
|
|
1214
|
+
DELETE_FROM +
|
|
1215
|
+
escapeId(tableName) +
|
|
1216
|
+
getWhereCondition(tableName, condition) +
|
|
1217
|
+
`AND(${escapeId(rowIdColumnName)}=${getPlaceholder([1])})`,
|
|
1218
|
+
[rowId],
|
|
1219
|
+
);
|
|
1220
|
+
} else if (!isEmpty(settingColumnNames)) {
|
|
1221
|
+
const changingColumnNames = arrayFilter(
|
|
1222
|
+
objIds(row),
|
|
1223
|
+
includeContentSubId,
|
|
1224
|
+
);
|
|
1225
|
+
if (!isEmpty(changingColumnNames)) {
|
|
1226
|
+
await upsert(
|
|
1227
|
+
executeCommand,
|
|
1228
|
+
tableName,
|
|
1229
|
+
rowIdColumnName,
|
|
1230
|
+
changingColumnNames,
|
|
1231
|
+
{
|
|
1232
|
+
[rowId]: arrayMap(changingColumnNames, (cellId) =>
|
|
1233
|
+
encode ? encode(row[cellId]) : row[cellId],
|
|
1234
|
+
),
|
|
1235
|
+
},
|
|
1236
|
+
getPlaceholder,
|
|
1237
|
+
currentColumnNames,
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
}),
|
|
1242
|
+
);
|
|
1243
|
+
}
|
|
1244
|
+
} else {
|
|
1245
|
+
if (!isEmpty(settingColumnNames)) {
|
|
1246
|
+
const changingColumnNames = arrayFilter(
|
|
1247
|
+
collValues(mapGet(schemaMap, tableName)),
|
|
1248
|
+
(changingColumnName) =>
|
|
1249
|
+
changingColumnName != rowIdColumnName &&
|
|
1250
|
+
includeContentSubId(changingColumnName),
|
|
1251
|
+
);
|
|
1252
|
+
const rows = objNew();
|
|
1253
|
+
const deleteRowIds = [];
|
|
1254
|
+
objForEach(content ?? {}, (row, rowId) => {
|
|
1255
|
+
objSet(
|
|
1256
|
+
rows,
|
|
1257
|
+
rowId,
|
|
1258
|
+
arrayMap(changingColumnNames, (cellId) =>
|
|
1259
|
+
encode ? encode(row?.[cellId]) : row?.[cellId],
|
|
1260
|
+
),
|
|
1261
|
+
);
|
|
1262
|
+
arrayPush(deleteRowIds, rowId);
|
|
1263
|
+
});
|
|
1264
|
+
await upsert(
|
|
1265
|
+
executeCommand,
|
|
1266
|
+
tableName,
|
|
1267
|
+
rowIdColumnName,
|
|
1268
|
+
changingColumnNames,
|
|
1269
|
+
rows,
|
|
1270
|
+
getPlaceholder,
|
|
1271
|
+
currentColumnNames,
|
|
1272
|
+
);
|
|
1273
|
+
await executeCommand(
|
|
1274
|
+
DELETE_FROM +
|
|
1275
|
+
escapeId(tableName) +
|
|
1276
|
+
getWhereCondition(tableName, condition) + // eslint-disable-next-line max-len
|
|
1277
|
+
`AND${escapeId(rowIdColumnName)}NOT IN(${getPlaceholders(deleteRowIds, getPlaceholder)})`,
|
|
1278
|
+
deleteRowIds,
|
|
1279
|
+
);
|
|
1280
|
+
} else if (
|
|
1281
|
+
isUndefined(contentSubIdSet) &&
|
|
1282
|
+
collHas(schemaMap, tableName)
|
|
1283
|
+
) {
|
|
1284
|
+
await executeCommand(
|
|
1285
|
+
DELETE_FROM +
|
|
1286
|
+
escapeId(tableName) +
|
|
1287
|
+
getWhereCondition(tableName, condition),
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
const transaction = async (actions) => {
|
|
1293
|
+
if (executeTransaction) {
|
|
1294
|
+
return await executeTransaction(async (transactionExecuteCommand) => {
|
|
1295
|
+
const executeCommandWas = executeCommand;
|
|
1296
|
+
executeCommand = transactionExecuteCommand;
|
|
1297
|
+
return await tryFinallyAsync(actions, () => {
|
|
1298
|
+
executeCommand = executeCommandWas;
|
|
1299
|
+
});
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
await databaseExecuteCommand('BEGIN');
|
|
1303
|
+
try {
|
|
1304
|
+
const result = await actions();
|
|
1305
|
+
await databaseExecuteCommand('END');
|
|
1306
|
+
return result;
|
|
1307
|
+
} catch (error) {
|
|
1308
|
+
await tryCatch(() => databaseExecuteCommand('ROLLBACK'));
|
|
1309
|
+
throw error;
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
return [refreshSchema, loadTable, saveTable, transaction];
|
|
1313
|
+
};
|
|
1314
|
+
const defaultUpsert = async (
|
|
1315
|
+
executeCommand,
|
|
1316
|
+
tableName,
|
|
1317
|
+
rowIdColumnName,
|
|
1318
|
+
changingColumnNames,
|
|
1319
|
+
rows,
|
|
1320
|
+
getPlaceholder,
|
|
1321
|
+
) => {
|
|
1322
|
+
const offset = [1];
|
|
1323
|
+
await executeCommand(
|
|
1324
|
+
INSERT +
|
|
1325
|
+
' INTO' +
|
|
1326
|
+
escapeId(tableName) +
|
|
1327
|
+
'(' +
|
|
1328
|
+
escapeColumnNames(rowIdColumnName, ...changingColumnNames) +
|
|
1329
|
+
')VALUES' +
|
|
1330
|
+
arrayJoin(
|
|
1331
|
+
objToArray(
|
|
1332
|
+
rows,
|
|
1333
|
+
(row) =>
|
|
1334
|
+
'(' +
|
|
1335
|
+
getPlaceholder(offset) +
|
|
1336
|
+
',' +
|
|
1337
|
+
getPlaceholders(row, getPlaceholder, offset) +
|
|
1338
|
+
')',
|
|
1339
|
+
),
|
|
1340
|
+
COMMA,
|
|
1341
|
+
) +
|
|
1342
|
+
'ON CONFLICT(' +
|
|
1343
|
+
escapeId(rowIdColumnName) +
|
|
1344
|
+
`)DO ${UPDATE} SET` +
|
|
1345
|
+
arrayJoin(
|
|
1346
|
+
arrayMap(
|
|
1347
|
+
changingColumnNames,
|
|
1348
|
+
(columnName) =>
|
|
1349
|
+
escapeId(columnName) + '=excluded.' + escapeId(columnName),
|
|
1350
|
+
),
|
|
1351
|
+
COMMA,
|
|
1352
|
+
),
|
|
1353
|
+
objToArray(rows, (row, id) => [
|
|
1354
|
+
id,
|
|
1355
|
+
...arrayMap(row, (value) => value ?? null),
|
|
1356
|
+
]).flat(),
|
|
1357
|
+
);
|
|
1358
|
+
};
|
|
1359
|
+
|
|
1360
|
+
const createJsonPersister = (
|
|
1361
|
+
store,
|
|
1362
|
+
executeCommand,
|
|
1363
|
+
addPersisterListener,
|
|
1364
|
+
delPersisterListener,
|
|
1365
|
+
onIgnoredError,
|
|
1366
|
+
extraDestroy,
|
|
1367
|
+
persist,
|
|
1368
|
+
[storeTableName, storeIdColumnName, storeColumnName],
|
|
1369
|
+
managedTableNames,
|
|
1370
|
+
querySchema,
|
|
1371
|
+
thing,
|
|
1372
|
+
getThing,
|
|
1373
|
+
columnType,
|
|
1374
|
+
getPlaceholder,
|
|
1375
|
+
upsert,
|
|
1376
|
+
_encode,
|
|
1377
|
+
_decode,
|
|
1378
|
+
executeTransaction,
|
|
1379
|
+
) => {
|
|
1380
|
+
const [refreshSchema, loadTable, saveTable, transaction] =
|
|
1381
|
+
getCommandFunctions(
|
|
1382
|
+
executeCommand,
|
|
1383
|
+
managedTableNames,
|
|
1384
|
+
querySchema,
|
|
1385
|
+
columnType,
|
|
1386
|
+
getPlaceholder,
|
|
1387
|
+
upsert,
|
|
1388
|
+
void 0,
|
|
1389
|
+
void 0,
|
|
1390
|
+
executeTransaction,
|
|
1391
|
+
);
|
|
1392
|
+
const getPersisted = () =>
|
|
1393
|
+
transaction(async () => {
|
|
1394
|
+
await refreshSchema();
|
|
1395
|
+
return jsonParseWithUndefined(
|
|
1396
|
+
(await loadTable(storeTableName, storeIdColumnName))[SINGLE_ROW_ID]?.[
|
|
1397
|
+
storeColumnName
|
|
1398
|
+
] ?? 'null',
|
|
1399
|
+
);
|
|
1400
|
+
});
|
|
1401
|
+
const setPersisted = (getContent) =>
|
|
1402
|
+
transaction(async () => {
|
|
1403
|
+
await refreshSchema();
|
|
1404
|
+
await saveTable(
|
|
1405
|
+
storeTableName,
|
|
1406
|
+
storeIdColumnName,
|
|
1407
|
+
{
|
|
1408
|
+
[SINGLE_ROW_ID]: {
|
|
1409
|
+
[storeColumnName]: jsonStringWithUndefined(getContent() ?? null),
|
|
1410
|
+
},
|
|
1411
|
+
},
|
|
1412
|
+
true,
|
|
1413
|
+
true,
|
|
1414
|
+
);
|
|
1415
|
+
});
|
|
1416
|
+
return createCustomPersister(
|
|
1417
|
+
store,
|
|
1418
|
+
getPersisted,
|
|
1419
|
+
setPersisted,
|
|
1420
|
+
addPersisterListener,
|
|
1421
|
+
delPersisterListener,
|
|
1422
|
+
onIgnoredError,
|
|
1423
|
+
persist,
|
|
1424
|
+
{[getThing]: () => thing, destroy: extraDestroy},
|
|
1425
|
+
0,
|
|
1426
|
+
thing,
|
|
1427
|
+
);
|
|
1428
|
+
};
|
|
1429
|
+
|
|
1430
|
+
const createTabularPersister = (
|
|
1431
|
+
store,
|
|
1432
|
+
executeCommand,
|
|
1433
|
+
addPersisterListener,
|
|
1434
|
+
delPersisterListener,
|
|
1435
|
+
onIgnoredError,
|
|
1436
|
+
extraDestroy,
|
|
1437
|
+
persist,
|
|
1438
|
+
[
|
|
1439
|
+
tablesLoadConfig,
|
|
1440
|
+
tablesSaveConfig,
|
|
1441
|
+
[
|
|
1442
|
+
valuesLoad,
|
|
1443
|
+
valuesSave,
|
|
1444
|
+
valuesTableName,
|
|
1445
|
+
valuesLoadValueIds,
|
|
1446
|
+
valuesSaveValueIds,
|
|
1447
|
+
],
|
|
1448
|
+
],
|
|
1449
|
+
managedTableNames,
|
|
1450
|
+
querySchema,
|
|
1451
|
+
thing,
|
|
1452
|
+
getThing,
|
|
1453
|
+
columnType,
|
|
1454
|
+
getPlaceholder,
|
|
1455
|
+
upsert,
|
|
1456
|
+
encode,
|
|
1457
|
+
decode,
|
|
1458
|
+
executeTransaction,
|
|
1459
|
+
) => {
|
|
1460
|
+
const [refreshSchema, loadTable, saveTable, transaction] =
|
|
1461
|
+
getCommandFunctions(
|
|
1462
|
+
executeCommand,
|
|
1463
|
+
managedTableNames,
|
|
1464
|
+
querySchema,
|
|
1465
|
+
columnType,
|
|
1466
|
+
getPlaceholder,
|
|
1467
|
+
upsert,
|
|
1468
|
+
encode,
|
|
1469
|
+
decode,
|
|
1470
|
+
executeTransaction,
|
|
1471
|
+
);
|
|
1472
|
+
const saveTables = (tables, partial) =>
|
|
1473
|
+
promiseAll(
|
|
1474
|
+
mapMap(
|
|
1475
|
+
tablesSaveConfig,
|
|
1476
|
+
async (
|
|
1477
|
+
[
|
|
1478
|
+
tableName,
|
|
1479
|
+
rowIdColumnName,
|
|
1480
|
+
deleteEmptyColumns,
|
|
1481
|
+
deleteEmptyTable,
|
|
1482
|
+
condition,
|
|
1483
|
+
],
|
|
1484
|
+
tableId,
|
|
1485
|
+
) => {
|
|
1486
|
+
if (!partial || objHas(tables, tableId)) {
|
|
1487
|
+
await saveTable(
|
|
1488
|
+
tableName,
|
|
1489
|
+
rowIdColumnName,
|
|
1490
|
+
tables[tableId],
|
|
1491
|
+
deleteEmptyColumns,
|
|
1492
|
+
deleteEmptyTable,
|
|
1493
|
+
partial,
|
|
1494
|
+
condition,
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
},
|
|
1498
|
+
),
|
|
1499
|
+
);
|
|
1500
|
+
const getValuesSubset = (values, valueIds, partial) =>
|
|
1501
|
+
objNew(
|
|
1502
|
+
partial == true
|
|
1503
|
+
? arrayFilter(
|
|
1504
|
+
objToArray(values, (value, valueId) => [valueId, value]),
|
|
1505
|
+
([valueId]) => arrayHas(valueIds, valueId),
|
|
1506
|
+
)
|
|
1507
|
+
: arrayFilter(
|
|
1508
|
+
arrayMap(valueIds, (valueId) => [valueId, values[valueId]]),
|
|
1509
|
+
([, value]) => !isUndefined(value),
|
|
1510
|
+
),
|
|
1511
|
+
);
|
|
1512
|
+
const saveValues = async (values, partial) =>
|
|
1513
|
+
valuesSave
|
|
1514
|
+
? await saveTable(
|
|
1515
|
+
valuesTableName,
|
|
1516
|
+
DEFAULT_ROW_ID_COLUMN_NAME,
|
|
1517
|
+
{
|
|
1518
|
+
[SINGLE_ROW_ID]: isUndefined(valuesSaveValueIds)
|
|
1519
|
+
? values
|
|
1520
|
+
: getValuesSubset(values, valuesSaveValueIds, partial),
|
|
1521
|
+
},
|
|
1522
|
+
true,
|
|
1523
|
+
true,
|
|
1524
|
+
partial,
|
|
1525
|
+
void 0,
|
|
1526
|
+
valuesSaveValueIds,
|
|
1527
|
+
)
|
|
1528
|
+
: null;
|
|
1529
|
+
const loadTables = async () =>
|
|
1530
|
+
objNew(
|
|
1531
|
+
arrayFilter(
|
|
1532
|
+
await promiseAll(
|
|
1533
|
+
mapMap(
|
|
1534
|
+
tablesLoadConfig,
|
|
1535
|
+
async ([tableId, rowIdColumnName, condition], tableName) => [
|
|
1536
|
+
tableId,
|
|
1537
|
+
await loadTable(tableName, rowIdColumnName, condition),
|
|
1538
|
+
],
|
|
1539
|
+
),
|
|
1540
|
+
),
|
|
1541
|
+
(pair) => !objIsEmpty(pair[1]),
|
|
1542
|
+
),
|
|
1543
|
+
);
|
|
1544
|
+
const loadValues = async () =>
|
|
1545
|
+
valuesLoad
|
|
1546
|
+
? (
|
|
1547
|
+
await loadTable(
|
|
1548
|
+
valuesTableName,
|
|
1549
|
+
DEFAULT_ROW_ID_COLUMN_NAME,
|
|
1550
|
+
void 0,
|
|
1551
|
+
valuesLoadValueIds,
|
|
1552
|
+
)
|
|
1553
|
+
)[SINGLE_ROW_ID]
|
|
1554
|
+
: {};
|
|
1555
|
+
const getPersisted = () =>
|
|
1556
|
+
transaction(async () => {
|
|
1557
|
+
await refreshSchema();
|
|
1558
|
+
const tables = await loadTables();
|
|
1559
|
+
const values = await loadValues();
|
|
1560
|
+
return !objIsEmpty(tables) || !isUndefined(values)
|
|
1561
|
+
? [tables, values]
|
|
1562
|
+
: void 0;
|
|
1563
|
+
});
|
|
1564
|
+
const setPersisted = (getContent, changes) =>
|
|
1565
|
+
transaction(async () => {
|
|
1566
|
+
await refreshSchema();
|
|
1567
|
+
if (!isUndefined(changes)) {
|
|
1568
|
+
await saveTables(changes[0], true);
|
|
1569
|
+
await saveValues(changes[1], true);
|
|
1570
|
+
} else {
|
|
1571
|
+
const [tables, values] = getContent();
|
|
1572
|
+
await saveTables(tables);
|
|
1573
|
+
await saveValues(values);
|
|
1574
|
+
}
|
|
1575
|
+
});
|
|
1576
|
+
return createCustomPersister(
|
|
1577
|
+
store,
|
|
1578
|
+
getPersisted,
|
|
1579
|
+
setPersisted,
|
|
1580
|
+
addPersisterListener,
|
|
1581
|
+
delPersisterListener,
|
|
1582
|
+
onIgnoredError,
|
|
1583
|
+
persist,
|
|
1584
|
+
{[getThing]: () => thing, destroy: extraDestroy},
|
|
1585
|
+
0,
|
|
1586
|
+
thing,
|
|
1587
|
+
);
|
|
1588
|
+
};
|
|
1589
|
+
|
|
1590
|
+
const createCustomSqlitePersister = (
|
|
1591
|
+
store,
|
|
1592
|
+
configOrStoreTableName,
|
|
1593
|
+
rawExecuteCommand,
|
|
1594
|
+
addChangeListener,
|
|
1595
|
+
delChangeListener,
|
|
1596
|
+
onSqlCommand,
|
|
1597
|
+
onIgnoredError,
|
|
1598
|
+
destroy,
|
|
1599
|
+
persist,
|
|
1600
|
+
thing,
|
|
1601
|
+
getThing = 'getDb',
|
|
1602
|
+
upsert,
|
|
1603
|
+
executeTransaction,
|
|
1604
|
+
) => {
|
|
1605
|
+
let dataVersion;
|
|
1606
|
+
let schemaVersion;
|
|
1607
|
+
let totalChanges;
|
|
1608
|
+
const executeCommand = getWrappedCommand(rawExecuteCommand, onSqlCommand);
|
|
1609
|
+
const [
|
|
1610
|
+
isJson,
|
|
1611
|
+
autoLoadIntervalSeconds,
|
|
1612
|
+
defaultedConfig,
|
|
1613
|
+
managedTableNamesSet,
|
|
1614
|
+
] = getConfigStructures(configOrStoreTableName);
|
|
1615
|
+
if (!isJson && store.isMergeable()) {
|
|
1616
|
+
errorThrow(ERROR_STORE_TYPE);
|
|
1617
|
+
}
|
|
1618
|
+
const addPersisterListener = (listener) => {
|
|
1619
|
+
let active = 1;
|
|
1620
|
+
let baselineReady = 0;
|
|
1621
|
+
let interval;
|
|
1622
|
+
let nativeChange = 0;
|
|
1623
|
+
let task;
|
|
1624
|
+
const checkForChanges = async (notify = true) => {
|
|
1625
|
+
const [{d, s, c}] = await executeCommand(
|
|
1626
|
+
SELECT + // eslint-disable-next-line max-len
|
|
1627
|
+
` ${DATA_VERSION} d,${SCHEMA_VERSION} s,TOTAL_CHANGES() c FROM ${PRAGMA}${DATA_VERSION} JOIN ${PRAGMA}${SCHEMA_VERSION}`,
|
|
1628
|
+
);
|
|
1629
|
+
if (
|
|
1630
|
+
active &&
|
|
1631
|
+
(d != dataVersion || s != schemaVersion || c != totalChanges)
|
|
1632
|
+
) {
|
|
1633
|
+
const shouldNotify = notify && !nativeChange && !isNullish(dataVersion);
|
|
1634
|
+
dataVersion = d;
|
|
1635
|
+
schemaVersion = s;
|
|
1636
|
+
totalChanges = c;
|
|
1637
|
+
if (shouldNotify && active) {
|
|
1638
|
+
await listener();
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
};
|
|
1642
|
+
const stopPolling = () => {
|
|
1643
|
+
if (!isUndefined(interval)) {
|
|
1644
|
+
stopInterval(interval);
|
|
1645
|
+
interval = void 0;
|
|
1646
|
+
}
|
|
1647
|
+
};
|
|
1648
|
+
const startPolling = () => {
|
|
1649
|
+
if (active && isUndefined(interval)) {
|
|
1650
|
+
interval = startInterval(() => run(true), autoLoadIntervalSeconds);
|
|
1651
|
+
}
|
|
1652
|
+
};
|
|
1653
|
+
const run = (notify = false) => {
|
|
1654
|
+
if (task) {
|
|
1655
|
+
return task;
|
|
1656
|
+
}
|
|
1657
|
+
const newTask = tryFinallyAsync(
|
|
1658
|
+
() =>
|
|
1659
|
+
tryCatchIgnore(async () => {
|
|
1660
|
+
if (!baselineReady) {
|
|
1661
|
+
await checkForChanges(false);
|
|
1662
|
+
baselineReady = 1;
|
|
1663
|
+
} else if (notify) {
|
|
1664
|
+
await checkForChanges();
|
|
1665
|
+
}
|
|
1666
|
+
while (active && nativeChange) {
|
|
1667
|
+
nativeChange = 0;
|
|
1668
|
+
await checkForChanges(false);
|
|
1669
|
+
if (active) {
|
|
1670
|
+
await listener();
|
|
1671
|
+
await checkForChanges();
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
}, onIgnoredError),
|
|
1675
|
+
() => {
|
|
1676
|
+
if (task == newTask) {
|
|
1677
|
+
task = void 0;
|
|
1678
|
+
}
|
|
1679
|
+
if (active) {
|
|
1680
|
+
if (nativeChange) {
|
|
1681
|
+
void run();
|
|
1682
|
+
} else {
|
|
1683
|
+
startPolling();
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
},
|
|
1687
|
+
);
|
|
1688
|
+
task = newTask;
|
|
1689
|
+
return newTask;
|
|
1690
|
+
};
|
|
1691
|
+
const listeningHandle = addChangeListener((tableName) => {
|
|
1692
|
+
if (active && collHas(managedTableNamesSet, tableName)) {
|
|
1693
|
+
nativeChange = 1;
|
|
1694
|
+
stopPolling();
|
|
1695
|
+
void promiseResolve().then(() => (active ? void run() : 0));
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
return run().then(() => async () => {
|
|
1699
|
+
active = 0;
|
|
1700
|
+
nativeChange = 0;
|
|
1701
|
+
stopPolling();
|
|
1702
|
+
await tryFinallyAsync(
|
|
1703
|
+
async () => await task,
|
|
1704
|
+
async () => {
|
|
1705
|
+
dataVersion = schemaVersion = totalChanges = null;
|
|
1706
|
+
await delChangeListener(listeningHandle);
|
|
1707
|
+
},
|
|
1708
|
+
);
|
|
1709
|
+
});
|
|
1710
|
+
};
|
|
1711
|
+
const delPersisterListener = (stopPollingAndDelUpdateListener) =>
|
|
1712
|
+
stopPollingAndDelUpdateListener();
|
|
1713
|
+
return (isJson ? createJsonPersister : createTabularPersister)(
|
|
1714
|
+
store,
|
|
1715
|
+
executeCommand,
|
|
1716
|
+
addPersisterListener,
|
|
1717
|
+
delPersisterListener,
|
|
1718
|
+
onIgnoredError,
|
|
1719
|
+
destroy,
|
|
1720
|
+
persist,
|
|
1721
|
+
defaultedConfig,
|
|
1722
|
+
collValues(managedTableNamesSet),
|
|
1723
|
+
async (executeCommand2, managedTableNames) =>
|
|
1724
|
+
await executeCommand2(
|
|
1725
|
+
SELECT + // eslint-disable-next-line max-len
|
|
1726
|
+
` t.name tn,c.name cn,c.pk OR EXISTS(${SELECT} 1 FROM ${PRAGMA}index_list(t.name)i,${PRAGMA}index_info(i.name)ii ${WHERE} i."unique"=1 AND ii.name=c.name AND(${SELECT} count(*) FROM ${PRAGMA}index_info(i.name))=1)uq FROM ${PRAGMA_TABLE}list()t,${PRAGMA_TABLE}info(t.name)c ${WHERE} t.schema='main'AND t.type IN('table','view')AND t.name IN(${getPlaceholders(managedTableNames, anonymousPlaceholder)})ORDER BY t.name,c.name`,
|
|
1727
|
+
managedTableNames,
|
|
1728
|
+
),
|
|
1729
|
+
thing,
|
|
1730
|
+
getThing,
|
|
1731
|
+
EMPTY_STRING,
|
|
1732
|
+
anonymousPlaceholder,
|
|
1733
|
+
upsert,
|
|
1734
|
+
(cellOrValue) =>
|
|
1735
|
+
isTrue(cellOrValue) ? 1 : isFalse(cellOrValue) ? 0 : cellOrValue,
|
|
1736
|
+
void 0,
|
|
1737
|
+
executeTransaction,
|
|
1738
|
+
);
|
|
1739
|
+
};
|
|
1740
|
+
|
|
1741
|
+
const createBetterSqlite3Persister = (
|
|
1742
|
+
store,
|
|
1743
|
+
db,
|
|
1744
|
+
configOrStoreTableName,
|
|
1745
|
+
onSqlCommand,
|
|
1746
|
+
onIgnoredError,
|
|
1747
|
+
) =>
|
|
1748
|
+
createCustomSqlitePersister(
|
|
1749
|
+
store,
|
|
1750
|
+
configOrStoreTableName,
|
|
1751
|
+
async (sql, params = []) => {
|
|
1752
|
+
const statement = db.prepare(sql);
|
|
1753
|
+
return statement.reader
|
|
1754
|
+
? statement.all(...params)
|
|
1755
|
+
: (statement.run(...params), []);
|
|
1756
|
+
},
|
|
1757
|
+
() => noop,
|
|
1758
|
+
(unsubscribeFunction) => unsubscribeFunction(),
|
|
1759
|
+
onSqlCommand,
|
|
1760
|
+
onIgnoredError,
|
|
1761
|
+
noop,
|
|
1762
|
+
3,
|
|
1763
|
+
// StoreOrMergeableStore,
|
|
1764
|
+
db,
|
|
1765
|
+
);
|
|
1766
|
+
|
|
1767
|
+
export {createBetterSqlite3Persister};
|