@based/db 0.0.10 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/lib/darwin_aarch64/include/selva/fields.h +8 -13
  2. package/dist/lib/darwin_aarch64/libnode-v20.11.1.node +0 -0
  3. package/dist/lib/darwin_aarch64/libnode-v20.18.1.node +0 -0
  4. package/dist/lib/darwin_aarch64/libnode-v22.13.0.node +0 -0
  5. package/dist/lib/darwin_aarch64/libnode-v22.8.0.node +0 -0
  6. package/dist/lib/darwin_aarch64/libselva.dylib +0 -0
  7. package/dist/lib/darwin_aarch64/libxxhash.0.8.2.dylib +0 -0
  8. package/dist/lib/linux_aarch64/include/selva/fields.h +8 -13
  9. package/dist/lib/linux_aarch64/libnode-v20.11.1.node +0 -0
  10. package/dist/lib/linux_aarch64/libnode-v20.18.1.node +0 -0
  11. package/dist/lib/linux_aarch64/libnode-v22.13.0.node +0 -0
  12. package/dist/lib/linux_aarch64/libselva.so +0 -0
  13. package/dist/lib/linux_x86_64/include/selva/fields.h +8 -13
  14. package/dist/lib/linux_x86_64/libnode-v20.11.1.node +0 -0
  15. package/dist/lib/linux_x86_64/libnode-v20.18.1.node +0 -0
  16. package/dist/lib/linux_x86_64/libnode-v22.13.0.node +0 -0
  17. package/dist/lib/linux_x86_64/libselva.so +0 -0
  18. package/dist/src/client/index.d.ts +1 -1
  19. package/dist/src/client/index.js +3 -0
  20. package/dist/src/client/modify/cardinality.d.ts +1 -1
  21. package/dist/src/client/modify/cardinality.js +22 -30
  22. package/dist/src/client/query/BasedDbQuery.d.ts +2 -2
  23. package/dist/src/client/query/BasedDbQuery.js +18 -29
  24. package/dist/src/client/query/filter/filter.js +0 -4
  25. package/dist/src/client/query/include/walk.js +7 -3
  26. package/dist/src/client/query/queryDef.js +12 -7
  27. package/dist/src/client/query/registerQuery.js +2 -17
  28. package/dist/src/client/query/subscription/index.js +9 -3
  29. package/dist/src/client/query/thresholds.d.ts +3 -2
  30. package/dist/src/client/query/thresholds.js +3 -2
  31. package/dist/src/client/query/toBuffer.js +9 -0
  32. package/dist/src/client/query/types.d.ts +3 -1
  33. package/dist/src/client/query/types.js +3 -0
  34. package/dist/src/client/query/validation.d.ts +29 -16
  35. package/dist/src/client/query/validation.js +169 -59
  36. package/dist/src/server/csmt/tree.js +0 -1
  37. package/dist/src/server/index.d.ts +3 -1
  38. package/dist/src/server/index.js +3 -1
  39. package/dist/src/server/save.d.ts +1 -1
  40. package/dist/src/server/save.js +8 -2
  41. package/dist/src/server/start.js +7 -0
  42. package/package.json +2 -1
  43. package/dist/lib/darwin_aarch64/libxxhash.0.dylib +0 -0
  44. package/dist/lib/darwin_aarch64/libxxhash.dylib +0 -0
  45. package/dist/lib/linux_aarch64/libxxhash.so +0 -0
  46. package/dist/lib/linux_aarch64/libxxhash.so.0 +0 -0
  47. package/dist/lib/linux_x86_64/libxxhash.so +0 -0
  48. package/dist/lib/linux_x86_64/libxxhash.so.0 +0 -0
@@ -119,17 +119,6 @@ int selva_fields_set(
119
119
  const struct SelvaFieldSchema *fs,
120
120
  const void *value, size_t len);
121
121
 
122
- /**
123
- * Set field value with CRC.
124
- */
125
- SELVA_EXPORT
126
- int selva_fields_set_wcrc(
127
- struct SelvaDb *db,
128
- struct SelvaNode *node,
129
- const struct SelvaFieldSchema *fs,
130
- const void *value, size_t len,
131
- uint32_t crc);
132
-
133
122
  SELVA_EXPORT
134
123
  int selva_fields_get_mutable_string(
135
124
  struct SelvaNode *node,
@@ -160,6 +149,7 @@ int selva_fields_reference_set(
160
149
 
161
150
  /**
162
151
  * @param index 0 = first; -1 = last.
152
+ * @param reorder move the existing ref to `index` instead of returning EEXIST.
163
153
  */
164
154
  SELVA_EXPORT
165
155
  int selva_fields_references_insert(
@@ -243,7 +233,12 @@ int selva_fields_get_reference_meta_mutable_string(
243
233
  * +------+------+--------+-----+
244
234
  */
245
235
  SELVA_EXPORT
246
- int selva_fields_set_string(struct SelvaNode *node, const struct SelvaFieldSchema *fs, struct SelvaFieldInfo *nfo, const char *str, size_t len);
236
+ int selva_fields_set_string(
237
+ struct SelvaNode *node,
238
+ const struct SelvaFieldSchema *fs,
239
+ struct SelvaFieldInfo *nfo,
240
+ const char *str,
241
+ size_t len);
247
242
 
248
243
  /**
249
244
  * Set text field translation.
@@ -326,7 +321,7 @@ SELVA_EXPORT
326
321
  void selva_fields_clear_references(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs);
327
322
 
328
323
  /**
329
- * Init fields of a node.
324
+ * Init the fields struct of a node or edge.
330
325
  */
331
326
  SELVA_EXPORT
332
327
  void selva_fields_init(const struct SelvaFieldsSchema *schema, struct SelvaFields *fields);
@@ -119,17 +119,6 @@ int selva_fields_set(
119
119
  const struct SelvaFieldSchema *fs,
120
120
  const void *value, size_t len);
121
121
 
122
- /**
123
- * Set field value with CRC.
124
- */
125
- SELVA_EXPORT
126
- int selva_fields_set_wcrc(
127
- struct SelvaDb *db,
128
- struct SelvaNode *node,
129
- const struct SelvaFieldSchema *fs,
130
- const void *value, size_t len,
131
- uint32_t crc);
132
-
133
122
  SELVA_EXPORT
134
123
  int selva_fields_get_mutable_string(
135
124
  struct SelvaNode *node,
@@ -160,6 +149,7 @@ int selva_fields_reference_set(
160
149
 
161
150
  /**
162
151
  * @param index 0 = first; -1 = last.
152
+ * @param reorder move the existing ref to `index` instead of returning EEXIST.
163
153
  */
164
154
  SELVA_EXPORT
165
155
  int selva_fields_references_insert(
@@ -243,7 +233,12 @@ int selva_fields_get_reference_meta_mutable_string(
243
233
  * +------+------+--------+-----+
244
234
  */
245
235
  SELVA_EXPORT
246
- int selva_fields_set_string(struct SelvaNode *node, const struct SelvaFieldSchema *fs, struct SelvaFieldInfo *nfo, const char *str, size_t len);
236
+ int selva_fields_set_string(
237
+ struct SelvaNode *node,
238
+ const struct SelvaFieldSchema *fs,
239
+ struct SelvaFieldInfo *nfo,
240
+ const char *str,
241
+ size_t len);
247
242
 
248
243
  /**
249
244
  * Set text field translation.
@@ -326,7 +321,7 @@ SELVA_EXPORT
326
321
  void selva_fields_clear_references(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs);
327
322
 
328
323
  /**
329
- * Init fields of a node.
324
+ * Init the fields struct of a node or edge.
330
325
  */
331
326
  SELVA_EXPORT
332
327
  void selva_fields_init(const struct SelvaFieldsSchema *schema, struct SelvaFields *fields);
Binary file
@@ -119,17 +119,6 @@ int selva_fields_set(
119
119
  const struct SelvaFieldSchema *fs,
120
120
  const void *value, size_t len);
121
121
 
122
- /**
123
- * Set field value with CRC.
124
- */
125
- SELVA_EXPORT
126
- int selva_fields_set_wcrc(
127
- struct SelvaDb *db,
128
- struct SelvaNode *node,
129
- const struct SelvaFieldSchema *fs,
130
- const void *value, size_t len,
131
- uint32_t crc);
132
-
133
122
  SELVA_EXPORT
134
123
  int selva_fields_get_mutable_string(
135
124
  struct SelvaNode *node,
@@ -160,6 +149,7 @@ int selva_fields_reference_set(
160
149
 
161
150
  /**
162
151
  * @param index 0 = first; -1 = last.
152
+ * @param reorder move the existing ref to `index` instead of returning EEXIST.
163
153
  */
164
154
  SELVA_EXPORT
165
155
  int selva_fields_references_insert(
@@ -243,7 +233,12 @@ int selva_fields_get_reference_meta_mutable_string(
243
233
  * +------+------+--------+-----+
244
234
  */
245
235
  SELVA_EXPORT
246
- int selva_fields_set_string(struct SelvaNode *node, const struct SelvaFieldSchema *fs, struct SelvaFieldInfo *nfo, const char *str, size_t len);
236
+ int selva_fields_set_string(
237
+ struct SelvaNode *node,
238
+ const struct SelvaFieldSchema *fs,
239
+ struct SelvaFieldInfo *nfo,
240
+ const char *str,
241
+ size_t len);
247
242
 
248
243
  /**
249
244
  * Set text field translation.
@@ -326,7 +321,7 @@ SELVA_EXPORT
326
321
  void selva_fields_clear_references(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs);
327
322
 
328
323
  /**
329
- * Init fields of a node.
324
+ * Init the fields struct of a node or edge.
330
325
  */
331
326
  SELVA_EXPORT
332
327
  void selva_fields_init(const struct SelvaFieldsSchema *schema, struct SelvaFields *fields);
Binary file
@@ -47,7 +47,7 @@ export declare class DbClient {
47
47
  };
48
48
  create(type: string, obj?: CreateObj, opts?: ModifyOpts): ModifyRes;
49
49
  copy(type: string, target: number | ModifyRes, objOrTransformFn?: Record<string, any> | ((item: Record<string, any>) => Promise<any>)): Promise<ModifyRes>;
50
- query(type: string, id?: number | ModifyRes | (number | ModifyRes)[] | QueryByAliasObj | QueryByAliasObj[]): BasedDbQuery;
50
+ query(type: string, id?: number | ModifyRes | (number | ModifyRes)[] | QueryByAliasObj | QueryByAliasObj[] | Uint32Array): BasedDbQuery;
51
51
  query(): BasedDbQuery;
52
52
  update(type: string, id: number | ModifyRes, value: any, opts?: ModifyOpts): ModifyRes;
53
53
  update(type: string, value: Record<string, any> & {
@@ -114,6 +114,9 @@ export class DbClient {
114
114
  }
115
115
  }
116
116
  }
117
+ else if (id instanceof Uint32Array) {
118
+ // all good
119
+ }
117
120
  else if (typeof id === 'object') {
118
121
  if (id instanceof ModifyState) {
119
122
  id = id.tmpId;
@@ -1,4 +1,4 @@
1
1
  import { ModifyCtx } from '../../index.js';
2
2
  import { SchemaTypeDef, PropDef } from '../../server/schema/types.js';
3
3
  import { ModifyOp, ModifyErr } from './types.js';
4
- export declare function writeHll(value: string | null | Buffer, ctx: ModifyCtx, def: SchemaTypeDef, t: PropDef, parentId: number, modifyOp: ModifyOp): ModifyErr;
4
+ export declare function writeHll(value: string | null | Buffer | Array<string | Buffer>, ctx: ModifyCtx, def: SchemaTypeDef, t: PropDef, parentId: number, modifyOp: ModifyOp): ModifyErr;
@@ -7,44 +7,36 @@ export function writeHll(value, ctx, def, t, parentId, modifyOp) {
7
7
  return new ModifyError(t, value);
8
8
  }
9
9
  if (value === null) {
10
- // console.log('modify/cardinality.ts trying to reset?')
11
- // if (modifyOp === UPDATE) {
12
- // if (ctx.len + 11 > ctx.max) {
13
- // return RANGE_ERR
14
- // }
15
- // setCursor(ctx, def, t.prop, parentId, modifyOp)
16
- // ctx.buf[ctx.len++] = DELETE
17
- // }
10
+ // Future hll_reset frunction
11
+ return;
18
12
  }
19
- else if (Array.isArray(value)) {
20
- // console.log('modify/cardinality.ts Array.isArray(value)')
21
- // for (const key in value) {
22
- // if (key === 'add') {
23
- // // @ts-ignore
24
- // const err = addHll(value[key], ctx, def, t, parentId, modifyOp, 1)
25
- // if (err) {
26
- // return err
27
- // }
28
- // } else {
29
- // return new ModifyError(t, value)
30
- // }
31
- // }
32
- }
33
- else {
34
- return addHll(value, ctx, def, t, parentId, modifyOp);
13
+ else if (!Array.isArray(value)) {
14
+ value = [value];
35
15
  }
16
+ const err = addHll(value, ctx, def, t, parentId, modifyOp);
36
17
  }
37
18
  function addHll(value, ctx, def, t, parentId, modifyOp) {
38
- let size = 8;
19
+ const len = value.length;
20
+ let size = 2 + len * 8;
39
21
  if (ctx.len + size + 11 > ctx.max) {
40
22
  return RANGE_ERR;
41
23
  }
42
- // console.log(`test JS original value = ${value}`)
43
24
  setCursor(ctx, def, t.prop, t.typeIndex, parentId, modifyOp);
44
25
  ctx.buf[ctx.len++] = modifyOp;
45
- let hash = xxHash64(Buffer.from(value)); //1ec6c662633f0026 or 2217677992400715814
46
- ctx.buf.writeBigUInt64LE(hash, ctx.len);
47
- // console.log('js hash:', hash)
48
- ctx.len += 8;
26
+ ctx.buf.writeUint16LE(len, ctx.len);
27
+ ctx.len += 2;
28
+ for (let val of value) {
29
+ let b;
30
+ if (typeof val === 'string') {
31
+ b = Buffer.from(val);
32
+ }
33
+ else if (!(val instanceof Buffer)) {
34
+ b = val;
35
+ return new ModifyError(t, val);
36
+ }
37
+ const hash = xxHash64(b);
38
+ ctx.buf.writeBigUInt64LE(hash, ctx.len);
39
+ ctx.len += 8;
40
+ }
49
41
  }
50
42
  //# sourceMappingURL=cardinality.js.map
@@ -31,11 +31,11 @@ declare class GetPromise extends Promise<BasedQueryResponse> {
31
31
  }
32
32
  export declare class BasedDbQuery extends QueryBranch<BasedDbQuery> {
33
33
  #private;
34
- constructor(db: DbClient, type: string, id?: QueryByAliasObj | number | (QueryByAliasObj | number)[]);
34
+ constructor(db: DbClient, type: string, id?: QueryByAliasObj | number | Uint32Array | (QueryByAliasObj | number)[]);
35
35
  id: number;
36
36
  get(): GetPromise;
37
37
  buffer: Buffer;
38
- register(): Buffer;
38
+ register(): void;
39
39
  i18n(locale: LangName): this;
40
40
  subscribe(onData: OnData, onError?: OnError): import("./subscription/types.js").OnClose;
41
41
  _getSync(dbCtxExternal: any): BasedQueryResponse;
@@ -1,9 +1,8 @@
1
- import { createQueryDef, QueryDefType, includeFields, filter, sort, defToBuffer, filterOr, convertFilter, isAlias, includeField, } from './query.js';
1
+ import { createQueryDef, QueryDefType, filter, sort, defToBuffer, filterOr, convertFilter, isAlias, includeField, includeFields, } from './query.js';
2
2
  import { BasedQueryResponse } from './BasedIterable.js';
3
3
  import { createOrGetEdgeRefQueryDef, createOrGetRefQueryDef, } from './include/utils.js';
4
4
  import { FilterBranch } from './filter/FilterBranch.js';
5
5
  import { search, vectorSearch } from './search/index.js';
6
- import { isValidId, checkMaxIdsPerQuery, checkTotalBufferSize, hasField, isValidAlias, } from './validation.js';
7
6
  import native from '../../native.js';
8
7
  import { REFERENCE, REFERENCES } from '../../server/schema/types.js';
9
8
  import { subscribe } from './subscription/index.js';
@@ -140,10 +139,7 @@ export class QueryBranch {
140
139
  });
141
140
  }
142
141
  else if (Array.isArray(f)) {
143
- for (const field of f) {
144
- hasField(field);
145
- includeField(this.def, field);
146
- }
142
+ includeFields(this.def, f);
147
143
  }
148
144
  else if (f !== undefined) {
149
145
  throw new Error('Invalid include statement: expected props, refs and edges (string or array) or function');
@@ -178,39 +174,33 @@ export class BasedDbQuery extends QueryBranch {
178
174
  target.alias = id;
179
175
  }
180
176
  else {
181
- if (Array.isArray(id)) {
182
- checkMaxIdsPerQuery(id);
183
- // const ids = id.filter((id) => typeof id === 'number')
184
- // if (ids.length < id.length) {
185
- // throw new Error(
186
- // 'Seems that aliases are part of ids in qeury not supported yet...',
187
- // )
188
- // }
177
+ if (Array.isArray(id) || id instanceof Uint32Array) {
189
178
  // TODO ADD MULTI ALIAS
190
179
  // @ts-ignore
191
- target.ids = new Uint32Array(id);
192
- for (const id of target.ids) {
193
- isValidId(id);
194
- }
195
- target.ids.sort();
180
+ target.ids = id;
181
+ // target.ids = new Uint32Array(id)
182
+ // target.ids.sort()
196
183
  }
197
184
  else {
198
- isValidId(id);
199
185
  target.id = id;
200
186
  }
201
187
  }
202
188
  }
203
189
  const def = createQueryDef(db, QueryDefType.Root, target);
204
- if (isAlias(id)) {
205
- isValidAlias(def, id);
206
- }
207
190
  super(db, def);
208
191
  }
209
192
  #getInternal = async (resolve, reject) => {
210
193
  if (!this.def.include.stringFields.size && !this.def.references.size) {
211
- includeFields(this.def, ['*']);
194
+ includeField(this.def, '*');
195
+ }
196
+ let buf;
197
+ try {
198
+ buf = registerQuery(this);
199
+ }
200
+ catch (err) {
201
+ reject(err);
202
+ return;
212
203
  }
213
- const buf = registerQuery(this);
214
204
  const d = performance.now();
215
205
  const res = await this.db.hooks.getQueryBuf(buf);
216
206
  if (res instanceof Error) {
@@ -227,7 +217,7 @@ export class BasedDbQuery extends QueryBranch {
227
217
  }
228
218
  buffer;
229
219
  register() {
230
- return registerQuery(this);
220
+ registerQuery(this);
231
221
  }
232
222
  i18n(locale) {
233
223
  this.def.lang = langCodesMap.get(locale) ?? 0;
@@ -241,7 +231,7 @@ export class BasedDbQuery extends QueryBranch {
241
231
  }
242
232
  _getSync(dbCtxExternal) {
243
233
  if (!this.def.include.stringFields.size && !this.def.references.size) {
244
- includeFields(this.def, ['*']);
234
+ includeField(this.def, '*');
245
235
  }
246
236
  const buf = registerQuery(this);
247
237
  const d = performance.now();
@@ -250,10 +240,9 @@ export class BasedDbQuery extends QueryBranch {
250
240
  }
251
241
  toBuffer() {
252
242
  if (!this.def.include.stringFields.size && !this.def.references.size) {
253
- includeFields(this.def, ['*']);
243
+ includeField(this.def, '*');
254
244
  }
255
245
  const b = defToBuffer(this.db, this.def);
256
- checkTotalBufferSize(b);
257
246
  return Buffer.concat(b);
258
247
  }
259
248
  }
@@ -2,7 +2,6 @@ import { isPropDef, ID_FIELD_DEF, TEXT, } from '../../../server/schema/schema.js
2
2
  import { primitiveFilter } from './primitiveFilter.js';
3
3
  import { toFilterCtx } from './types.js';
4
4
  import { IsFilter } from './types.js';
5
- import { hasField, checkOperator, checkValue } from '../validation.js';
6
5
  import { langCodesMap } from '@based/schema';
7
6
  const referencesFilter = (db, filter, schema, conditions, def) => {
8
7
  const [fieldStr, ctx, value] = filter;
@@ -111,9 +110,6 @@ export const convertFilter = (field, operator, value, opts) => {
111
110
  value = operator;
112
111
  operator = '=';
113
112
  }
114
- hasField(field);
115
- checkOperator(operator);
116
- checkValue(value, operator);
117
113
  if (operator === '!..') {
118
114
  return [
119
115
  [field, toFilterCtx('>', opts), value[1]],
@@ -2,8 +2,9 @@ import { isPropDef, REFERENCE, REFERENCES, TEXT, } from '../../../server/schema/
2
2
  import { createQueryDef } from '../queryDef.js';
3
3
  import { isRefDef, QueryDefType } from '../types.js';
4
4
  import { getAllFieldFromObject, createOrGetRefQueryDef } from './utils.js';
5
- import { includeFields, includeProp, includeAllProps } from './props.js';
5
+ import { includeProp, includeAllProps, includeField } from './props.js';
6
6
  import { langCodesMap } from '@based/schema';
7
+ import { includeDoesNotExist } from '../validation.js';
7
8
  export const walkDefs = (db, def, f) => {
8
9
  const prop = def.props[f];
9
10
  const path = f.split('.');
@@ -28,7 +29,7 @@ export const walkDefs = (db, def, f) => {
28
29
  else {
29
30
  const f = path.slice(i + 1).join('.');
30
31
  if (!includeProp(refDef, refDef.props[f])) {
31
- includeFields(refDef, [f]);
32
+ includeField(refDef, f);
32
33
  }
33
34
  return;
34
35
  }
@@ -40,6 +41,9 @@ export const walkDefs = (db, def, f) => {
40
41
  }
41
42
  t = t[p];
42
43
  if (!t) {
44
+ if (f != 'id') {
45
+ includeDoesNotExist(def, f);
46
+ }
43
47
  return;
44
48
  }
45
49
  if (isPropDef(t) && t.typeIndex === TEXT) {
@@ -55,7 +59,7 @@ export const walkDefs = (db, def, f) => {
55
59
  const refDef = createOrGetRefQueryDef(db, def, t);
56
60
  const f = path.slice(i + 1).join('.');
57
61
  if (!includeProp(refDef, refDef.props[f])) {
58
- includeFields(refDef, [f]);
62
+ includeField(refDef, f);
59
63
  }
60
64
  return;
61
65
  }
@@ -1,8 +1,10 @@
1
1
  import { langCodesMap } from '@based/schema';
2
- import { MAX_RANGE_PROP_LIMIT, MAX_RANGE_REF_LIMIT } from './thresholds.js';
2
+ import { DEF_RANGE_PROP_LIMIT, DEF_RANGE_REF_LIMIT } from './thresholds.js';
3
3
  import { QueryDefType, } from './types.js';
4
+ import { validateId, validateIds, validateType } from './validation.js';
4
5
  const createEmptySharedDef = () => {
5
6
  const q = {
7
+ errors: [],
6
8
  filter: { conditions: new Map(), size: 0 },
7
9
  range: { offset: 0, limit: 0 },
8
10
  lang: langCodesMap.get('none'),
@@ -35,21 +37,24 @@ export const createQueryDef = (db, type, target) => {
35
37
  else {
36
38
  const t = target;
37
39
  const q = queryDef;
38
- q.schema = db.schemaTypesParsed[t.type];
40
+ q.schema = validateType(db, q, t.type);
39
41
  q.props = q.schema.props;
40
42
  q.type = type;
41
43
  q.target = t;
42
44
  if (type === QueryDefType.Root) {
43
- // IDS sort
44
- if (t.ids) {
45
- q.range.limit = t.ids.length; // 1k?
45
+ if (t.id) {
46
+ t.id = validateId(q, t.id);
47
+ }
48
+ else if (t.ids) {
49
+ t.ids = validateIds(q, t.ids);
50
+ q.range.limit = t.ids.length;
46
51
  }
47
52
  else {
48
- q.range.limit = MAX_RANGE_PROP_LIMIT;
53
+ q.range.limit = DEF_RANGE_PROP_LIMIT;
49
54
  }
50
55
  }
51
56
  else if (type === QueryDefType.References) {
52
- q.range.limit = MAX_RANGE_REF_LIMIT;
57
+ q.range.limit = DEF_RANGE_REF_LIMIT;
53
58
  }
54
59
  return q;
55
60
  }
@@ -1,29 +1,14 @@
1
1
  import native from '../../native.js';
2
2
  import { defToBuffer } from './toBuffer.js';
3
- import { checkMaxBufferSize } from './validation.js';
3
+ import { handleErrors } from './validation.js';
4
4
  export const registerQuery = (q) => {
5
- // just add crc32 in the buffer
6
5
  if (!q.id) {
7
6
  const b = defToBuffer(q.db, q.def);
8
7
  const buf = Buffer.concat(b);
9
8
  let id = native.crc32(buf);
10
9
  q.id = id;
11
- // id = (id ^ q.def.schema.id) >>> 0
12
- // typeId, crc32, len
13
- // but want it to fit in a js number...
14
- // use 2 bytes for len and just continue counting
15
- // const x = Buffer.allocUnsafe(8)
16
- // // const number
17
- // x.writeUint16LE(q.def.schema.id, 0)
18
- // x.writeUint32LE(id, 2)
19
- // x.writeUint16LE(buf.byteLength, 6)
20
- // // ------------------------
21
- // console.log('-> CRC32', { id, x: new Uint8Array(x), y: x.readFloatLE(0) })
22
- // do a test for
23
- // console.log(id)
24
- // id, len, type as id?
25
10
  q.buffer = buf;
26
- checkMaxBufferSize(buf);
11
+ handleErrors(q.def);
27
12
  return buf;
28
13
  }
29
14
  return q.buffer;
@@ -1,4 +1,4 @@
1
- import { includeFields } from '../query.js';
1
+ import { includeField } from '../query.js';
2
2
  import { registerQuery } from '../registerQuery.js';
3
3
  import { runSubscription } from './run.js';
4
4
  import { addSubscriptionMarkers, deleteSubscriptionMarkers } from './markers.js';
@@ -7,9 +7,15 @@ export * from './markers.js';
7
7
  export const subscribe = (q, onData, onError) => {
8
8
  let closed = false;
9
9
  if (!q.def.include.stringFields.size && !q.def.references.size) {
10
- includeFields(q.def, ['*']);
10
+ includeField(q.def, '*');
11
+ }
12
+ try {
13
+ registerQuery(q);
14
+ }
15
+ catch (err) {
16
+ onError(err);
17
+ return () => q;
11
18
  }
12
- registerQuery(q);
13
19
  if (!q.db.subscriptions.has(q.id)) {
14
20
  const subscription = {
15
21
  query: q,
@@ -1,6 +1,7 @@
1
1
  export declare const MAX_IDS_PER_QUERY = 1000000;
2
2
  export declare const MAX_BUFFER_SIZE: number;
3
- export declare const MAX_RANGE_PROP_LIMIT = 1000;
4
- export declare const MAX_RANGE_REF_LIMIT = 10000;
3
+ export declare const DEF_RANGE_PROP_LIMIT = 1000;
4
+ export declare const DEF_RANGE_REF_LIMIT = 10000;
5
+ export declare const MAX_ID = 4294967295;
5
6
  export declare const MIN_ID_VALUE = 1;
6
7
  export declare const MAX_ID_VALUE: number;
@@ -1,8 +1,9 @@
1
1
  // Query thresholds
2
2
  export const MAX_IDS_PER_QUERY = 1e6; // Max number of IDs that can be queried at once
3
3
  export const MAX_BUFFER_SIZE = 5 * 1024 * 1024; // 5MB (max buffer size)
4
- export const MAX_RANGE_PROP_LIMIT = 1e3;
5
- export const MAX_RANGE_REF_LIMIT = 1e4;
4
+ export const DEF_RANGE_PROP_LIMIT = 1e3;
5
+ export const DEF_RANGE_REF_LIMIT = 1e4;
6
+ export const MAX_ID = 4294967295;
6
7
  // Data validation thresholds
7
8
  export const MIN_ID_VALUE = 1; // Minimum allowed value for an ID (id array stared)
8
9
  export const MAX_ID_VALUE = 2 ** 32 - 1; /// Maximum allowed value for an ID (Uint32)
@@ -28,10 +28,16 @@ const getAliasPropdef = (alias, path, def) => {
28
28
  }
29
29
  };
30
30
  export function defToBuffer(db, def) {
31
+ // if (def.errors.length) {
32
+ // return []
33
+ // }
31
34
  const result = [];
32
35
  const include = includeToBuffer(db, def);
33
36
  def.references.forEach((ref) => {
34
37
  include.push(...defToBuffer(db, ref));
38
+ if (ref.errors) {
39
+ def.errors.push(...ref.errors);
40
+ }
35
41
  });
36
42
  let edges;
37
43
  let edgesSize = 0;
@@ -39,6 +45,9 @@ export function defToBuffer(db, def) {
39
45
  edges = includeToBuffer(db, def.edges);
40
46
  def.edges.references.forEach((ref) => {
41
47
  edges.push(...defToBuffer(db, ref));
48
+ if (ref.errors) {
49
+ def.errors.push(...ref.errors);
50
+ }
42
51
  });
43
52
  edgesSize = byteSize(edges);
44
53
  }
@@ -1,6 +1,7 @@
1
1
  import { LangCode } from '@based/schema';
2
2
  import { PropDef, PropDefEdge, SchemaTypeDef } from '../../server/schema/schema.js';
3
3
  import { FilterOpts } from './filter/types.js';
4
+ import { QueryError } from './validation.js';
4
5
  export type MainIncludes = {
5
6
  [start: string]: [number, PropDef];
6
7
  };
@@ -54,6 +55,7 @@ export type QueryDefSort = {
54
55
  order: 0 | 1;
55
56
  };
56
57
  export type QueryDefShared = {
58
+ errors: QueryError[];
57
59
  lang: LangCode;
58
60
  filter: QueryDefFilter;
59
61
  search: null | QueryDefSearch;
@@ -97,4 +99,4 @@ export { QueryDefType };
97
99
  export type QueryByAliasObj = {
98
100
  [key: string]: string | QueryByAliasObj;
99
101
  };
100
- export declare const isAlias: (id: QueryByAliasObj | number | (QueryByAliasObj | number)[]) => id is QueryByAliasObj;
102
+ export declare const isAlias: (id: QueryByAliasObj | number | Uint32Array | (QueryByAliasObj | number)[]) => id is QueryByAliasObj;
@@ -10,6 +10,9 @@ export const isRefDef = (def) => {
10
10
  };
11
11
  export { QueryDefType };
12
12
  export const isAlias = (id) => {
13
+ if (id instanceof Uint32Array) {
14
+ return false;
15
+ }
13
16
  return typeof id === 'object' && id !== null && !Array.isArray(id);
14
17
  };
15
18
  //# sourceMappingURL=types.js.map
@@ -1,16 +1,29 @@
1
- import { PropDef, PropDefEdge } from '../../server/schema/types.js';
2
- import { Operator } from './filter/types.js';
3
- import { QueryByAliasObj, QueryDef } from './types.js';
4
- export declare const isValidId: (id: number) => void;
5
- export declare const checkMaxIdsPerQuery: (ids: (number | QueryByAliasObj)[]) => void;
6
- export declare const checkMaxBufferSize: (buf: Buffer) => void;
7
- export declare const checkTotalBufferSize: (bufers: Buffer[]) => void;
8
- export declare const hasFields: (fields: {
9
- [key: string]: PropDefEdge;
10
- } | {
11
- [path: string]: PropDef;
12
- }) => void;
13
- export declare const isValidAlias: (def: QueryDef, id: QueryByAliasObj) => void;
14
- export declare const hasField: (field: string) => void;
15
- export declare const checkOperator: (operator: Operator | boolean) => void;
16
- export declare const checkValue: (value: any, operator: Operator) => void;
1
+ import { SchemaTypeDef } from '../../server/schema/types.js';
2
+ import { DbClient } from '../index.js';
3
+ import { QueryDef } from './types.js';
4
+ export type QueryError = {
5
+ code: number;
6
+ payload: any;
7
+ };
8
+ export declare const ERR_TARGET_INVAL_TYPE = 1;
9
+ export declare const ERR_TARGET_INVAL_ALIAS = 2;
10
+ export declare const ERR_TARGET_EXCEED_MAX_IDS = 3;
11
+ export declare const ERR_TARGET_INVAL_IDS = 4;
12
+ export declare const ERR_TARGET_INVAL_ID = 5;
13
+ export declare const ERR_INCLUDE_ENOENT = 6;
14
+ declare const messages: {
15
+ 1: (p: any) => string;
16
+ 2: (p: any) => string;
17
+ 3: (p: any) => string;
18
+ 4: (p: any) => string;
19
+ 5: (p: any) => string;
20
+ 6: (p: any) => string;
21
+ };
22
+ export type ErrorCode = keyof typeof messages;
23
+ export declare const validateType: (db: DbClient, def: QueryDef, type: string) => SchemaTypeDef;
24
+ export declare const includeDoesNotExist: (def: QueryDef, field: string) => void;
25
+ export declare const validateId: (def: QueryDef, id: any) => number;
26
+ export declare const validateIds: (def: QueryDef, ids: any) => Uint32Array;
27
+ export declare const handleErrors: (def: QueryDef) => void;
28
+ export declare const EMPTY_SCHEMA_DEF: SchemaTypeDef;
29
+ export {};
@@ -1,74 +1,184 @@
1
- import { ALIAS } from '../../server/schema/types.js';
2
- import { MAX_IDS_PER_QUERY, MIN_ID_VALUE, MAX_ID_VALUE, MAX_BUFFER_SIZE, } from './thresholds.js';
3
- import { validOperators } from './filter/types.js';
4
- export const isValidId = (id) => {
5
- if (typeof id != 'number') {
6
- throw new Error('Id has to be a number');
7
- }
8
- else if (id < MIN_ID_VALUE || id > MAX_ID_VALUE) {
9
- throw new Error(`Invalid Id: The Id should range between ${MIN_ID_VALUE} and ${MAX_ID_VALUE}.)`);
10
- }
11
- };
12
- export const checkMaxIdsPerQuery = (ids) => {
13
- if (ids.length > MAX_IDS_PER_QUERY) {
14
- throw new Error(`The number of IDs cannot exceed ${MAX_IDS_PER_QUERY}.`);
15
- }
1
+ import { MAX_ID, MAX_IDS_PER_QUERY } from './thresholds.js';
2
+ export const ERR_TARGET_INVAL_TYPE = 1;
3
+ export const ERR_TARGET_INVAL_ALIAS = 2;
4
+ export const ERR_TARGET_EXCEED_MAX_IDS = 3;
5
+ export const ERR_TARGET_INVAL_IDS = 4;
6
+ export const ERR_TARGET_INVAL_ID = 5;
7
+ export const ERR_INCLUDE_ENOENT = 6;
8
+ const messages = {
9
+ [ERR_TARGET_INVAL_TYPE]: (p) => `Type "${p}" does not exist`,
10
+ [ERR_TARGET_INVAL_ALIAS]: (p) => `Invalid alias "${p}"`,
11
+ [ERR_TARGET_EXCEED_MAX_IDS]: (p) => `Exceeds max ids ${~~(p.length / 1e3)}k (max ${MAX_IDS_PER_QUERY / 1e3}k)`,
12
+ [ERR_TARGET_INVAL_IDS]: (p) => `Ids should be of type array or Uint32Array with valid ids`,
13
+ [ERR_TARGET_INVAL_ID]: (p) => `Invalid id should be a number larger then 0 "${p}"`,
14
+ [ERR_INCLUDE_ENOENT]: (p) => `Included field does not exist "${p}"`,
16
15
  };
17
- export const checkMaxBufferSize = (buf) => {
18
- if (buf.byteLength > MAX_BUFFER_SIZE) {
19
- throw new Error(`The buffer size exceeds the maximum threshold of ${MAX_BUFFER_SIZE} bytes.` +
20
- `Crrent size is ${buf.byteLength} bytes.`);
16
+ export const validateType = (db, def, type) => {
17
+ const r = db.schemaTypesParsed[type];
18
+ if (!r) {
19
+ def.errors.push({
20
+ code: ERR_TARGET_INVAL_TYPE,
21
+ payload: type,
22
+ });
23
+ EMPTY_SCHEMA_DEF.locales = db.schema.locales;
24
+ return EMPTY_SCHEMA_DEF;
21
25
  }
26
+ return r;
22
27
  };
23
- export const checkTotalBufferSize = (bufers) => {
24
- let totalSize = 0;
25
- for (const buffer of bufers) {
26
- totalSize += buffer.byteLength;
27
- if (totalSize > MAX_BUFFER_SIZE) {
28
- throw new Error(`The total buffer size exceeds the maximum threshold of ${MAX_BUFFER_SIZE} bytes.` +
29
- `Crrent size is ${totalSize} bytes.`);
30
- }
31
- }
28
+ export const includeDoesNotExist = (def, field) => {
29
+ def.errors.push({
30
+ code: ERR_INCLUDE_ENOENT,
31
+ payload: field,
32
+ });
32
33
  };
33
- export const hasFields = (
34
- // get schema see if it actualy has the value (can find it on def)
35
- fields) => {
36
- if (Object.keys(fields).length === 0) {
37
- throw new Error('No fields available to include');
34
+ export const validateId = (def, id) => {
35
+ if (typeof id != 'number' || id == 0 || id > MAX_ID) {
36
+ def.errors.push({
37
+ code: ERR_TARGET_INVAL_ID,
38
+ payload: id,
39
+ });
40
+ return 1;
38
41
  }
42
+ return id;
39
43
  };
40
- export const isValidAlias = (def, id) => {
41
- for (const key in id) {
42
- const prop = def.schema.props[key];
43
- if (!prop || prop.typeIndex !== ALIAS) {
44
- throw new Error(`Incorrect alias provided for query "${key}"`);
45
- }
44
+ export const validateIds = (def, ids) => {
45
+ if (!Array.isArray(ids) && !(ids instanceof Uint32Array)) {
46
+ def.errors.push({
47
+ code: ERR_TARGET_INVAL_IDS,
48
+ payload: ids,
49
+ });
50
+ return new Uint32Array([]);
46
51
  }
47
- };
48
- // also wrong
49
- export const hasField = (field) => {
50
- // get schema see if it actualy has the value (can find it on def)
51
- if (!field) {
52
- throw new Error(`Invalid field: ${field}`);
52
+ if (ids.length > MAX_IDS_PER_QUERY) {
53
+ def.errors.push({
54
+ code: ERR_TARGET_EXCEED_MAX_IDS,
55
+ payload: ids,
56
+ });
57
+ return new Uint32Array([]);
53
58
  }
54
- else if (typeof field !== 'string' || field.trim() === '') {
55
- throw new Error('Field must be a non-empty string');
59
+ if (Array.isArray(ids)) {
60
+ try {
61
+ ids = new Uint32Array(ids);
62
+ ids.sort();
63
+ }
64
+ catch (err) {
65
+ def.errors.push({
66
+ code: ERR_TARGET_INVAL_IDS,
67
+ payload: ids,
68
+ });
69
+ return new Uint32Array([]);
70
+ }
56
71
  }
57
- };
58
- export const checkOperator = (operator) => {
59
- // pass schema value (def) and complete for each prop + operator combination
60
- if (operator !== undefined &&
61
- typeof operator !== 'boolean' &&
62
- !validOperators.includes(operator)) {
63
- throw new Error(`Invalid operator: ${operator}`);
72
+ // pretty heavy if it are a lot...
73
+ for (const id of ids) {
74
+ if (typeof id != 'number' || id == 0 || id > MAX_ID) {
75
+ def.errors.push({
76
+ code: ERR_TARGET_INVAL_IDS,
77
+ payload: ids,
78
+ });
79
+ return new Uint32Array([]);
80
+ }
64
81
  }
82
+ return ids;
65
83
  };
66
- export const checkValue = (value, operator) => {
67
- // pass schema value (def) and complete for each prop + operator combination
68
- if (operator === '..' || operator === '!..') {
69
- if (!Array.isArray(value) || value.length !== 2) {
70
- throw new Error(`Invalid value for operator ${operator}: expected an array with two elements`);
84
+ export const handleErrors = (def) => {
85
+ if (def.errors.length) {
86
+ let name = `Query\n`;
87
+ for (const err of def.errors) {
88
+ name += ` ${messages[err.code](err.payload)}\n`;
71
89
  }
90
+ const err = new Error(name);
91
+ err.stack = '';
92
+ throw err;
72
93
  }
73
94
  };
95
+ export const EMPTY_SCHEMA_DEF = {
96
+ type: '_error',
97
+ cnt: 0,
98
+ checksum: 0,
99
+ total: 0,
100
+ lastId: 0,
101
+ blockCapacity: 0,
102
+ mainLen: 0,
103
+ buf: Buffer.from([]),
104
+ propNames: Buffer.from([]),
105
+ props: {},
106
+ locales: {},
107
+ reverseProps: {},
108
+ id: 0,
109
+ idUint8: new Uint8Array([0, 0]),
110
+ main: {},
111
+ separate: [],
112
+ tree: {},
113
+ hasStringProp: false,
114
+ stringPropsSize: 0,
115
+ stringPropsCurrent: Buffer.from([]),
116
+ stringProps: Buffer.from([]),
117
+ stringPropsLoop: [],
118
+ };
119
+ // import { ALIAS, PropDef, PropDefEdge } from '../../server/schema/types.js'
120
+ // import {
121
+ // MAX_IDS_PER_QUERY,
122
+ // MIN_ID_VALUE,
123
+ // MAX_ID_VALUE,
124
+ // MAX_BUFFER_SIZE,
125
+ // } from './thresholds.js'
126
+ // import { QueryByAliasObj, QueryDef } from './types.js'
127
+ // import { DbClient } from '../index.js'
128
+ // export const isValidId = (id: number): void => {
129
+ // if (typeof id != 'number') {
130
+ // throw new Error('Id has to be a number')
131
+ // } else if (id < MIN_ID_VALUE || id > MAX_ID_VALUE) {
132
+ // throw new Error(
133
+ // `Invalid Id: The Id should range between ${MIN_ID_VALUE} and ${MAX_ID_VALUE}.)`,
134
+ // )
135
+ // }
136
+ // }
137
+ // export const isValidType = (
138
+ // type: string,
139
+ // schema: DbClient['schemaTypesParsed'],
140
+ // ): void => {
141
+ // if (!schema[type]) {
142
+ // throw new Error(`Incorrect type provided to query "${type}"`)
143
+ // }
144
+ // }
145
+ // export const isValidAlias = (def: QueryDef, id: QueryByAliasObj) => {
146
+ // for (const key in id) {
147
+ // const prop = def.schema.props[key]
148
+ // if (!prop || prop.typeIndex !== ALIAS) {
149
+ // throw new Error(`Incorrect alias provided to query "${key}"`)
150
+ // }
151
+ // }
152
+ // }
153
+ // export const checkMaxIdsPerQuery = (
154
+ // ids: (number | QueryByAliasObj)[],
155
+ // ): void => {
156
+ // if (ids.length > MAX_IDS_PER_QUERY) {
157
+ // throw new Error(`The number of IDs cannot exceed ${MAX_IDS_PER_QUERY}.`)
158
+ // }
159
+ // }
160
+ // export const checkMaxBufferSize = (buf: Buffer): void => {
161
+ // if (buf.byteLength > MAX_BUFFER_SIZE) {
162
+ // throw new Error(
163
+ // `The buffer size exceeds the maximum threshold of ${MAX_BUFFER_SIZE} bytes.` +
164
+ // `Crrent size is ${buf.byteLength} bytes.`,
165
+ // )
166
+ // }
167
+ // }
168
+ // export const checkTotalBufferSize = (bufers: Buffer[]): void => {
169
+ // let totalSize = 0
170
+ // for (const buffer of bufers) {
171
+ // totalSize += buffer.byteLength
172
+ // if (totalSize > MAX_BUFFER_SIZE) {
173
+ // throw new Error(
174
+ // `The total buffer size exceeds the maximum threshold of ${MAX_BUFFER_SIZE} bytes.` +
175
+ // `Crrent size is ${totalSize} bytes.`,
176
+ // )
177
+ // }
178
+ // }
179
+ // }
180
+ // // ------------------------------
181
+ // export const includeDoesNotExist = (def: QueryDef, field: string) => {
182
+ // throw new Error(`Incorrect include field provided to query "${field}")`)
183
+ // }
74
184
  //# sourceMappingURL=validation.js.map
@@ -81,7 +81,6 @@ export function createTree(createHash) {
81
81
  const left = node.left;
82
82
  const right = node.right;
83
83
  if (!left || !right) {
84
- console.log(node, k);
85
84
  if (node.data) {
86
85
  if (node.key === k) {
87
86
  return null;
@@ -3,6 +3,7 @@ import { SchemaTypeDef } from './schema/types.js';
3
3
  import { createTree } from './csmt/index.js';
4
4
  import { Worker, MessagePort } from 'node:worker_threads';
5
5
  import { TransformFns } from './migrate/index.js';
6
+ import exitHook from 'exit-hook';
6
7
  declare class SortIndex {
7
8
  constructor(buf: Buffer, dbCtxExternal: any);
8
9
  buf: Buffer;
@@ -48,6 +49,7 @@ export declare class DbServer {
48
49
  queryQueue: Map<Function, Buffer>;
49
50
  stopped: boolean;
50
51
  onSchemaChange: OnSchemaChange;
52
+ unlistenExit: ReturnType<typeof exitHook>;
51
53
  constructor({ path, maxModifySize, onSchemaChange, }: {
52
54
  path: string;
53
55
  maxModifySize?: number;
@@ -56,7 +58,7 @@ export declare class DbServer {
56
58
  start(opts?: {
57
59
  clean?: boolean;
58
60
  }): Promise<void>;
59
- save(): Promise<void>;
61
+ save(): void | Promise<void>;
60
62
  createCsmtHashFun: () => {
61
63
  update: (buf: Buffer) => any;
62
64
  digest: (encoding?: BufferEncoding) => Buffer | string;
@@ -82,6 +82,7 @@ export class DbServer {
82
82
  queryQueue = new Map();
83
83
  stopped;
84
84
  onSchemaChange;
85
+ unlistenExit;
85
86
  constructor({ path, maxModifySize = 100 * 1e3 * 1e3, onSchemaChange, }) {
86
87
  this.maxModifySize = maxModifySize;
87
88
  this.fileSystemPath = path;
@@ -432,6 +433,7 @@ export class DbServer {
432
433
  }
433
434
  this.stopped = true;
434
435
  clearTimeout(this.cleanupTimer);
436
+ this.unlistenExit();
435
437
  try {
436
438
  if (!noSave) {
437
439
  await this.save();
@@ -448,7 +450,7 @@ export class DbServer {
448
450
  }
449
451
  async destroy() {
450
452
  await this.stop(true);
451
- await rm(this.fileSystemPath, { recursive: true }).catch((err) => console.warn('Error removing dump folder', err.message));
453
+ await rm(this.fileSystemPath, { recursive: true }).catch((err) => console.warn('Error removing dump folder', this.fileSystemPath, err.message));
452
454
  }
453
455
  }
454
456
  //# sourceMappingURL=index.js.map
@@ -1,2 +1,2 @@
1
1
  import { DbServer } from './index.js';
2
- export declare function save(db: DbServer): Promise<void>;
2
+ export declare function save(db: DbServer, sync?: boolean): void | Promise<void>;
@@ -2,10 +2,14 @@ import native from '../native.js';
2
2
  import { writeFile } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
4
  import { destructureCsmtKey, foreachDirtyBlock } from './tree.js';
5
+ import { writeFileSync } from 'node:fs';
5
6
  const WRITELOG_FILE = 'writelog.json';
6
7
  const COMMON_SDB_FILE = 'common.sdb';
7
8
  const block_sdb_file = (typeId, start, end) => `${typeId}_${start}_${end}.sdb`;
8
- export async function save(db) {
9
+ export function save(db, sync = false) {
10
+ if (!db.dirtyRanges.size) {
11
+ return;
12
+ }
9
13
  let err;
10
14
  const ts = Date.now();
11
15
  err = native.saveCommon(join(db.fileSystemPath, COMMON_SDB_FILE), db.dbCtxExternal);
@@ -61,6 +65,8 @@ export async function save(db) {
61
65
  if (mtRoot) {
62
66
  data.hash = mtRoot.hash.toString('hex');
63
67
  }
64
- await writeFile(join(db.fileSystemPath, WRITELOG_FILE), JSON.stringify(data));
68
+ const filePath = join(db.fileSystemPath, WRITELOG_FILE);
69
+ const content = JSON.stringify(data);
70
+ return sync ? writeFileSync(filePath, content) : writeFile(filePath, content);
65
71
  }
66
72
  //# sourceMappingURL=save.js.map
@@ -6,7 +6,9 @@ import { join } from 'node:path';
6
6
  import { createTree } from './csmt/index.js';
7
7
  import { foreachBlock } from './tree.js';
8
8
  import { availableParallelism } from 'node:os';
9
+ import exitHook from 'exit-hook';
9
10
  import './worker.js';
11
+ import { save } from './save.js';
10
12
  const SCHEMA_FILE = 'schema.json';
11
13
  const WRITELOG_FILE = 'writelog.json';
12
14
  export const DEFAULT_BLOCK_CAPACITY = 100_000;
@@ -82,5 +84,10 @@ export async function start(db, opts) {
82
84
  while (i--) {
83
85
  db.workers[i] = new DbWorker(address, db);
84
86
  }
87
+ db.unlistenExit = exitHook((signal) => {
88
+ console.log(`Exiting with signal: ${signal}`);
89
+ save(db, true);
90
+ console.log('Successfully saved.');
91
+ });
85
92
  }
86
93
  //# sourceMappingURL=start.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@based/db",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -34,6 +34,7 @@
34
34
  "@based/schema": "5.0.0-alpha.3",
35
35
  "@saulx/hash": "^3.0.0",
36
36
  "@saulx/utils": "^4.3.2",
37
+ "exit-hook": "^4.0.0",
37
38
  "picocolors": "^1.1.0"
38
39
  },
39
40
  "optionalDependencies": {
Binary file
Binary file