@based/db 0.0.29 → 0.0.31

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/db.h +2 -1
  2. package/dist/lib/darwin_aarch64/include/selva/fields.h +20 -7
  3. package/dist/lib/darwin_aarch64/include/selva/types.h +3 -1
  4. package/dist/lib/darwin_aarch64/libnode-v20.node +0 -0
  5. package/dist/lib/darwin_aarch64/libnode-v21.node +0 -0
  6. package/dist/lib/darwin_aarch64/libnode-v22.node +0 -0
  7. package/dist/lib/darwin_aarch64/libnode-v23.node +0 -0
  8. package/dist/lib/darwin_aarch64/libselva.dylib +0 -0
  9. package/dist/lib/linux_aarch64/include/selva/db.h +2 -1
  10. package/dist/lib/linux_aarch64/include/selva/fields.h +20 -7
  11. package/dist/lib/linux_aarch64/include/selva/types.h +3 -1
  12. package/dist/lib/linux_aarch64/libnode-v20.node +0 -0
  13. package/dist/lib/linux_aarch64/libnode-v21.node +0 -0
  14. package/dist/lib/linux_aarch64/libnode-v22.node +0 -0
  15. package/dist/lib/linux_aarch64/libnode-v23.node +0 -0
  16. package/dist/lib/linux_aarch64/libselva.so +0 -0
  17. package/dist/lib/linux_x86_64/include/selva/db.h +2 -1
  18. package/dist/lib/linux_x86_64/include/selva/fields.h +20 -7
  19. package/dist/lib/linux_x86_64/include/selva/types.h +3 -1
  20. package/dist/lib/linux_x86_64/libnode-v20.node +0 -0
  21. package/dist/lib/linux_x86_64/libnode-v21.node +0 -0
  22. package/dist/lib/linux_x86_64/libnode-v22.node +0 -0
  23. package/dist/lib/linux_x86_64/libnode-v23.node +0 -0
  24. package/dist/lib/linux_x86_64/libselva.so +0 -0
  25. package/dist/src/client/flushModify.js +4 -3
  26. package/dist/src/client/index.d.ts +2 -6
  27. package/dist/src/client/index.js +0 -6
  28. package/dist/src/client/modify/ModifyRes.d.ts +1 -3
  29. package/dist/src/client/modify/ModifyRes.js +1 -3
  30. package/dist/src/client/modify/create.js +1 -2
  31. package/dist/src/client/modify/delete.js +1 -2
  32. package/dist/src/client/modify/modify.js +0 -4
  33. package/dist/src/client/modify/setCursor.js +1 -1
  34. package/dist/src/client/modify/update.js +1 -2
  35. package/dist/src/client/query/read/read.js +13 -4
  36. package/dist/src/client/query/subscription/index.d.ts +1 -2
  37. package/dist/src/client/query/subscription/index.js +3 -50
  38. package/dist/src/client/query/subscription/types.d.ts +1 -29
  39. package/dist/src/client/query/subscription/types.js +8 -1
  40. package/dist/src/client/string.js +1 -1
  41. package/dist/src/index.js +28 -0
  42. package/dist/src/native.d.ts +2 -2
  43. package/dist/src/native.js +3 -1
  44. package/dist/src/server/save.js +4 -7
  45. package/dist/src/server/start.js +8 -6
  46. package/dist/src/server/tree.d.ts +1 -1
  47. package/dist/src/server/tree.js +2 -2
  48. package/package.json +1 -1
@@ -209,9 +209,10 @@ void selva_db_expire_tick(struct SelvaDb *db, int64_t now);
209
209
 
210
210
  /**
211
211
  * Delete a node.
212
+ * @param dirty_cb is called for any newly dirty nodes in addition to the node being deleted.
212
213
  */
213
214
  SELVA_EXPORT
214
- void selva_del_node(struct SelvaDb *db, struct SelvaTypeEntry *type, struct SelvaNode *node) __attribute__((nonnull));
215
+ void selva_del_node(struct SelvaDb *db, struct SelvaTypeEntry *type, struct SelvaNode *node, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx) __attribute__((nonnull(1, 2, 3)));
215
216
 
216
217
  /**
217
218
  * Get a node by id.
@@ -152,14 +152,22 @@ struct selva_string *selva_fields_ensure_string2(
152
152
  const struct SelvaFieldSchema *fs,
153
153
  size_t initial_len);
154
154
 
155
+ /**
156
+ * Set reference to fields.
157
+ * @param dirty_nodes returns the nodes that were changed, apart from src and dst.
158
+ * [n].id = 0 = nil;
159
+ * [0] = the node src was pointing to previously (same type as dst);
160
+ * [1] = the node dst was pointing to previously (same type as src).
161
+ */
155
162
  SELVA_EXPORT
156
163
  int selva_fields_reference_set(
157
164
  struct SelvaDb *db,
158
165
  struct SelvaNode * restrict src,
159
166
  const struct SelvaFieldSchema *fs_src,
160
167
  struct SelvaNode * restrict dst,
161
- struct SelvaNodeReference **ref_out)
162
- __attribute__((access(write_only, 5)));
168
+ struct SelvaNodeReference **ref_out,
169
+ node_id_t dirty_nodes[static 2])
170
+ __attribute__((access(write_only, 5), access(write_only, 6)));
163
171
 
164
172
  /**
165
173
  * @param index 0 = first; -1 = last.
@@ -333,10 +341,11 @@ struct SelvaFieldsPointer selva_fields_get_raw(struct SelvaNode *node, const str
333
341
 
334
342
  /**
335
343
  * Delete field.
344
+ * @param dirty_cb will be called with the deleted node_id in case of a reference(s) field.
336
345
  */
337
346
  SELVA_EXPORT
338
- int selva_fields_del(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs)
339
- __attribute__((nonnull));
347
+ int selva_fields_del(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx)
348
+ __attribute__((nonnull(1, 2, 3)));
340
349
 
341
350
  /**
342
351
  * Delete an edge from a references field.
@@ -344,9 +353,12 @@ int selva_fields_del(struct SelvaDb *db, struct SelvaNode *node, const struct Se
344
353
  SELVA_EXPORT
345
354
  int selva_fields_del_ref(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs, node_id_t dst_node_id);
346
355
 
356
+ /**
357
+ * Clear a references field but don't free it.
358
+ */
347
359
  SELVA_EXPORT
348
- void selva_fields_clear_references(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs)
349
- __attribute__((nonnull));
360
+ void selva_fields_clear_references(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx)
361
+ __attribute__((nonnull(1, 2, 3)));
350
362
 
351
363
  /**
352
364
  * Init the fields struct of a node or edge.
@@ -361,7 +373,8 @@ void selva_fields_init(const struct SelvaFieldsSchema *schema, struct SelvaField
361
373
  * regardless wether the schema defines fields for this node.
362
374
  */
363
375
  SELVA_EXPORT
364
- void selva_fields_destroy(struct SelvaDb *db, struct SelvaNode *node);
376
+ void selva_fields_destroy(struct SelvaDb *db, struct SelvaNode *node, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx)
377
+ __attribute__((nonnull(1, 2)));
365
378
 
366
379
  SELVA_EXPORT
367
380
  void selva_fields_hash_update(struct XXH3_state_s *hash_state, struct SelvaDb *db, const struct SelvaFieldsSchema *schema, const struct SelvaFields *fields);
@@ -43,7 +43,7 @@ struct EdgeFieldConstraint {
43
43
  EDGE_FIELD_CONSTRAINT_FLAG_SCHEMA_REF_CACHED = 0x40,
44
44
  /**
45
45
  * Skip saving this field while dumping.
46
- * If the field is of type SELVA_FIELD_TYPE_WEAK_REFERENCES it's saved
46
+ * If the field is of type SELVA_FIELD_TYPE_REFERENCES it's saved
47
47
  * regardless of this flag to preserve the original order of references.
48
48
  */
49
49
  EDGE_FIELD_CONSTRAINT_FLAG_SKIP_DUMP = 0x80,
@@ -97,6 +97,8 @@ struct SelvaFields;
97
97
  struct SelvaNode;
98
98
  struct SelvaTypeEntry;
99
99
 
100
+ typedef void (*selva_dirty_node_cb_t)(void *ctx, node_type_t type, node_id_t node_id);
101
+
100
102
  SELVA_EXPORT
101
103
  bool selva_is_valid_field_type(enum SelvaFieldType ftype);
102
104
 
@@ -209,9 +209,10 @@ void selva_db_expire_tick(struct SelvaDb *db, int64_t now);
209
209
 
210
210
  /**
211
211
  * Delete a node.
212
+ * @param dirty_cb is called for any newly dirty nodes in addition to the node being deleted.
212
213
  */
213
214
  SELVA_EXPORT
214
- void selva_del_node(struct SelvaDb *db, struct SelvaTypeEntry *type, struct SelvaNode *node) __attribute__((nonnull));
215
+ void selva_del_node(struct SelvaDb *db, struct SelvaTypeEntry *type, struct SelvaNode *node, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx) __attribute__((nonnull(1, 2, 3)));
215
216
 
216
217
  /**
217
218
  * Get a node by id.
@@ -152,14 +152,22 @@ struct selva_string *selva_fields_ensure_string2(
152
152
  const struct SelvaFieldSchema *fs,
153
153
  size_t initial_len);
154
154
 
155
+ /**
156
+ * Set reference to fields.
157
+ * @param dirty_nodes returns the nodes that were changed, apart from src and dst.
158
+ * [n].id = 0 = nil;
159
+ * [0] = the node src was pointing to previously (same type as dst);
160
+ * [1] = the node dst was pointing to previously (same type as src).
161
+ */
155
162
  SELVA_EXPORT
156
163
  int selva_fields_reference_set(
157
164
  struct SelvaDb *db,
158
165
  struct SelvaNode * restrict src,
159
166
  const struct SelvaFieldSchema *fs_src,
160
167
  struct SelvaNode * restrict dst,
161
- struct SelvaNodeReference **ref_out)
162
- __attribute__((access(write_only, 5)));
168
+ struct SelvaNodeReference **ref_out,
169
+ node_id_t dirty_nodes[static 2])
170
+ __attribute__((access(write_only, 5), access(write_only, 6)));
163
171
 
164
172
  /**
165
173
  * @param index 0 = first; -1 = last.
@@ -333,10 +341,11 @@ struct SelvaFieldsPointer selva_fields_get_raw(struct SelvaNode *node, const str
333
341
 
334
342
  /**
335
343
  * Delete field.
344
+ * @param dirty_cb will be called with the deleted node_id in case of a reference(s) field.
336
345
  */
337
346
  SELVA_EXPORT
338
- int selva_fields_del(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs)
339
- __attribute__((nonnull));
347
+ int selva_fields_del(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx)
348
+ __attribute__((nonnull(1, 2, 3)));
340
349
 
341
350
  /**
342
351
  * Delete an edge from a references field.
@@ -344,9 +353,12 @@ int selva_fields_del(struct SelvaDb *db, struct SelvaNode *node, const struct Se
344
353
  SELVA_EXPORT
345
354
  int selva_fields_del_ref(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs, node_id_t dst_node_id);
346
355
 
356
+ /**
357
+ * Clear a references field but don't free it.
358
+ */
347
359
  SELVA_EXPORT
348
- void selva_fields_clear_references(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs)
349
- __attribute__((nonnull));
360
+ void selva_fields_clear_references(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx)
361
+ __attribute__((nonnull(1, 2, 3)));
350
362
 
351
363
  /**
352
364
  * Init the fields struct of a node or edge.
@@ -361,7 +373,8 @@ void selva_fields_init(const struct SelvaFieldsSchema *schema, struct SelvaField
361
373
  * regardless wether the schema defines fields for this node.
362
374
  */
363
375
  SELVA_EXPORT
364
- void selva_fields_destroy(struct SelvaDb *db, struct SelvaNode *node);
376
+ void selva_fields_destroy(struct SelvaDb *db, struct SelvaNode *node, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx)
377
+ __attribute__((nonnull(1, 2)));
365
378
 
366
379
  SELVA_EXPORT
367
380
  void selva_fields_hash_update(struct XXH3_state_s *hash_state, struct SelvaDb *db, const struct SelvaFieldsSchema *schema, const struct SelvaFields *fields);
@@ -43,7 +43,7 @@ struct EdgeFieldConstraint {
43
43
  EDGE_FIELD_CONSTRAINT_FLAG_SCHEMA_REF_CACHED = 0x40,
44
44
  /**
45
45
  * Skip saving this field while dumping.
46
- * If the field is of type SELVA_FIELD_TYPE_WEAK_REFERENCES it's saved
46
+ * If the field is of type SELVA_FIELD_TYPE_REFERENCES it's saved
47
47
  * regardless of this flag to preserve the original order of references.
48
48
  */
49
49
  EDGE_FIELD_CONSTRAINT_FLAG_SKIP_DUMP = 0x80,
@@ -97,6 +97,8 @@ struct SelvaFields;
97
97
  struct SelvaNode;
98
98
  struct SelvaTypeEntry;
99
99
 
100
+ typedef void (*selva_dirty_node_cb_t)(void *ctx, node_type_t type, node_id_t node_id);
101
+
100
102
  SELVA_EXPORT
101
103
  bool selva_is_valid_field_type(enum SelvaFieldType ftype);
102
104
 
Binary file
@@ -209,9 +209,10 @@ void selva_db_expire_tick(struct SelvaDb *db, int64_t now);
209
209
 
210
210
  /**
211
211
  * Delete a node.
212
+ * @param dirty_cb is called for any newly dirty nodes in addition to the node being deleted.
212
213
  */
213
214
  SELVA_EXPORT
214
- void selva_del_node(struct SelvaDb *db, struct SelvaTypeEntry *type, struct SelvaNode *node) __attribute__((nonnull));
215
+ void selva_del_node(struct SelvaDb *db, struct SelvaTypeEntry *type, struct SelvaNode *node, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx) __attribute__((nonnull(1, 2, 3)));
215
216
 
216
217
  /**
217
218
  * Get a node by id.
@@ -152,14 +152,22 @@ struct selva_string *selva_fields_ensure_string2(
152
152
  const struct SelvaFieldSchema *fs,
153
153
  size_t initial_len);
154
154
 
155
+ /**
156
+ * Set reference to fields.
157
+ * @param dirty_nodes returns the nodes that were changed, apart from src and dst.
158
+ * [n].id = 0 = nil;
159
+ * [0] = the node src was pointing to previously (same type as dst);
160
+ * [1] = the node dst was pointing to previously (same type as src).
161
+ */
155
162
  SELVA_EXPORT
156
163
  int selva_fields_reference_set(
157
164
  struct SelvaDb *db,
158
165
  struct SelvaNode * restrict src,
159
166
  const struct SelvaFieldSchema *fs_src,
160
167
  struct SelvaNode * restrict dst,
161
- struct SelvaNodeReference **ref_out)
162
- __attribute__((access(write_only, 5)));
168
+ struct SelvaNodeReference **ref_out,
169
+ node_id_t dirty_nodes[static 2])
170
+ __attribute__((access(write_only, 5), access(write_only, 6)));
163
171
 
164
172
  /**
165
173
  * @param index 0 = first; -1 = last.
@@ -333,10 +341,11 @@ struct SelvaFieldsPointer selva_fields_get_raw(struct SelvaNode *node, const str
333
341
 
334
342
  /**
335
343
  * Delete field.
344
+ * @param dirty_cb will be called with the deleted node_id in case of a reference(s) field.
336
345
  */
337
346
  SELVA_EXPORT
338
- int selva_fields_del(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs)
339
- __attribute__((nonnull));
347
+ int selva_fields_del(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx)
348
+ __attribute__((nonnull(1, 2, 3)));
340
349
 
341
350
  /**
342
351
  * Delete an edge from a references field.
@@ -344,9 +353,12 @@ int selva_fields_del(struct SelvaDb *db, struct SelvaNode *node, const struct Se
344
353
  SELVA_EXPORT
345
354
  int selva_fields_del_ref(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs, node_id_t dst_node_id);
346
355
 
356
+ /**
357
+ * Clear a references field but don't free it.
358
+ */
347
359
  SELVA_EXPORT
348
- void selva_fields_clear_references(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs)
349
- __attribute__((nonnull));
360
+ void selva_fields_clear_references(struct SelvaDb *db, struct SelvaNode *node, const struct SelvaFieldSchema *fs, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx)
361
+ __attribute__((nonnull(1, 2, 3)));
350
362
 
351
363
  /**
352
364
  * Init the fields struct of a node or edge.
@@ -361,7 +373,8 @@ void selva_fields_init(const struct SelvaFieldsSchema *schema, struct SelvaField
361
373
  * regardless wether the schema defines fields for this node.
362
374
  */
363
375
  SELVA_EXPORT
364
- void selva_fields_destroy(struct SelvaDb *db, struct SelvaNode *node);
376
+ void selva_fields_destroy(struct SelvaDb *db, struct SelvaNode *node, selva_dirty_node_cb_t dirty_cb, void *dirty_ctx)
377
+ __attribute__((nonnull(1, 2)));
365
378
 
366
379
  SELVA_EXPORT
367
380
  void selva_fields_hash_update(struct XXH3_state_s *hash_state, struct SelvaDb *db, const struct SelvaFieldsSchema *schema, const struct SelvaFields *fields);
@@ -43,7 +43,7 @@ struct EdgeFieldConstraint {
43
43
  EDGE_FIELD_CONSTRAINT_FLAG_SCHEMA_REF_CACHED = 0x40,
44
44
  /**
45
45
  * Skip saving this field while dumping.
46
- * If the field is of type SELVA_FIELD_TYPE_WEAK_REFERENCES it's saved
46
+ * If the field is of type SELVA_FIELD_TYPE_REFERENCES it's saved
47
47
  * regardless of this flag to preserve the original order of references.
48
48
  */
49
49
  EDGE_FIELD_CONSTRAINT_FLAG_SKIP_DUMP = 0x80,
@@ -97,6 +97,8 @@ struct SelvaFields;
97
97
  struct SelvaNode;
98
98
  struct SelvaTypeEntry;
99
99
 
100
+ typedef void (*selva_dirty_node_cb_t)(void *ctx, node_type_t type, node_id_t node_id);
101
+
100
102
  SELVA_EXPORT
101
103
  bool selva_is_valid_field_type(enum SelvaFieldType ftype);
102
104
 
Binary file
@@ -90,11 +90,13 @@ export const flushBuffer = (db) => {
90
90
  const ctx = db.modifyCtx;
91
91
  let flushPromise;
92
92
  if (ctx.len) {
93
- const d = Date.now();
94
93
  const lastIds = {};
95
94
  const data = ctx.getData(lastIds);
96
95
  const resCtx = ctx.ctx;
96
+ const d = performance.now();
97
97
  flushPromise = db.hooks.flushModify(data).then(({ offsets }) => {
98
+ // return time there
99
+ db.writeTime += performance.now() - d;
98
100
  resCtx.offsets = offsets;
99
101
  for (const typeId in lastIds) {
100
102
  if (typeId in offsets) {
@@ -107,7 +109,7 @@ export const flushBuffer = (db) => {
107
109
  }
108
110
  }
109
111
  else {
110
- console.warn('no offset returned, very wrong');
112
+ console.error('Panic: No offset returned in flushModify');
111
113
  }
112
114
  }
113
115
  if (resCtx.queue?.size) {
@@ -117,7 +119,6 @@ export const flushBuffer = (db) => {
117
119
  resolve(res.getId());
118
120
  }
119
121
  }
120
- db.writeTime += Date.now() - d;
121
122
  db.flushReady();
122
123
  });
123
124
  ctx.dirtyTypes.clear();
@@ -2,18 +2,19 @@ import { Schema, StrictSchema } from '@based/schema';
2
2
  import { CreateObj } from './modify/create.js';
3
3
  import { SchemaTypeDef } from '@based/schema/def';
4
4
  import { ModifyCtx } from './flushModify.js';
5
- import { SubscriptionMarkerMap, SubscriptionsMap, SubscriptionsToRun } from './query/subscription/index.js';
6
5
  import { BasedDbQuery, QueryByAliasObj } from './query/BasedDbQuery.js';
7
6
  import { ModifyRes } from './modify/ModifyRes.js';
8
7
  import { DbServer } from '../server/index.js';
9
8
  import { TransformFns } from '../server/migrate/index.js';
10
9
  import { ModifyOpts } from './modify/types.js';
10
+ import { OnClose, OnData, OnError } from './query/subscription/types.js';
11
11
  export type DbClientHooks = {
12
12
  setSchema(schema: StrictSchema, fromStart?: boolean, transformFns?: TransformFns): Promise<DbServer['schema']>;
13
13
  flushModify(buf: Uint8Array): Promise<{
14
14
  offsets: Record<number, number>;
15
15
  }>;
16
16
  getQueryBuf(buf: Uint8Array): Promise<Uint8Array>;
17
+ subscribe(q: BasedDbQuery, onData: OnData, onError?: OnError): OnClose;
17
18
  };
18
19
  type DbClientOpts = {
19
20
  hooks: DbClientHooks;
@@ -42,11 +43,6 @@ export declare class DbClient {
42
43
  o: Record<string, any>;
43
44
  p: Promise<number | ModifyRes>;
44
45
  }>;
45
- subscriptionsInProgress: boolean;
46
- subscriptonThrottleMs: number;
47
- subscriptions: SubscriptionsMap;
48
- subscriptionMarkers: SubscriptionMarkerMap;
49
- subscriptionsToRun: SubscriptionsToRun;
50
46
  schemaChecksum: number;
51
47
  setSchema(schema: Schema, fromStart?: boolean, transformFns?: TransformFns): Promise<StrictSchema>;
52
48
  putLocalSchema(schema: any): DbClientSchema;
@@ -47,12 +47,6 @@ export class DbClient {
47
47
  modifyCtx;
48
48
  maxModifySize;
49
49
  upserting = new Map();
50
- // subscriptions
51
- subscriptionsInProgress = false;
52
- subscriptonThrottleMs = 20;
53
- subscriptions = new Map();
54
- subscriptionMarkers = {};
55
- subscriptionsToRun = [];
56
50
  schemaChecksum;
57
51
  async setSchema(schema, fromStart, transformFns) {
58
52
  this.schemaIsSetValue = true;
@@ -1,5 +1,4 @@
1
1
  import { PropDef, PropDefEdge, SchemaPropTree } from '@based/schema/def';
2
- import { SubscriptionMarkersCheck } from '../query/subscription/index.js';
3
2
  import { DbClient } from '../index.js';
4
3
  import { ModifyOpts } from './types.js';
5
4
  import { LangCode } from '@based/schema';
@@ -12,8 +11,7 @@ export declare class ModifyError extends Error {
12
11
  }
13
12
  export declare class ModifyState {
14
13
  #private;
15
- constructor(typeId: number, tmpId: number, db: DbClient, subMarkers: SubscriptionMarkersCheck | false, opts: ModifyOpts, update?: boolean);
16
- subMarkers: SubscriptionMarkersCheck | false;
14
+ constructor(typeId: number, tmpId: number, db: DbClient, opts: ModifyOpts, update?: boolean);
17
15
  update: boolean;
18
16
  locale: LangCode;
19
17
  tmpId: number;
@@ -42,17 +42,15 @@ export class ModifyError extends Error {
42
42
  }
43
43
  }
44
44
  export class ModifyState {
45
- constructor(typeId, tmpId, db, subMarkers, opts, update = false) {
45
+ constructor(typeId, tmpId, db, opts, update = false) {
46
46
  this.tmpId = tmpId;
47
47
  this.#typeId = typeId;
48
48
  this.#ctx = db.modifyCtx.ctx;
49
- this.subMarkers = subMarkers;
50
49
  this.update = update;
51
50
  if (opts?.locale) {
52
51
  this.locale = langCodesMap.get(opts.locale);
53
52
  }
54
53
  }
55
- subMarkers;
56
54
  update;
57
55
  locale;
58
56
  #ctx;
@@ -5,7 +5,6 @@ import { modify } from './modify.js';
5
5
  import { ModifyState } from './ModifyRes.js';
6
6
  import { CREATE, RANGE_ERR, ADD_EMPTY_SORT, ADD_EMPTY_SORT_TEXT, } from './types.js';
7
7
  import { writeFixedValue } from './fixed.js';
8
- import { getSubscriptionMarkers } from '../query/subscription/index.js';
9
8
  const appendCreate = (ctx, def, obj, res, unsafe) => {
10
9
  const len = ctx.len;
11
10
  let err = modify(ctx, res, obj, def, CREATE, def.tree, true, unsafe);
@@ -136,7 +135,7 @@ export function create(db, type, obj, opts) {
136
135
  id = def.lastId + 1;
137
136
  }
138
137
  const ctx = db.modifyCtx;
139
- const res = new ModifyState(def.id, id, db, getSubscriptionMarkers(db, def.id, id, true), opts);
138
+ const res = new ModifyState(def.id, id, db, opts);
140
139
  const pos = ctx.len;
141
140
  const err = appendCreate(ctx, def, obj, res, opts?.unsafe);
142
141
  if (err) {
@@ -1,5 +1,4 @@
1
1
  import { flushBuffer, startDrain } from '../flushModify.js';
2
- import { getSubscriptionMarkers } from '../query/subscription/markers.js';
3
2
  import { ModifyState } from './ModifyRes.js';
4
3
  import { setCursor } from './setCursor.js';
5
4
  import { UPDATE, DELETE_SORT_INDEX, DELETE_NODE, } from './types.js';
@@ -10,7 +9,7 @@ export const deleteFn = (db, type, id, opts) => {
10
9
  throw new Error(`Unknown type: ${type}. Did you mean on of: ${Object.keys(db.schemaTypesParsed).join(', ')}`);
11
10
  }
12
11
  const ctx = db.modifyCtx;
13
- const res = new ModifyState(def.id, id, db, getSubscriptionMarkers(db, def.id, id, true), opts);
12
+ const res = new ModifyState(def.id, id, db, opts);
14
13
  const schema = db.schemaTypesParsed[type];
15
14
  const separate = schema.separate;
16
15
  if (separate) {
@@ -11,7 +11,6 @@ import { appendFixedValue, writeFixedValue } from './fixed.js';
11
11
  import { writeAlias } from './alias.js';
12
12
  import { writeHll } from './cardinality.js';
13
13
  import { writeVector } from './vector.js';
14
- import { checkSubscriptionMarkers } from '../query/subscription/index.js';
15
14
  import { writeJson } from './json.js';
16
15
  function _modify(ctx, res, obj, schema, mod, tree, overwrite, unsafe) {
17
16
  for (const key in obj) {
@@ -28,9 +27,6 @@ function _modify(ctx, res, obj, schema, mod, tree, overwrite, unsafe) {
28
27
  if (val === undefined) {
29
28
  continue;
30
29
  }
31
- if (res.subMarkers) {
32
- checkSubscriptionMarkers(ctx.db, res.subMarkers, def);
33
- }
34
30
  const type = def.typeIndex;
35
31
  if (def.separate) {
36
32
  if (type === STRING) {
@@ -1,5 +1,5 @@
1
1
  import { CREATE, SWITCH_FIELD, SWITCH_ID_CREATE, SWITCH_ID_UPDATE, SWITCH_TYPE, } from './types.js';
2
- export const setCursor = (ctx, schema, field, // PROPDEF
2
+ export const setCursor = (ctx, schema, field, // TODO pass propdef better
3
3
  typeIndex, id, modifyOp, ignoreField) => {
4
4
  const prefix0 = schema.idUint8[0];
5
5
  const prefix1 = schema.idUint8[1];
@@ -5,7 +5,6 @@ import { modify } from './modify.js';
5
5
  import { ModifyState } from './ModifyRes.js';
6
6
  import { RANGE_ERR, UPDATE } from './types.js';
7
7
  import { appendFixedValue } from './fixed.js';
8
- import { getSubscriptionMarkers } from '../query/subscription/index.js';
9
8
  const appendUpdate = (ctx, def, obj, res, overwrite) => {
10
9
  const err = modify(ctx, res, obj, def, UPDATE, def.tree, overwrite);
11
10
  if (err) {
@@ -62,7 +61,7 @@ export const update = (db, type, id, obj, opts) => {
62
61
  }
63
62
  const ctx = db.modifyCtx;
64
63
  const pos = ctx.len;
65
- const res = new ModifyState(def.id, id, db, getSubscriptionMarkers(db, def.id, id, false), opts, true);
64
+ const res = new ModifyState(def.id, id, db, opts, true);
66
65
  const err = appendUpdate(ctx, def, obj, res, opts?.overwrite);
67
66
  if (err) {
68
67
  ctx.prefix0 = -1; // force a new cursor
@@ -146,7 +146,8 @@ const handleUndefinedProps = (id, q, item) => {
146
146
  if (lang.has(0)) {
147
147
  for (const locale in q.schema.locales) {
148
148
  if (!lan[locale]) {
149
- lan[locale] = '';
149
+ // console.log('???', locale, prop.default)
150
+ lan[locale] = prop.default[locale] || '';
150
151
  }
151
152
  }
152
153
  }
@@ -154,16 +155,24 @@ const handleUndefinedProps = (id, q, item) => {
154
155
  for (const code of lang) {
155
156
  const locale = inverseLangMap.get(code);
156
157
  if (!lan[locale]) {
157
- lan[locale] = '';
158
+ lan[locale] = prop.default[locale] || '';
158
159
  }
159
160
  }
160
161
  }
161
162
  }
162
163
  else if (prop.typeIndex === BINARY) {
163
- addField(prop, new Uint8Array(0), item);
164
+ addField(prop, prop.default, item);
165
+ }
166
+ else if (prop.typeIndex === TEXT) {
167
+ // q.lang
168
+ // console.log('???')
169
+ addField(prop, '', item);
164
170
  }
165
171
  else {
166
- addField(prop, prop.typeIndex === JSON ? null : '', item);
172
+ 1;
173
+ if (prop.default !== undefined) {
174
+ addField(prop, prop.default, item);
175
+ }
167
176
  }
168
177
  }
169
178
  }
@@ -1,5 +1,4 @@
1
1
  import { BasedDbQuery } from '../BasedDbQuery.js';
2
2
  import { OnData, OnError, OnClose } from './types.js';
3
+ export declare const subscribe: (q: BasedDbQuery, onData: OnData, onError?: OnError) => OnClose;
3
4
  export * from './types.js';
4
- export * from './markers.js';
5
- export declare const subscribe: (q: BasedDbQuery, onData: OnData, onError: OnError) => OnClose;
@@ -1,58 +1,11 @@
1
1
  import { includeField } from '../query.js';
2
2
  import { registerQuery } from '../registerQuery.js';
3
- import { runSubscription } from './run.js';
4
- import { addSubscriptionMarkers, deleteSubscriptionMarkers } from './markers.js';
5
- export * from './types.js';
6
- export * from './markers.js';
7
3
  export const subscribe = (q, onData, onError) => {
8
- let closed = false;
9
4
  if (!q.def.include.stringFields.size && !q.def.references.size) {
10
5
  includeField(q.def, '*');
11
6
  }
12
- try {
13
- registerQuery(q);
14
- }
15
- catch (err) {
16
- onError(err);
17
- return () => q;
18
- }
19
- if (!q.db.subscriptions.has(q.id)) {
20
- const subscription = {
21
- query: q,
22
- subs: new Set(),
23
- inProgress: false,
24
- closed: false,
25
- };
26
- q.db.subscriptions.set(q.id, subscription);
27
- addSubscriptionMarkers(q, subscription);
28
- }
29
- const fn = (res, err) => {
30
- if (!closed) {
31
- if (err) {
32
- onError(err);
33
- }
34
- else {
35
- onData(res);
36
- }
37
- }
38
- };
39
- const sub = q.db.subscriptions.get(q.id);
40
- const close = () => {
41
- sub.subs.delete(fn);
42
- if (sub.subs.size === 0) {
43
- q.db.subscriptions.delete(q.id);
44
- deleteSubscriptionMarkers(q);
45
- }
46
- closed = true;
47
- return q;
48
- };
49
- sub.subs.add(fn);
50
- if (sub.res) {
51
- onData(sub.res);
52
- }
53
- if (!sub.inProgress) {
54
- runSubscription(sub);
55
- }
56
- return close;
7
+ registerQuery(q);
8
+ return q.db.hooks.subscribe(q, onData, onError);
57
9
  };
10
+ export * from './types.js';
58
11
  //# sourceMappingURL=index.js.map
@@ -1,33 +1,5 @@
1
1
  import { BasedQueryResponse } from '../BasedIterable.js';
2
- import { BasedDbQuery } from '../BasedDbQuery.js';
3
2
  export type OnData = (res: BasedQueryResponse) => any;
4
3
  export type OnError = (err: Error) => any;
5
- export type OnClose = () => BasedDbQuery;
4
+ export type OnClose = () => any;
6
5
  export type OnSubscription = (res: any, err?: Error) => void;
7
- export type Subscription = {
8
- query: BasedDbQuery;
9
- subs: Set<OnSubscription>;
10
- res?: BasedQueryResponse;
11
- closed: boolean;
12
- inProgress: boolean;
13
- };
14
- export type SubscriptionsMap = Map<number, Subscription>;
15
- export type SubscriptionsToRun = Subscription[];
16
- export type SubscriptionMarkers = {
17
- main: {
18
- [start: string]: Subscription[];
19
- };
20
- props: {
21
- [prop: string]: Subscription[];
22
- };
23
- };
24
- export type SubscriptionMarkerMap = {
25
- [typeID: string]: {
26
- ids: Map<number, SubscriptionMarkers>;
27
- collection: SubscriptionMarkers;
28
- };
29
- };
30
- export type SubscriptionMarkersCheck = {
31
- collection: SubscriptionMarkers | false;
32
- ids: SubscriptionMarkers | false;
33
- };
@@ -1,3 +1,10 @@
1
1
  export {};
2
- // has sub
2
+ // export type Subscription = {
3
+ // query: BasedDbQuery
4
+ // subs: Set<OnSubscription>
5
+ // res?: BasedQueryResponse
6
+ // closed: boolean
7
+ // inProgress: boolean // dont need to check
8
+ // // filter - realy nice to add
9
+ // }
3
10
  //# sourceMappingURL=types.js.map
@@ -10,7 +10,7 @@ export const write = (buf, value, offset, noCompression, lang) => {
10
10
  buf[offset] = lang || 0;
11
11
  const { written: l } = ENCODER.encodeInto(value, buf.subarray(offset + 2));
12
12
  let crc = native.crc32(buf.subarray(offset + 2, offset + 2 + l));
13
- // 50 maybe if lvl 1
13
+ // 50 len maybe if lvl 1
14
14
  if (value.length > 200 && !noCompression) {
15
15
  buf.copyWithin(offset + 6 + l, offset + 2, offset + 2 + l);
16
16
  const size = native.compress(buf, offset + 6, l);
package/dist/src/index.js CHANGED
@@ -4,6 +4,7 @@ import { DbServer } from './server/index.js';
4
4
  import { DbClient } from './client/index.js';
5
5
  import { wait } from '@saulx/utils';
6
6
  import { debugMode, debugServer } from './utils.js';
7
+ import { BasedQueryResponse } from './client/query/BasedIterable.js';
7
8
  export * from './client/modify/modify.js';
8
9
  export { compress, decompress };
9
10
  export { ModifyCtx }; // TODO move this somewhere
@@ -44,6 +45,33 @@ export class BasedDb {
44
45
  const client = new DbClient({
45
46
  maxModifySize,
46
47
  hooks: {
48
+ subscribe(q, onData, onError) {
49
+ let timer;
50
+ let prevChecksum;
51
+ let lastLen = 0;
52
+ let response;
53
+ const get = async () => {
54
+ const res = await server.getQueryBuf(q.buffer);
55
+ if (!response) {
56
+ response = new BasedQueryResponse(q.id, q.def, res, 0);
57
+ }
58
+ else {
59
+ response.result = res;
60
+ response.end = res.byteLength;
61
+ }
62
+ const checksum = response.checksum;
63
+ if (lastLen != res.byteLength || checksum != prevChecksum) {
64
+ onData(response);
65
+ lastLen = res.byteLength;
66
+ prevChecksum = checksum;
67
+ }
68
+ setTimeout(get, 200);
69
+ };
70
+ get();
71
+ return () => {
72
+ clearTimeout(timer);
73
+ };
74
+ },
47
75
  setSchema(schema, fromStart) {
48
76
  return Promise.resolve(server.setSchema(schema, fromStart));
49
77
  },
@@ -1,4 +1,4 @@
1
- declare const _default: {
1
+ declare const native: {
2
2
  historyAppend(history: any, typeId: number, nodeId: number, dbCtx: any): any;
3
3
  historyCreate(pathname: string, mainLen: number): any;
4
4
  workerCtxInit: () => void;
@@ -24,4 +24,4 @@ declare const _default: {
24
24
  equals: (a: Uint8Array, b: Uint8Array) => boolean;
25
25
  expire: (dbCtx: any) => void;
26
26
  };
27
- export default _default;
27
+ export default native;
@@ -11,7 +11,7 @@ function SelvaIoErrlogToString(buf) {
11
11
  let len = (i = buf.indexOf(0)) >= 0 ? i : buf.byteLength;
12
12
  return DECODER.decode(selvaIoErrlog.slice(0, len));
13
13
  }
14
- export default {
14
+ const native = {
15
15
  historyAppend(history, typeId, nodeId, dbCtx) {
16
16
  return db.historyAppend(history, typeId, nodeId, dbCtx);
17
17
  },
@@ -97,4 +97,6 @@ export default {
97
97
  db.expire(dbCtx);
98
98
  },
99
99
  };
100
+ global.__basedDb__native__ = native;
101
+ export default native;
100
102
  //# sourceMappingURL=native.js.map
@@ -12,9 +12,8 @@ function saveRange(db, typeId, start, end, hashOut) {
12
12
  const file = block_sdb_file(typeId, start, end);
13
13
  const path = join(db.fileSystemPath, file);
14
14
  const err = native.saveRange(path, typeId, start, end, db.dbCtxExternal, hashOut);
15
- if (err == -8) {
16
- // TODO ENOENT
17
- return '';
15
+ if (err == -8) { // TODO ENOENT
16
+ return ''; // empty range
18
17
  }
19
18
  else if (err) {
20
19
  // TODO print the error string
@@ -61,18 +60,16 @@ export function save(db, sync = false, forceFullDump = false) {
61
60
  else {
62
61
  foreachDirtyBlock(db, (mtKey, typeId, start, end) => {
63
62
  const hash = new Uint8Array(16);
64
- // TODO Don't save if empty
65
63
  const file = saveRange(db, typeId, start, end, hash);
66
64
  if (file === null) {
67
65
  // The previous state should remain in the merkle tree for
68
66
  // load and sync purposes.
69
67
  return;
70
68
  }
71
- else if (file.length === 0) {
72
- // The range is empty
73
- }
74
69
  else {
75
70
  const oldLeaf = db.merkleTree.search(mtKey);
71
+ // If (file.length === 0) then the range is empty but that's fine,
72
+ // we'll keep them around for now to maintain the order of the tree.
76
73
  if (oldLeaf) {
77
74
  oldLeaf.data.file = file;
78
75
  db.merkleTree.update(mtKey, hash);
@@ -36,11 +36,13 @@ export async function start(db, opts) {
36
36
  const dumps = writelog.rangeDumps[typeId];
37
37
  for (const dump of dumps) {
38
38
  const fname = dump.file;
39
- try {
40
- native.loadRange(join(path, fname), db.dbCtxExternal);
41
- }
42
- catch (e) {
43
- console.error(e.message);
39
+ if (fname?.length > 0) {
40
+ try {
41
+ native.loadRange(join(path, fname), db.dbCtxExternal);
42
+ }
43
+ catch (e) {
44
+ console.error(e.message);
45
+ }
44
46
  }
45
47
  }
46
48
  }
@@ -71,7 +73,7 @@ export async function start(db, opts) {
71
73
  end,
72
74
  };
73
75
  db.merkleTree.insert(mtKey, hash, data);
74
- });
76
+ }, true);
75
77
  }
76
78
  if (writelog?.hash) {
77
79
  const oldHash = hexToBuf(writelog.hash);
@@ -11,5 +11,5 @@ export declare const destructureCsmtKey: (key: number) => number[];
11
11
  export declare const makeCsmtKey: (typeId: number, start: number) => number;
12
12
  export declare const makeCsmtKeyFromNodeId: (typeId: number, blockCapacity: number, nodeId: number) => number;
13
13
  export declare function initCsmt(db: DbServer): {};
14
- export declare function foreachBlock(db: DbServer, def: SchemaTypeDef, cb: (start: number, end: number, hash: Uint8Array) => void): void;
14
+ export declare function foreachBlock(db: DbServer, def: SchemaTypeDef, cb: (start: number, end: number, hash: Uint8Array) => void, includeEmptyBlocks?: boolean): void;
15
15
  export declare function foreachDirtyBlock(db: DbServer, cb: (mtKey: number, typeId: number, start: number, end: number) => void): Promise<void>;
@@ -38,13 +38,13 @@ export function initCsmt(db) {
38
38
  }
39
39
  return types;
40
40
  }
41
- export function foreachBlock(db, def, cb) {
41
+ export function foreachBlock(db, def, cb, includeEmptyBlocks = false) {
42
42
  const step = def.blockCapacity;
43
43
  for (let start = 1; start <= def.lastId; start += step) {
44
44
  const end = start + step - 1;
45
45
  const hash = new Uint8Array(16);
46
46
  const res = native.getNodeRangeHash(def.id, start, end, hash, db.dbCtxExternal);
47
- if (res) {
47
+ if (res || includeEmptyBlocks) {
48
48
  cb(start, end, hash);
49
49
  }
50
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@based/db",
3
- "version": "0.0.29",
3
+ "version": "0.0.31",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",