jsql-neo 6.4.0-beta.4 → 6.4.0-beta.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.
- package/README.md +1 -1
- package/index.js +1 -1
- package/lib/database.js +83 -74
- package/lib/native_client.js +31 -31
- package/lib/plugin.js +12 -10
- package/lib/wasm_client.js +29 -29
- package/package.json +1 -1
- package/test/query-opt.test.js +8 -8
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> **One engine to rule them all** — a Rust-powered embedded database that speaks your language:
|
|
4
4
|
> MySQL, PostgreSQL, MongoDB, Redis, SQL, TypeScript, **and the browser**.
|
|
5
5
|
|
|
6
|
-
> **v6.4.0-beta.
|
|
6
|
+
> **v6.4.0-beta.6** — official release build · [github.com/vexify-org/JSQL-neo](https://github.com/vexify-org/JSQL-neo) · [jsql.vexify.top](https://jsql.vexify.top)
|
|
7
7
|
|
|
8
8
|

|
|
9
9
|

|
package/index.js
CHANGED
package/lib/database.js
CHANGED
|
@@ -652,13 +652,13 @@ class Database {
|
|
|
652
652
|
switch (op.op) {
|
|
653
653
|
case 'createTable':
|
|
654
654
|
if (op.table && !this._tables[op.table]) {
|
|
655
|
-
this.
|
|
655
|
+
this._createTableSync(op.table, op.schema || {});
|
|
656
656
|
}
|
|
657
657
|
return true;
|
|
658
658
|
|
|
659
659
|
case 'dropTable':
|
|
660
660
|
if (op.table && this._tables[op.table]) {
|
|
661
|
-
this.
|
|
661
|
+
this._dropTableSync(op.table);
|
|
662
662
|
}
|
|
663
663
|
return true;
|
|
664
664
|
|
|
@@ -696,22 +696,7 @@ class Database {
|
|
|
696
696
|
// 表管理
|
|
697
697
|
// ============================================================
|
|
698
698
|
|
|
699
|
-
|
|
700
|
-
if (!name || name.length > 64 || name === '.' || name === '..' || /[\x00-\x1f/\\]|\.\./.test(name)) {
|
|
701
|
-
throw createError('ER_BAD_TABLE_NAME', name);
|
|
702
|
-
}
|
|
703
|
-
if (typeof schema === 'string') {
|
|
704
|
-
const parsed = {};
|
|
705
|
-
for (const seg of schema.split(',')) {
|
|
706
|
-
const trimmed = seg.trim();
|
|
707
|
-
if (!trimmed) continue;
|
|
708
|
-
const parts = trimmed.split(/\s+/);
|
|
709
|
-
const field = parts.shift();
|
|
710
|
-
parsed[field] = parts.join(' ').toLowerCase().trim() || 'string';
|
|
711
|
-
}
|
|
712
|
-
schema = parsed;
|
|
713
|
-
}
|
|
714
|
-
if (!this._runHooks('beforeCreateTable', [name, schema])) throw createError('ER_PLUGIN_ABORT', 'createTable aborted by plugin');
|
|
699
|
+
_createTableSync(name, schema) {
|
|
715
700
|
if (this._tables[name] || (this._dirMode && this._meta.tables[name])) {
|
|
716
701
|
throw createError('ER_TABLE_EXISTS_ERROR', name);
|
|
717
702
|
}
|
|
@@ -741,13 +726,31 @@ class Database {
|
|
|
741
726
|
this._markDirty(name);
|
|
742
727
|
this._walWrite({ op: 'createTable', table: name, schema });
|
|
743
728
|
this._emit('createTable', { name, schema });
|
|
744
|
-
this._runHooks('afterCreateTable', [name, schema]);
|
|
745
729
|
return table;
|
|
746
730
|
}
|
|
747
731
|
|
|
748
|
-
|
|
749
|
-
if (!
|
|
750
|
-
|
|
732
|
+
async createTable(name, schema) {
|
|
733
|
+
if (!name || name.length > 64 || name === '.' || name === '..' || /[\x00-\x1f/\\]|\.\./.test(name)) {
|
|
734
|
+
throw createError('ER_BAD_TABLE_NAME', name);
|
|
735
|
+
}
|
|
736
|
+
if (typeof schema === 'string') {
|
|
737
|
+
const parsed = {};
|
|
738
|
+
for (const seg of schema.split(',')) {
|
|
739
|
+
const trimmed = seg.trim();
|
|
740
|
+
if (!trimmed) continue;
|
|
741
|
+
const parts = trimmed.split(/\s+/);
|
|
742
|
+
const field = parts.shift();
|
|
743
|
+
parsed[field] = parts.join(' ').toLowerCase().trim() || 'string';
|
|
744
|
+
}
|
|
745
|
+
schema = parsed;
|
|
746
|
+
}
|
|
747
|
+
if (!(await this._runHooks('beforeCreateTable', [name, schema]))) throw createError('ER_PLUGIN_ABORT', 'createTable aborted by plugin');
|
|
748
|
+
const table = this._createTableSync(name, schema);
|
|
749
|
+
await this._runHooks('afterCreateTable', [name, schema]);
|
|
750
|
+
return table;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
_dropTableSync(name) {
|
|
751
754
|
if (this._tables[name]) {
|
|
752
755
|
delete this._tables[name];
|
|
753
756
|
}
|
|
@@ -766,7 +769,13 @@ class Database {
|
|
|
766
769
|
this._walWrite({ op: 'dropTable', table: name });
|
|
767
770
|
this._markDirty(name);
|
|
768
771
|
this._emit('dropTable', { name });
|
|
769
|
-
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
async dropTable(name) {
|
|
775
|
+
if (!this._tables[name] && !(this._dirMode && this._meta.tables[name])) throw createError('ER_NO_SUCH_TABLE', name);
|
|
776
|
+
if (!(await this._runHooks('beforeDropTable', [name]))) return;
|
|
777
|
+
this._dropTableSync(name);
|
|
778
|
+
await this._runHooks('afterDropTable', [name]);
|
|
770
779
|
}
|
|
771
780
|
|
|
772
781
|
/**
|
|
@@ -777,7 +786,7 @@ class Database {
|
|
|
777
786
|
* 各自都存了一份。漏掉任何一个都会留下一张「半改名」的表:
|
|
778
787
|
* 查得到数据却列不出来,或者反过来。
|
|
779
788
|
*/
|
|
780
|
-
renameTable(oldName, newName, { ifExists = false } = {}) {
|
|
789
|
+
async renameTable(oldName, newName, { ifExists = false } = {}) {
|
|
781
790
|
if (oldName === newName) {
|
|
782
791
|
if (!this._tables[oldName]) {
|
|
783
792
|
if (ifExists) return false;
|
|
@@ -796,7 +805,7 @@ class Database {
|
|
|
796
805
|
/[\x00-\x1f/\\]|\.\./.test(newName)) {
|
|
797
806
|
throw createError('ER_BAD_TABLE_NAME', newName);
|
|
798
807
|
}
|
|
799
|
-
if (!this._runHooks('beforeRenameTable', [oldName, newName])) return false;
|
|
808
|
+
if (!(await this._runHooks('beforeRenameTable', [oldName, newName]))) return false;
|
|
800
809
|
|
|
801
810
|
const table = this._tables[oldName];
|
|
802
811
|
|
|
@@ -848,7 +857,7 @@ class Database {
|
|
|
848
857
|
this._markDirty(newName);
|
|
849
858
|
this._walWrite({ op: 'renameTable', from: oldName, to: newName });
|
|
850
859
|
this._emit('renameTable', { from: oldName, to: newName });
|
|
851
|
-
this._runHooks('afterRenameTable', [oldName, newName]);
|
|
860
|
+
await this._runHooks('afterRenameTable', [oldName, newName]);
|
|
852
861
|
return true;
|
|
853
862
|
}
|
|
854
863
|
|
|
@@ -1723,7 +1732,7 @@ class Database {
|
|
|
1723
1732
|
}
|
|
1724
1733
|
|
|
1725
1734
|
async start() {
|
|
1726
|
-
this._runHooks('onStart', []);
|
|
1735
|
+
await this._runHooks('onStart', []);
|
|
1727
1736
|
this._emit('start', {});
|
|
1728
1737
|
if (this._dirMode && !this._sigInstalled) {
|
|
1729
1738
|
this._sigInstalled = true;
|
|
@@ -1772,11 +1781,11 @@ class Database {
|
|
|
1772
1781
|
}
|
|
1773
1782
|
}
|
|
1774
1783
|
|
|
1775
|
-
insert(tableName, data) {
|
|
1784
|
+
async insert(tableName, data) {
|
|
1776
1785
|
const table = this._ensureTable(tableName);
|
|
1777
1786
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
1778
1787
|
const arr = Array.isArray(data) ? data : [data];
|
|
1779
|
-
if (!this._runHooks('beforeInsert', [tableName, arr])) return [];
|
|
1788
|
+
if (!(await this._runHooks('beforeInsert', [tableName, arr]))) return [];
|
|
1780
1789
|
const pk = this._pkOf(table);
|
|
1781
1790
|
const ids = [];
|
|
1782
1791
|
const logged = [];
|
|
@@ -1791,20 +1800,20 @@ class Database {
|
|
|
1791
1800
|
// 有主键才可幂等回放;无主键表回放会重复插行,故不记录
|
|
1792
1801
|
if (pk) this._walWrite({ op: 'insert', table: tableName, rows: logged });
|
|
1793
1802
|
this._emit('insert', { table: tableName, count: arr.length, ids });
|
|
1794
|
-
this._runHooks('afterInsert', [tableName, arr, ids]);
|
|
1803
|
+
await this._runHooks('afterInsert', [tableName, arr, ids]);
|
|
1795
1804
|
this._markDirty(tableName);
|
|
1796
1805
|
return ids;
|
|
1797
1806
|
}
|
|
1798
1807
|
|
|
1799
1808
|
async flush() {
|
|
1800
|
-
if (!this._runHooks('beforeFlush', [])) return;
|
|
1809
|
+
if (!(await this._runHooks('beforeFlush', []))) return;
|
|
1801
1810
|
if (this._dirMode) {
|
|
1802
1811
|
this._flushDirty();
|
|
1803
1812
|
this._saveMeta();
|
|
1804
1813
|
} else if (!this._memoryMode) {
|
|
1805
1814
|
this.save();
|
|
1806
1815
|
}
|
|
1807
|
-
this._runHooks('afterFlush', []);
|
|
1816
|
+
await this._runHooks('afterFlush', []);
|
|
1808
1817
|
return this;
|
|
1809
1818
|
}
|
|
1810
1819
|
|
|
@@ -1822,10 +1831,10 @@ class Database {
|
|
|
1822
1831
|
return null;
|
|
1823
1832
|
}
|
|
1824
1833
|
|
|
1825
|
-
find(tableName, filter, opts = {}) {
|
|
1834
|
+
async find(tableName, filter, opts = {}) {
|
|
1826
1835
|
const table = this._ensureTable(tableName);
|
|
1827
1836
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
1828
|
-
if (!this._runHooks('beforeFind', [tableName, { filter, opts }])) return [];
|
|
1837
|
+
if (!(await this._runHooks('beforeFind', [tableName, { filter, opts }]))) return [];
|
|
1829
1838
|
const { limit, offset = 0 } = opts;
|
|
1830
1839
|
// P1-4: 软删除模式下不得泄露已删除行——只看可见行
|
|
1831
1840
|
let rows = table._applyFilterOptimized(table._getVisibleRows(), filter || {});
|
|
@@ -1834,7 +1843,7 @@ class Database {
|
|
|
1834
1843
|
// P1-11: 返回浅拷贝,防止调用方修改影响内部数据
|
|
1835
1844
|
rows = rows.map(r => ({ ...r }));
|
|
1836
1845
|
this._touchTable(tableName);
|
|
1837
|
-
this._runHooks('afterFind', [tableName, { filter, opts }, rows]);
|
|
1846
|
+
await this._runHooks('afterFind', [tableName, { filter, opts }, rows]);
|
|
1838
1847
|
return rows;
|
|
1839
1848
|
}
|
|
1840
1849
|
|
|
@@ -1847,9 +1856,9 @@ class Database {
|
|
|
1847
1856
|
|
|
1848
1857
|
async query(sql, paramsOrOpts, opts) {
|
|
1849
1858
|
const { executeSQL } = require('./sql');
|
|
1850
|
-
if (!this._runHooks('beforeQuery', [sql, paramsOrOpts, opts])) return null;
|
|
1859
|
+
if (!(await this._runHooks('beforeQuery', [sql, paramsOrOpts, opts]))) return null;
|
|
1851
1860
|
const result = await executeSQL(this, sql, paramsOrOpts, opts);
|
|
1852
|
-
this._runHooks('afterQuery', [sql, paramsOrOpts, opts, result]);
|
|
1861
|
+
await this._runHooks('afterQuery', [sql, paramsOrOpts, opts, result]);
|
|
1853
1862
|
return result;
|
|
1854
1863
|
}
|
|
1855
1864
|
|
|
@@ -1857,28 +1866,28 @@ class Database {
|
|
|
1857
1866
|
return require('./prepared').createPrepared(this, sql);
|
|
1858
1867
|
}
|
|
1859
1868
|
|
|
1860
|
-
findById(tableName, id) {
|
|
1869
|
+
async findById(tableName, id) {
|
|
1861
1870
|
const table = this._ensureTable(tableName);
|
|
1862
1871
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
1863
|
-
if (!this._runHooks('beforeFind', [tableName, { id }])) return null;
|
|
1872
|
+
if (!(await this._runHooks('beforeFind', [tableName, { id }]))) return null;
|
|
1864
1873
|
const row = this._resolveId(table, id);
|
|
1865
1874
|
// P1-4: 软删除行对普通读取不可见
|
|
1866
1875
|
if (row && row._deleted) return null;
|
|
1867
1876
|
// P1-11: 返回浅拷贝,防止调用方修改影响内部数据
|
|
1868
1877
|
const result = row ? { ...row } : null;
|
|
1869
1878
|
this._touchTable(tableName);
|
|
1870
|
-
this._runHooks('afterFind', [tableName, { id }, result]);
|
|
1879
|
+
await this._runHooks('afterFind', [tableName, { id }, result]);
|
|
1871
1880
|
return result;
|
|
1872
1881
|
}
|
|
1873
1882
|
|
|
1874
|
-
findByIds(tableName, ids) {
|
|
1883
|
+
async findByIds(tableName, ids) {
|
|
1875
1884
|
const table = this._ensureTable(tableName);
|
|
1876
1885
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
1877
|
-
if (!this._runHooks('beforeFind', [tableName, { ids }])) return null;
|
|
1886
|
+
if (!(await this._runHooks('beforeFind', [tableName, { ids }]))) return null;
|
|
1878
1887
|
// P1-4: 过滤掉软删除行;P1-11: 返回浅拷贝
|
|
1879
1888
|
const rows = ids.map(id => this._resolveId(table, id)).filter(r => r !== null && !r._deleted).map(r => ({ ...r }));
|
|
1880
1889
|
this._touchTable(tableName);
|
|
1881
|
-
this._runHooks('afterFind', [tableName, { ids }, rows]);
|
|
1890
|
+
await this._runHooks('afterFind', [tableName, { ids }, rows]);
|
|
1882
1891
|
return rows;
|
|
1883
1892
|
}
|
|
1884
1893
|
|
|
@@ -1886,21 +1895,21 @@ class Database {
|
|
|
1886
1895
|
return this.findByIds(tableName, ids);
|
|
1887
1896
|
}
|
|
1888
1897
|
|
|
1889
|
-
count(tableName) {
|
|
1898
|
+
async count(tableName) {
|
|
1890
1899
|
const table = this._ensureTable(tableName);
|
|
1891
1900
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
1892
|
-
this._runHooks('beforeCount', [tableName]);
|
|
1901
|
+
if (!(await this._runHooks('beforeCount', [tableName]))) return undefined;
|
|
1893
1902
|
// P1-4: 软删除模式下只统计可见行
|
|
1894
1903
|
const n = table._softDelete ? table._getVisibleRows().length : table._rows.length;
|
|
1895
1904
|
this._touchTable(tableName);
|
|
1896
|
-
this._runHooks('afterCount', [tableName, n]);
|
|
1905
|
+
await this._runHooks('afterCount', [tableName, n]);
|
|
1897
1906
|
return n;
|
|
1898
1907
|
}
|
|
1899
1908
|
|
|
1900
|
-
updateById(tableName, id, data) {
|
|
1909
|
+
async updateById(tableName, id, data) {
|
|
1901
1910
|
const table = this._ensureTable(tableName);
|
|
1902
1911
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
1903
|
-
if (!this._runHooks('beforeUpdate', [tableName, id, data])) return;
|
|
1912
|
+
if (!(await this._runHooks('beforeUpdate', [tableName, id, data]))) return;
|
|
1904
1913
|
// P1-9: updateById 绕过类型校验——先校验再更新
|
|
1905
1914
|
const validated = table._validateDataTypes({ ...data }, true);
|
|
1906
1915
|
const row = this._resolveId(table, id);
|
|
@@ -1925,16 +1934,16 @@ class Database {
|
|
|
1925
1934
|
Object.assign(row, validated);
|
|
1926
1935
|
if (pk) this._walWrite({ op: 'update', table: tableName, pk, id, row: { ...validated } });
|
|
1927
1936
|
this._emit('update', { table: tableName, id, data: validated });
|
|
1928
|
-
this._runHooks('afterUpdate', [tableName, id, validated, { ok: true }]);
|
|
1937
|
+
await this._runHooks('afterUpdate', [tableName, id, validated, { ok: true }]);
|
|
1929
1938
|
this._markDirty(tableName);
|
|
1930
1939
|
return { ok: true };
|
|
1931
1940
|
}
|
|
1932
1941
|
|
|
1933
|
-
updateByIds(tableName, entries) {
|
|
1942
|
+
async updateByIds(tableName, entries) {
|
|
1934
1943
|
const table = this._ensureTable(tableName);
|
|
1935
1944
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
1936
1945
|
const pairs = entries.map(([id, data]) => [id, data]);
|
|
1937
|
-
if (!this._runHooks('beforeUpdate', [tableName, pairs])) return;
|
|
1946
|
+
if (!(await this._runHooks('beforeUpdate', [tableName, pairs]))) return;
|
|
1938
1947
|
const pk = this._pkOf(table);
|
|
1939
1948
|
let count = 0;
|
|
1940
1949
|
for (const [id, data] of pairs) {
|
|
@@ -1946,21 +1955,21 @@ class Database {
|
|
|
1946
1955
|
}
|
|
1947
1956
|
}
|
|
1948
1957
|
this._emit('update', { table: tableName, entries: pairs, result: { ok: true, count } });
|
|
1949
|
-
this._runHooks('afterUpdate', [tableName, pairs, { ok: true, count }]);
|
|
1958
|
+
await this._runHooks('afterUpdate', [tableName, pairs, { ok: true, count }]);
|
|
1950
1959
|
this._markDirty(tableName);
|
|
1951
1960
|
return { ok: true, count };
|
|
1952
1961
|
}
|
|
1953
1962
|
|
|
1954
|
-
removeById(tableName, id) {
|
|
1963
|
+
async removeById(tableName, id) {
|
|
1955
1964
|
const table = this._ensureTable(tableName);
|
|
1956
1965
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
1957
|
-
if (!this._runHooks('beforeDelete', [tableName, id])) return;
|
|
1966
|
+
if (!(await this._runHooks('beforeDelete', [tableName, id]))) return;
|
|
1958
1967
|
if (table._primaryKey) {
|
|
1959
1968
|
const removed = table.removeById(id);
|
|
1960
1969
|
if (removed === 0) return { ok: false, error: 'not found' };
|
|
1961
1970
|
this._walWrite({ op: 'remove', table: tableName, pk: table._primaryKey, id });
|
|
1962
1971
|
this._emit('delete', { table: tableName, id });
|
|
1963
|
-
this._runHooks('afterDelete', [tableName, id, { ok: true }]);
|
|
1972
|
+
await this._runHooks('afterDelete', [tableName, id, { ok: true }]);
|
|
1964
1973
|
this._markDirty(tableName);
|
|
1965
1974
|
return { ok: true };
|
|
1966
1975
|
}
|
|
@@ -1971,15 +1980,15 @@ class Database {
|
|
|
1971
1980
|
table._rebuildAllBTrees();
|
|
1972
1981
|
for (const field of Object.keys(table._indexes)) table.createIndex(field);
|
|
1973
1982
|
this._emit('delete', { table: tableName, id });
|
|
1974
|
-
this._runHooks('afterDelete', [tableName, id, { ok: true }]);
|
|
1983
|
+
await this._runHooks('afterDelete', [tableName, id, { ok: true }]);
|
|
1975
1984
|
this._markDirty(tableName);
|
|
1976
1985
|
return { ok: true };
|
|
1977
1986
|
}
|
|
1978
1987
|
|
|
1979
|
-
removeByIds(tableName, ids) {
|
|
1988
|
+
async removeByIds(tableName, ids) {
|
|
1980
1989
|
const table = this._ensureTable(tableName);
|
|
1981
1990
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
1982
|
-
if (!this._runHooks('beforeDelete', [tableName, ids])) return;
|
|
1991
|
+
if (!(await this._runHooks('beforeDelete', [tableName, ids]))) return;
|
|
1983
1992
|
let removed = 0;
|
|
1984
1993
|
if (table._primaryKey) {
|
|
1985
1994
|
for (const id of ids) removed += table.removeById(id);
|
|
@@ -2014,15 +2023,15 @@ class Database {
|
|
|
2014
2023
|
for (const field of Object.keys(table._indexes)) table.createIndex(field);
|
|
2015
2024
|
}
|
|
2016
2025
|
this._emit('delete', { table: tableName, ids, result: { ok: true, count: removed } });
|
|
2017
|
-
this._runHooks('afterDelete', [tableName, ids, { ok: true, count: removed }]);
|
|
2026
|
+
await this._runHooks('afterDelete', [tableName, ids, { ok: true, count: removed }]);
|
|
2018
2027
|
this._markDirty(tableName);
|
|
2019
2028
|
return { ok: true, count: removed };
|
|
2020
2029
|
}
|
|
2021
2030
|
|
|
2022
|
-
removeWhere(tableName, filter) {
|
|
2031
|
+
async removeWhere(tableName, filter) {
|
|
2023
2032
|
const table = this._ensureTable(tableName);
|
|
2024
2033
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
2025
|
-
if (!this._runHooks('beforeDelete', [tableName, [filter]])) return { ok: true, count: 0 };
|
|
2034
|
+
if (!(await this._runHooks('beforeDelete', [tableName, [filter]]))) return { ok: true, count: 0 };
|
|
2026
2035
|
const before = table._rows.length;
|
|
2027
2036
|
// P1-4: 只匹配可见行(软删除行已“不存在”,不应被硬删操作波及)
|
|
2028
2037
|
const matched = table._applyFilter(table._getVisibleRows(), filter || {});
|
|
@@ -2033,31 +2042,31 @@ class Database {
|
|
|
2033
2042
|
table._rebuildAllBTrees();
|
|
2034
2043
|
for (const field of Object.keys(table._indexes)) table.createIndex(field);
|
|
2035
2044
|
this._emit('delete', { table: tableName, ids: [], result: { ok: true, count: removed } });
|
|
2036
|
-
this._runHooks('afterDelete', [tableName, [filter], { ok: true, count: removed }]);
|
|
2045
|
+
await this._runHooks('afterDelete', [tableName, [filter], { ok: true, count: removed }]);
|
|
2037
2046
|
this._markDirty(tableName);
|
|
2038
2047
|
return { ok: true, count: removed };
|
|
2039
2048
|
}
|
|
2040
2049
|
|
|
2041
|
-
insertMany(tableName, items) {
|
|
2050
|
+
async insertMany(tableName, items) {
|
|
2042
2051
|
const table = this._ensureTable(tableName);
|
|
2043
2052
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
2044
2053
|
const arr = Array.isArray(items) ? items : [items];
|
|
2045
|
-
if (!this._runHooks('beforeInsert', [tableName, arr])) return [];
|
|
2054
|
+
if (!(await this._runHooks('beforeInsert', [tableName, arr]))) return [];
|
|
2046
2055
|
const inserted = table.insertMany(arr);
|
|
2047
2056
|
// P1-6: insertMany 不写 WAL——崩溃恢复时丢失这些操作
|
|
2048
2057
|
if (table._primaryKey && inserted.length > 0) {
|
|
2049
2058
|
this._walWrite({ op: 'insert', table: tableName, rows: inserted });
|
|
2050
2059
|
}
|
|
2051
2060
|
this._emit('insert', { table: tableName, count: arr.length });
|
|
2052
|
-
this._runHooks('afterInsert', [tableName, arr, inserted]);
|
|
2061
|
+
await this._runHooks('afterInsert', [tableName, arr, inserted]);
|
|
2053
2062
|
this._markDirty(tableName);
|
|
2054
2063
|
return inserted;
|
|
2055
2064
|
}
|
|
2056
2065
|
|
|
2057
|
-
update(tableName, query, updates) {
|
|
2066
|
+
async update(tableName, query, updates) {
|
|
2058
2067
|
const table = this._ensureTable(tableName);
|
|
2059
2068
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
2060
|
-
if (!this._runHooks('beforeUpdate', [tableName, query, updates])) return 0;
|
|
2069
|
+
if (!(await this._runHooks('beforeUpdate', [tableName, query, updates]))) return 0;
|
|
2061
2070
|
const count = table.update(query, updates);
|
|
2062
2071
|
// P1-6: update 不写 WAL——崩溃恢复时丢失这些操作
|
|
2063
2072
|
if (table._primaryKey && count > 0) {
|
|
@@ -2068,15 +2077,15 @@ class Database {
|
|
|
2068
2077
|
}
|
|
2069
2078
|
}
|
|
2070
2079
|
this._emit('update', { table: tableName, query, count });
|
|
2071
|
-
this._runHooks('afterUpdate', [tableName, query, updates, count]);
|
|
2080
|
+
await this._runHooks('afterUpdate', [tableName, query, updates, count]);
|
|
2072
2081
|
this._markDirty(tableName);
|
|
2073
2082
|
return count;
|
|
2074
2083
|
}
|
|
2075
2084
|
|
|
2076
|
-
delete(tableName, query = {}) {
|
|
2085
|
+
async delete(tableName, query = {}) {
|
|
2077
2086
|
const table = this._ensureTable(tableName);
|
|
2078
2087
|
if (!table) throw createError('ER_NO_SUCH_TABLE', tableName);
|
|
2079
|
-
if (!this._runHooks('beforeDelete', [tableName, query])) return 0;
|
|
2088
|
+
if (!(await this._runHooks('beforeDelete', [tableName, query]))) return 0;
|
|
2080
2089
|
// P1-6: delete 不写 WAL——崩溃恢复时丢失这些操作
|
|
2081
2090
|
if (table._primaryKey) {
|
|
2082
2091
|
const toDelete = table.find(query);
|
|
@@ -2087,7 +2096,7 @@ class Database {
|
|
|
2087
2096
|
}
|
|
2088
2097
|
const count = table.remove(query);
|
|
2089
2098
|
this._emit('delete', { table: tableName, query, count });
|
|
2090
|
-
this._runHooks('afterDelete', [tableName, query, count]);
|
|
2099
|
+
await this._runHooks('afterDelete', [tableName, query, count]);
|
|
2091
2100
|
this._markDirty(tableName);
|
|
2092
2101
|
return count;
|
|
2093
2102
|
}
|
|
@@ -2110,7 +2119,7 @@ class Database {
|
|
|
2110
2119
|
}
|
|
2111
2120
|
|
|
2112
2121
|
async stop() {
|
|
2113
|
-
this._runHooks('onStop', []);
|
|
2122
|
+
await this._runHooks('onStop', []);
|
|
2114
2123
|
this._emit('stop', {});
|
|
2115
2124
|
// 内存监控定时器:stop() 此前从不清理,重复创建/销毁实例会堆积定时器
|
|
2116
2125
|
if (this._monitorTimer) { clearInterval(this._monitorTimer); this._monitorTimer = null; }
|
|
@@ -2268,7 +2277,7 @@ class Database {
|
|
|
2268
2277
|
if (this._jsqlMode) {
|
|
2269
2278
|
this._jsqlFormat._open();
|
|
2270
2279
|
for (const [name, t] of this._jsqlFormat.tables) {
|
|
2271
|
-
if (!this._tables[name]) this.
|
|
2280
|
+
if (!this._tables[name]) this._createTableSync(name, t.schema);
|
|
2272
2281
|
if (t.rowCount > 0) {
|
|
2273
2282
|
const { rows } = this._jsqlFormat.readTableSync(name);
|
|
2274
2283
|
this._tables[name]._loadRows(rows);
|
|
@@ -2291,7 +2300,7 @@ class Database {
|
|
|
2291
2300
|
if (data.__schema__) {
|
|
2292
2301
|
for (const [name, schema] of Object.entries(data.__schema__)) {
|
|
2293
2302
|
if (!this._tables[name]) {
|
|
2294
|
-
this.
|
|
2303
|
+
this._createTableSync(name, schema);
|
|
2295
2304
|
}
|
|
2296
2305
|
}
|
|
2297
2306
|
}
|
package/lib/native_client.js
CHANGED
|
@@ -401,7 +401,7 @@ class JSQL {
|
|
|
401
401
|
}, this._evictInterval);
|
|
402
402
|
if (this._evictTimer.unref) this._evictTimer.unref();
|
|
403
403
|
}
|
|
404
|
-
this._runHooks('onStart', []);
|
|
404
|
+
await this._runHooks('onStart', []);
|
|
405
405
|
this._emit('start', {});
|
|
406
406
|
}
|
|
407
407
|
|
|
@@ -554,7 +554,7 @@ class JSQL {
|
|
|
554
554
|
|
|
555
555
|
async _flush() {
|
|
556
556
|
this._flushOpsNow();
|
|
557
|
-
if (!this._runHooks('beforeFlush', [])) return null;
|
|
557
|
+
if (!(await this._runHooks('beforeFlush', []))) return null;
|
|
558
558
|
// 先把整个 buffer 原子取出再写入。
|
|
559
559
|
// 旧写法是遍历 this._buffer、await 之后才清空 —— 期间其他协程继续往同一个数组
|
|
560
560
|
// push,同一批行会被多个 flush 重复写入(并发 insert 行数暴涨/丢行)。
|
|
@@ -579,7 +579,7 @@ class JSQL {
|
|
|
579
579
|
});
|
|
580
580
|
throw e;
|
|
581
581
|
}
|
|
582
|
-
this._runHooks('afterFlush', []);
|
|
582
|
+
await this._runHooks('afterFlush', []);
|
|
583
583
|
return flushed;
|
|
584
584
|
}
|
|
585
585
|
|
|
@@ -611,7 +611,7 @@ class JSQL {
|
|
|
611
611
|
const arr = Array.isArray(data) ? data : [data];
|
|
612
612
|
arr.forEach((row, i) => assertRowObject(row, i, arr.length > 1 || Array.isArray(data)));
|
|
613
613
|
var filtered = arr;
|
|
614
|
-
if (!this._runHooks('beforeInsert', [table, filtered])) return [];
|
|
614
|
+
if (!(await this._runHooks('beforeInsert', [table, filtered]))) return [];
|
|
615
615
|
if (arr.length > 1) {
|
|
616
616
|
await this._flush();
|
|
617
617
|
let result;
|
|
@@ -622,7 +622,7 @@ class JSQL {
|
|
|
622
622
|
if (!result) result = r;
|
|
623
623
|
}
|
|
624
624
|
this._emit('insert', { table, count: arr.length, ids: result });
|
|
625
|
-
this._runHooks('afterInsert', [table, filtered, result]);
|
|
625
|
+
await this._runHooks('afterInsert', [table, filtered, result]);
|
|
626
626
|
return result;
|
|
627
627
|
}
|
|
628
628
|
if (!this._buffer[table]) this._buffer[table] = [];
|
|
@@ -631,20 +631,20 @@ class JSQL {
|
|
|
631
631
|
const flushed = await this._flush();
|
|
632
632
|
const result = flushed && flushed[table] ? flushed[table] : null;
|
|
633
633
|
this._emit('insert', { table, count: arr.length, ids: result });
|
|
634
|
-
this._runHooks('afterInsert', [table, filtered, result]);
|
|
634
|
+
await this._runHooks('afterInsert', [table, filtered, result]);
|
|
635
635
|
return result;
|
|
636
636
|
}
|
|
637
637
|
|
|
638
638
|
async createTable(name, schema) {
|
|
639
639
|
await this._flush();
|
|
640
640
|
if (typeof schema === 'string') schema = parseSchemaString(schema);
|
|
641
|
-
if (!this._runHooks('beforeCreateTable', [name, schema])) return null;
|
|
641
|
+
if (!(await this._runHooks('beforeCreateTable', [name, schema]))) return null;
|
|
642
642
|
const r = safeParse(this._n('jsqlCreateTable', name, JSON.stringify(mapNativeSchema(schema))));
|
|
643
643
|
if (r && r.ok === false) throw new Error(r.error || 'create table failed');
|
|
644
644
|
this._tableNames.add(name);
|
|
645
645
|
this._schemas[name] = typeof schema === 'string' ? mapNativeSchema(schema) : schema;
|
|
646
646
|
this._emit('createTable', { name, schema });
|
|
647
|
-
this._runHooks('afterCreateTable', [name, schema]);
|
|
647
|
+
await this._runHooks('afterCreateTable', [name, schema]);
|
|
648
648
|
return r;
|
|
649
649
|
}
|
|
650
650
|
|
|
@@ -661,30 +661,30 @@ class JSQL {
|
|
|
661
661
|
|
|
662
662
|
async dropTable(name) {
|
|
663
663
|
await this._flush();
|
|
664
|
-
if (!this._runHooks('beforeDropTable', [name])) return null;
|
|
664
|
+
if (!(await this._runHooks('beforeDropTable', [name]))) return null;
|
|
665
665
|
const r = safeParse(this._n('jsqlDropTable', name));
|
|
666
666
|
if (r && r.ok === false) throw new Error(r.error || 'drop table failed');
|
|
667
667
|
this._tableNames.delete(name);
|
|
668
668
|
delete this._schemas[name];
|
|
669
669
|
this._emit('dropTable', { name });
|
|
670
|
-
this._runHooks('afterDropTable', [name]);
|
|
670
|
+
await this._runHooks('afterDropTable', [name]);
|
|
671
671
|
return r;
|
|
672
672
|
}
|
|
673
673
|
|
|
674
|
-
findById(table, id) {
|
|
674
|
+
async findById(table, id) {
|
|
675
675
|
this._flushOpsNow();
|
|
676
|
-
if (!this._runHooks('beforeFind', [table, { id }])) return null;
|
|
676
|
+
if (!(await this._runHooks('beforeFind', [table, { id }]))) return null;
|
|
677
677
|
const raw = this._findRawById(table, id);
|
|
678
678
|
if (raw && raw.error) throw new Error(raw.error);
|
|
679
|
-
this._runHooks('afterFind', [table, { id }, raw]);
|
|
679
|
+
await this._runHooks('afterFind', [table, { id }, raw]);
|
|
680
680
|
const schema = this._schemas[table];
|
|
681
681
|
if (schema && raw && typeof raw === 'object') return restoreRow(raw, schema);
|
|
682
682
|
return raw;
|
|
683
683
|
}
|
|
684
684
|
|
|
685
|
-
findByIds(table, ids) {
|
|
685
|
+
async findByIds(table, ids) {
|
|
686
686
|
this._flushOpsNow();
|
|
687
|
-
if (!this._runHooks('beforeFind', [table, { ids }])) return null;
|
|
687
|
+
if (!(await this._runHooks('beforeFind', [table, { ids }]))) return null;
|
|
688
688
|
let r;
|
|
689
689
|
if (this._pkOf(table)) {
|
|
690
690
|
r = ids.map(id => this._findRawById(table, id)).filter(x => x !== null && !(x && x.error));
|
|
@@ -692,7 +692,7 @@ class JSQL {
|
|
|
692
692
|
r = safeParse(this._n('jsqlFindByIds', table, JSON.stringify(ids)));
|
|
693
693
|
}
|
|
694
694
|
if (r && r.error) throw new Error(r.error);
|
|
695
|
-
this._runHooks('afterFind', [table, { ids }, r]);
|
|
695
|
+
await this._runHooks('afterFind', [table, { ids }, r]);
|
|
696
696
|
const schema = this._schemas[table];
|
|
697
697
|
if (schema && Array.isArray(r)) return r.map(row => restoreRow(row, schema));
|
|
698
698
|
return r;
|
|
@@ -704,12 +704,12 @@ class JSQL {
|
|
|
704
704
|
|
|
705
705
|
async find(table, filter, opts = {}) {
|
|
706
706
|
this._flushOpsNow();
|
|
707
|
-
if (!this._runHooks('beforeFind', [table, { filter, opts }])) return [];
|
|
707
|
+
if (!(await this._runHooks('beforeFind', [table, { filter, opts }]))) return [];
|
|
708
708
|
const filterStr = filter ? JSON.stringify(filter) : '';
|
|
709
709
|
const { limit = 100, offset = 0 } = opts;
|
|
710
710
|
const r = safeParse(this._n('jsqlFind', table, filterStr, limit, offset));
|
|
711
711
|
if (r && r.error) throw new Error(r.error);
|
|
712
|
-
this._runHooks('afterFind', [table, { filter, opts }, r]);
|
|
712
|
+
await this._runHooks('afterFind', [table, { filter, opts }, r]);
|
|
713
713
|
const schema = this._schemas[table];
|
|
714
714
|
if (schema && Array.isArray(r)) return r.map(row => restoreRow(row, schema));
|
|
715
715
|
return r;
|
|
@@ -717,27 +717,27 @@ class JSQL {
|
|
|
717
717
|
|
|
718
718
|
async count(table) {
|
|
719
719
|
this._flushOpsNow();
|
|
720
|
-
this._runHooks('beforeCount', [table]);
|
|
720
|
+
await this._runHooks('beforeCount', [table]);
|
|
721
721
|
const r = parseInt(this._n('jsqlCount', table), 10);
|
|
722
722
|
const n = isNaN(r) ? 0 : r;
|
|
723
|
-
this._runHooks('afterCount', [table, n]);
|
|
723
|
+
await this._runHooks('afterCount', [table, n]);
|
|
724
724
|
return n;
|
|
725
725
|
}
|
|
726
726
|
|
|
727
|
-
updateByIds(table, entries) {
|
|
727
|
+
async updateByIds(table, entries) {
|
|
728
728
|
const pairs = [];
|
|
729
729
|
for (const [id, data] of entries) {
|
|
730
730
|
const seq = this._seqIdByPk(table, id);
|
|
731
731
|
if (seq !== null) pairs.push([seq, data]);
|
|
732
732
|
}
|
|
733
|
-
if (!this._runHooks('beforeUpdate', [table, pairs])) return;
|
|
733
|
+
if (!(await this._runHooks('beforeUpdate', [table, pairs]))) return;
|
|
734
734
|
if (!this._opBuffer.update[table]) this._opBuffer.update[table] = [];
|
|
735
735
|
this._opBuffer.update[table].push(...pairs);
|
|
736
736
|
this._scheduleOpFlush();
|
|
737
737
|
}
|
|
738
738
|
|
|
739
|
-
removeByIds(table, ids) {
|
|
740
|
-
if (!this._runHooks('beforeDelete', [table, ids])) return;
|
|
739
|
+
async removeByIds(table, ids) {
|
|
740
|
+
if (!(await this._runHooks('beforeDelete', [table, ids]))) return;
|
|
741
741
|
if (!this._opBuffer.remove[table]) this._opBuffer.remove[table] = new Set();
|
|
742
742
|
for (const id of ids) {
|
|
743
743
|
const seq = this._seqIdByPk(table, id);
|
|
@@ -746,8 +746,8 @@ class JSQL {
|
|
|
746
746
|
this._scheduleOpFlush();
|
|
747
747
|
}
|
|
748
748
|
|
|
749
|
-
updateById(table, id, data) {
|
|
750
|
-
if (!this._runHooks('beforeUpdate', [table, id, data])) return;
|
|
749
|
+
async updateById(table, id, data) {
|
|
750
|
+
if (!(await this._runHooks('beforeUpdate', [table, id, data]))) return;
|
|
751
751
|
const seq = this._seqIdByPk(table, id);
|
|
752
752
|
if (seq === null) return;
|
|
753
753
|
// 改主键 / UNIQUE 列前先查冲突(同步版,与 lib/database.js 的修复对齐)。
|
|
@@ -785,8 +785,8 @@ class JSQL {
|
|
|
785
785
|
}
|
|
786
786
|
}
|
|
787
787
|
|
|
788
|
-
removeById(table, id) {
|
|
789
|
-
if (!this._runHooks('beforeDelete', [table, id])) return;
|
|
788
|
+
async removeById(table, id) {
|
|
789
|
+
if (!(await this._runHooks('beforeDelete', [table, id]))) return;
|
|
790
790
|
const seq = this._seqIdByPk(table, id);
|
|
791
791
|
if (seq === null) return;
|
|
792
792
|
if (!this._opBuffer.remove[table]) this._opBuffer.remove[table] = new Set();
|
|
@@ -814,9 +814,9 @@ class JSQL {
|
|
|
814
814
|
* await db.query("UPDATE users SET age = age + 1 WHERE name = 'A'");
|
|
815
815
|
*/
|
|
816
816
|
async query(sql, paramsOrOpts, opts) {
|
|
817
|
-
if (!this._runHooks('beforeQuery', [sql, paramsOrOpts, opts])) return null;
|
|
817
|
+
if (!(await this._runHooks('beforeQuery', [sql, paramsOrOpts, opts]))) return null;
|
|
818
818
|
const result = await executeSQL(this, sql, paramsOrOpts, opts);
|
|
819
|
-
this._runHooks('afterQuery', [sql, paramsOrOpts, opts, result]);
|
|
819
|
+
await this._runHooks('afterQuery', [sql, paramsOrOpts, opts, result]);
|
|
820
820
|
return result;
|
|
821
821
|
}
|
|
822
822
|
|
|
@@ -847,7 +847,7 @@ class JSQL {
|
|
|
847
847
|
} catch (e) { /* ignore */ }
|
|
848
848
|
this._handle = null;
|
|
849
849
|
}
|
|
850
|
-
this._runHooks('onStop', []);
|
|
850
|
+
await this._runHooks('onStop', []);
|
|
851
851
|
this._emit('stop', {});
|
|
852
852
|
}
|
|
853
853
|
|
package/lib/plugin.js
CHANGED
|
@@ -238,7 +238,7 @@ function applyPlugin(engine, plugin, opts) {
|
|
|
238
238
|
* - 任一钩子返回 false → 中止(返回 false),引擎据此跳过本次操作;
|
|
239
239
|
* - native 引擎置 `_forbidReentry`,钩子内再次触发引擎操作会抛 ER_PLUGIN_REENTRY。
|
|
240
240
|
*/
|
|
241
|
-
|
|
241
|
+
function runHooks(engine, hookName, args) {
|
|
242
242
|
const hooks = engine._hooks && engine._hooks[hookName];
|
|
243
243
|
if (!hooks || hooks.length === 0) return true;
|
|
244
244
|
|
|
@@ -250,16 +250,18 @@ async function runHooks(engine, hookName, args) {
|
|
|
250
250
|
}
|
|
251
251
|
engine._inHook = true;
|
|
252
252
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
|
|
253
|
+
|
|
254
|
+
return (async () => {
|
|
255
|
+
try {
|
|
256
|
+
for (const fn of hooks) {
|
|
257
|
+
const result = await fn(...args);
|
|
258
|
+
if (result === false) return false;
|
|
259
|
+
}
|
|
260
|
+
return true;
|
|
261
|
+
} finally {
|
|
262
|
+
if (guard) engine._inHook = false;
|
|
258
263
|
}
|
|
259
|
-
|
|
260
|
-
} finally {
|
|
261
|
-
if (guard) engine._inHook = false;
|
|
262
|
-
}
|
|
264
|
+
})();
|
|
263
265
|
}
|
|
264
266
|
|
|
265
267
|
module.exports = {
|
package/lib/wasm_client.js
CHANGED
|
@@ -406,7 +406,7 @@ class JSQL {
|
|
|
406
406
|
|
|
407
407
|
async start() {
|
|
408
408
|
wasmBindings.jsql_reset();
|
|
409
|
-
this._runHooks('onStart', []);
|
|
409
|
+
await this._runHooks('onStart', []);
|
|
410
410
|
this._emit('start', {});
|
|
411
411
|
}
|
|
412
412
|
|
|
@@ -516,7 +516,7 @@ class JSQL {
|
|
|
516
516
|
}
|
|
517
517
|
|
|
518
518
|
async _flush() {
|
|
519
|
-
if (!this._runHooks('beforeFlush', [])) return null;
|
|
519
|
+
if (!(await this._runHooks('beforeFlush', []))) return null;
|
|
520
520
|
// 先把整个 buffer 原子取出再写入。
|
|
521
521
|
// 旧写法是遍历 this._buffer 然后在 await 之后才清空 —— 这期间其他协程会继续
|
|
522
522
|
// 往同一个数组 push,导致同一批行被多个 flush 重复写(并发 insert 行数暴涨)。
|
|
@@ -541,7 +541,7 @@ class JSQL {
|
|
|
541
541
|
});
|
|
542
542
|
throw e;
|
|
543
543
|
}
|
|
544
|
-
this._runHooks('afterFlush', []);
|
|
544
|
+
await this._runHooks('afterFlush', []);
|
|
545
545
|
return flushed;
|
|
546
546
|
}
|
|
547
547
|
|
|
@@ -559,7 +559,7 @@ class JSQL {
|
|
|
559
559
|
// 难以定位的 "Cannot convert undefined or null to object",这里直接给明确 TypeError
|
|
560
560
|
const arr = Array.isArray(data) ? data : [data];
|
|
561
561
|
arr.forEach((row, i) => assertRowObject(row, i, arr.length > 1 || Array.isArray(data)));
|
|
562
|
-
if (!this._runHooks('beforeInsert', [table, arr])) return [];
|
|
562
|
+
if (!(await this._runHooks('beforeInsert', [table, arr]))) return [];
|
|
563
563
|
if (arr.length > 1) {
|
|
564
564
|
await this._flush();
|
|
565
565
|
let result;
|
|
@@ -570,7 +570,7 @@ class JSQL {
|
|
|
570
570
|
if (!result) result = r;
|
|
571
571
|
}
|
|
572
572
|
this._emit('insert', { table, count: arr.length, ids: result });
|
|
573
|
-
this._runHooks('afterInsert', [table, arr, result]);
|
|
573
|
+
await this._runHooks('afterInsert', [table, arr, result]);
|
|
574
574
|
return result;
|
|
575
575
|
}
|
|
576
576
|
if (!this._buffer[table]) this._buffer[table] = [];
|
|
@@ -579,7 +579,7 @@ class JSQL {
|
|
|
579
579
|
const flushed = await this._flush();
|
|
580
580
|
const result = flushed && flushed[table] ? flushed[table] : null;
|
|
581
581
|
this._emit('insert', { table, count: arr.length, ids: result });
|
|
582
|
-
this._runHooks('afterInsert', [table, arr, result]);
|
|
582
|
+
await this._runHooks('afterInsert', [table, arr, result]);
|
|
583
583
|
return result;
|
|
584
584
|
}
|
|
585
585
|
|
|
@@ -590,13 +590,13 @@ class JSQL {
|
|
|
590
590
|
async createTable(name, schema) {
|
|
591
591
|
await this._flush();
|
|
592
592
|
if (typeof schema === 'string') schema = parseSchemaString(schema);
|
|
593
|
-
if (!this._runHooks('beforeCreateTable', [name, schema])) return null;
|
|
593
|
+
if (!(await this._runHooks('beforeCreateTable', [name, schema]))) return null;
|
|
594
594
|
const r = safeJsonParse(wasmBindings.jsql_create_table(name, JSON.stringify(mapNativeSchema(schema))));
|
|
595
595
|
if (r && r.ok === false) throw new Error(r.error || 'create table failed');
|
|
596
596
|
this._tableNames.add(name);
|
|
597
597
|
this._schemas[name] = typeof schema === 'string' ? mapNativeSchema(schema) : schema;
|
|
598
598
|
this._emit('createTable', { name, schema });
|
|
599
|
-
this._runHooks('afterCreateTable', [name, schema]);
|
|
599
|
+
await this._runHooks('afterCreateTable', [name, schema]);
|
|
600
600
|
return r;
|
|
601
601
|
}
|
|
602
602
|
|
|
@@ -613,22 +613,22 @@ class JSQL {
|
|
|
613
613
|
|
|
614
614
|
async dropTable(name) {
|
|
615
615
|
await this._flush();
|
|
616
|
-
if (!this._runHooks('beforeDropTable', [name])) return null;
|
|
616
|
+
if (!(await this._runHooks('beforeDropTable', [name]))) return null;
|
|
617
617
|
const r = safeJsonParse(wasmBindings.jsql_drop_table(name));
|
|
618
618
|
if (r && r.ok === false) throw new Error(r.error || 'drop table failed');
|
|
619
619
|
this._tableNames.delete(name);
|
|
620
620
|
delete this._schemas[name];
|
|
621
621
|
this._emit('dropTable', { name });
|
|
622
|
-
this._runHooks('afterDropTable', [name]);
|
|
622
|
+
await this._runHooks('afterDropTable', [name]);
|
|
623
623
|
return r;
|
|
624
624
|
}
|
|
625
625
|
|
|
626
626
|
async findById(table, id) {
|
|
627
627
|
await this._flush();
|
|
628
|
-
if (!this._runHooks('beforeFind', [table, { id }])) return null;
|
|
628
|
+
if (!(await this._runHooks('beforeFind', [table, { id }]))) return null;
|
|
629
629
|
const r = this._findRawById(table, id);
|
|
630
630
|
if (r && r.error) throw new Error(r.error);
|
|
631
|
-
this._runHooks('afterFind', [table, { id }, r]);
|
|
631
|
+
await this._runHooks('afterFind', [table, { id }, r]);
|
|
632
632
|
const schema = this._schemas[table];
|
|
633
633
|
if (schema && r && typeof r === 'object') return restoreRow(r, schema);
|
|
634
634
|
return r;
|
|
@@ -636,12 +636,12 @@ class JSQL {
|
|
|
636
636
|
|
|
637
637
|
async find(table, filter, opts = {}) {
|
|
638
638
|
await this._flush();
|
|
639
|
-
if (!this._runHooks('beforeFind', [table, { filter, opts }])) return [];
|
|
639
|
+
if (!(await this._runHooks('beforeFind', [table, { filter, opts }]))) return [];
|
|
640
640
|
const filterStr = filter ? JSON.stringify(filter) : '';
|
|
641
641
|
const { limit = 100, offset = 0 } = opts;
|
|
642
642
|
const r = safeJsonParse(wasmBindings.jsql_find(table, filterStr, limit, offset));
|
|
643
643
|
if (r && r.error) throw new Error(r.error);
|
|
644
|
-
this._runHooks('afterFind', [table, { filter, opts }, r]);
|
|
644
|
+
await this._runHooks('afterFind', [table, { filter, opts }, r]);
|
|
645
645
|
const schema = this._schemas[table];
|
|
646
646
|
if (schema && Array.isArray(r)) return r.map(row => restoreRow(row, schema));
|
|
647
647
|
return r;
|
|
@@ -649,10 +649,10 @@ class JSQL {
|
|
|
649
649
|
|
|
650
650
|
async count(table) {
|
|
651
651
|
await this._flush();
|
|
652
|
-
this._runHooks('beforeCount', [table]);
|
|
652
|
+
await this._runHooks('beforeCount', [table]);
|
|
653
653
|
const r = parseInt(wasmBindings.jsql_count(table), 10);
|
|
654
654
|
const n = isNaN(r) ? 0 : r;
|
|
655
|
-
this._runHooks('afterCount', [table, n]);
|
|
655
|
+
await this._runHooks('afterCount', [table, n]);
|
|
656
656
|
return n;
|
|
657
657
|
}
|
|
658
658
|
|
|
@@ -662,29 +662,29 @@ class JSQL {
|
|
|
662
662
|
const seq = this._seqIdByPk(table, id);
|
|
663
663
|
if (seq !== null) pairs.push([seq, data]);
|
|
664
664
|
}
|
|
665
|
-
if (!this._runHooks('beforeUpdate', [table, pairs])) return;
|
|
665
|
+
if (!(await this._runHooks('beforeUpdate', [table, pairs]))) return;
|
|
666
666
|
await this._flush();
|
|
667
667
|
const r = safeJsonParse(wasmBindings.jsql_update_by_ids(table, JSON.stringify(pairs)));
|
|
668
668
|
if (r && r.error) throw new Error(r.error);
|
|
669
669
|
this._emit('update', { table, entries: pairs, result: r });
|
|
670
|
-
this._runHooks('afterUpdate', [table, pairs, r]);
|
|
670
|
+
await this._runHooks('afterUpdate', [table, pairs, r]);
|
|
671
671
|
return r;
|
|
672
672
|
}
|
|
673
673
|
|
|
674
674
|
async removeByIds(table, ids) {
|
|
675
|
-
if (!this._runHooks('beforeDelete', [table, ids])) return;
|
|
675
|
+
if (!(await this._runHooks('beforeDelete', [table, ids]))) return;
|
|
676
676
|
await this._flush();
|
|
677
677
|
const seqs = ids.map(id => this._seqIdByPk(table, id)).filter(s => s !== null);
|
|
678
678
|
const r = safeJsonParse(wasmBindings.jsql_remove_by_ids(table, JSON.stringify(seqs)));
|
|
679
679
|
if (r && r.error) throw new Error(r.error);
|
|
680
680
|
this._emit('delete', { table, ids: seqs, result: r });
|
|
681
|
-
this._runHooks('afterDelete', [table, ids, r]);
|
|
681
|
+
await this._runHooks('afterDelete', [table, ids, r]);
|
|
682
682
|
return r;
|
|
683
683
|
}
|
|
684
684
|
|
|
685
685
|
async findByIds(table, ids) {
|
|
686
686
|
await this._flush();
|
|
687
|
-
if (!this._runHooks('beforeFind', [table, { ids }])) return null;
|
|
687
|
+
if (!(await this._runHooks('beforeFind', [table, { ids }]))) return null;
|
|
688
688
|
let r;
|
|
689
689
|
if (this._pkOf(table)) {
|
|
690
690
|
r = ids.map(id => this._findRawById(table, id)).filter(x => x !== null && !(x && x.error));
|
|
@@ -692,7 +692,7 @@ class JSQL {
|
|
|
692
692
|
r = safeJsonParse(wasmBindings.jsql_find_by_ids(table, JSON.stringify(ids)));
|
|
693
693
|
}
|
|
694
694
|
if (r && r.error) throw new Error(r.error);
|
|
695
|
-
this._runHooks('afterFind', [table, { ids }, r]);
|
|
695
|
+
await this._runHooks('afterFind', [table, { ids }, r]);
|
|
696
696
|
const schema = this._schemas[table];
|
|
697
697
|
if (schema && Array.isArray(r)) return r.map(row => restoreRow(row, schema));
|
|
698
698
|
return r;
|
|
@@ -703,7 +703,7 @@ class JSQL {
|
|
|
703
703
|
}
|
|
704
704
|
|
|
705
705
|
async updateById(table, id, data) {
|
|
706
|
-
if (!this._runHooks('beforeUpdate', [table, id, data])) return;
|
|
706
|
+
if (!(await this._runHooks('beforeUpdate', [table, id, data]))) return;
|
|
707
707
|
await this._flush();
|
|
708
708
|
const seq = this._seqIdByPk(table, id);
|
|
709
709
|
if (seq === null) return null;
|
|
@@ -716,7 +716,7 @@ class JSQL {
|
|
|
716
716
|
const r = safeJsonParse(wasmBindings.jsql_update_by_id(table, BigInt(seq), JSON.stringify(data)));
|
|
717
717
|
if (r && r.ok === false) throw new Error(r.error || 'update failed');
|
|
718
718
|
this._emit('update', { table, id, data });
|
|
719
|
-
this._runHooks('afterUpdate', [table, id, data, r]);
|
|
719
|
+
await this._runHooks('afterUpdate', [table, id, data, r]);
|
|
720
720
|
return r;
|
|
721
721
|
}
|
|
722
722
|
|
|
@@ -750,14 +750,14 @@ class JSQL {
|
|
|
750
750
|
}
|
|
751
751
|
|
|
752
752
|
async removeById(table, id) {
|
|
753
|
-
if (!this._runHooks('beforeDelete', [table, id])) return;
|
|
753
|
+
if (!(await this._runHooks('beforeDelete', [table, id]))) return;
|
|
754
754
|
await this._flush();
|
|
755
755
|
const seq = this._seqIdByPk(table, id);
|
|
756
756
|
if (seq === null) return null;
|
|
757
757
|
const r = safeJsonParse(wasmBindings.jsql_remove_by_id(table, BigInt(seq)));
|
|
758
758
|
if (r && r.ok === false) throw new Error(r.error || 'remove failed');
|
|
759
759
|
this._emit('delete', { table, id });
|
|
760
|
-
this._runHooks('afterDelete', [table, id, r]);
|
|
760
|
+
await this._runHooks('afterDelete', [table, id, r]);
|
|
761
761
|
return r;
|
|
762
762
|
}
|
|
763
763
|
|
|
@@ -818,9 +818,9 @@ class JSQL {
|
|
|
818
818
|
* const rows = await db.query("SELECT * FROM users WHERE age > ?", [21]);
|
|
819
819
|
*/
|
|
820
820
|
async query(sql, paramsOrOpts, opts) {
|
|
821
|
-
if (!this._runHooks('beforeQuery', [sql, paramsOrOpts, opts])) return null;
|
|
821
|
+
if (!(await this._runHooks('beforeQuery', [sql, paramsOrOpts, opts]))) return null;
|
|
822
822
|
const result = await executeSQL(this, sql, paramsOrOpts, opts);
|
|
823
|
-
this._runHooks('afterQuery', [sql, paramsOrOpts, opts, result]);
|
|
823
|
+
await this._runHooks('afterQuery', [sql, paramsOrOpts, opts, result]);
|
|
824
824
|
return result;
|
|
825
825
|
}
|
|
826
826
|
|
|
@@ -835,7 +835,7 @@ class JSQL {
|
|
|
835
835
|
|
|
836
836
|
async stop() {
|
|
837
837
|
await this._flush();
|
|
838
|
-
this._runHooks('onStop', []);
|
|
838
|
+
await this._runHooks('onStop', []);
|
|
839
839
|
this._emit('stop', {});
|
|
840
840
|
}
|
|
841
841
|
}
|
package/package.json
CHANGED
package/test/query-opt.test.js
CHANGED
|
@@ -32,9 +32,9 @@ function ok(name, cond, extra) {
|
|
|
32
32
|
ok('string prefix z', bt.prefix('z').length === 0);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
{
|
|
35
|
+
(async () => {
|
|
36
36
|
const db = new Database(':memory:');
|
|
37
|
-
db.createTable('users', {
|
|
37
|
+
await db.createTable('users', {
|
|
38
38
|
id: { type: 'integer', primaryKey: true, autoIncrement: true },
|
|
39
39
|
name: { type: 'string', unique: true },
|
|
40
40
|
age: { type: 'integer' }
|
|
@@ -63,11 +63,11 @@ function ok(name, cond, extra) {
|
|
|
63
63
|
|
|
64
64
|
const one = db.users.findOne({ name: 'bob' });
|
|
65
65
|
ok('findOne no full clone', one && one.name === 'bob' && one.age === 40);
|
|
66
|
-
}
|
|
66
|
+
})();
|
|
67
67
|
|
|
68
68
|
(async () => {
|
|
69
69
|
const db = new Database(':memory:');
|
|
70
|
-
db.createTable('users', {
|
|
70
|
+
await db.createTable('users', {
|
|
71
71
|
id: { type: 'integer', primaryKey: true, autoIncrement: true },
|
|
72
72
|
name: { type: 'string' },
|
|
73
73
|
age: { type: 'integer' }
|
|
@@ -91,18 +91,18 @@ function ok(name, cond, extra) {
|
|
|
91
91
|
{
|
|
92
92
|
const pdb = new Database(':memory:');
|
|
93
93
|
pdb.use('timestamps', { createdField: 'created_at', updatedField: 'updated_at' });
|
|
94
|
-
pdb.createTable('notes', { id: { type: 'integer', primaryKey: true, autoIncrement: true }, title: { type: 'string' } });
|
|
94
|
+
await pdb.createTable('notes', { id: { type: 'integer', primaryKey: true, autoIncrement: true }, title: { type: 'string' } });
|
|
95
95
|
const schema = pdb.getTableSchema('notes');
|
|
96
96
|
ok('use opts timestamps fields', !!(schema && schema.created_at && schema.updated_at), schema);
|
|
97
|
-
pdb.insert('notes', { title: 'hello' });
|
|
97
|
+
await pdb.insert('notes', { title: 'hello' });
|
|
98
98
|
const row = pdb.notes.findOne({ title: 'hello' });
|
|
99
99
|
ok('timestamps stamped', !!(row && row.created_at && row.updated_at), row);
|
|
100
100
|
|
|
101
101
|
let afterInsertHits = 0;
|
|
102
102
|
pdb.on('afterInsert', () => { afterInsertHits++; });
|
|
103
|
-
pdb.insert('notes', { title: 'one' });
|
|
103
|
+
await pdb.insert('notes', { title: 'one' });
|
|
104
104
|
ok('single-row afterInsert', afterInsertHits === 1, afterInsertHits);
|
|
105
|
-
pdb.insert('notes', [{ title: 'a' }, { title: 'b' }]);
|
|
105
|
+
await pdb.insert('notes', [{ title: 'a' }, { title: 'b' }]);
|
|
106
106
|
ok('batch afterInsert', afterInsertHits === 2, afterInsertHits);
|
|
107
107
|
}
|
|
108
108
|
|