@based/db 0.1.5 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/lib/darwin_aarch64/include/cdefs.h +4 -0
  2. package/dist/lib/darwin_aarch64/include/selva/db.h +25 -5
  3. package/dist/lib/darwin_aarch64/include/selva/fields.h +34 -72
  4. package/dist/lib/darwin_aarch64/include/selva/selva_lang.h +7 -0
  5. package/dist/lib/darwin_aarch64/include/selva/types.h +9 -13
  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/libnode-v24.node +0 -0
  9. package/dist/lib/darwin_aarch64/libnode-v25.node +0 -0
  10. package/dist/lib/darwin_aarch64/libselva.dylib +0 -0
  11. package/dist/lib/linux_aarch64/include/cdefs.h +4 -0
  12. package/dist/lib/linux_aarch64/include/selva/db.h +25 -5
  13. package/dist/lib/linux_aarch64/include/selva/fields.h +34 -72
  14. package/dist/lib/linux_aarch64/include/selva/selva_lang.h +7 -0
  15. package/dist/lib/linux_aarch64/include/selva/types.h +9 -13
  16. package/dist/lib/linux_aarch64/libdeflate.so +0 -0
  17. package/dist/lib/linux_aarch64/libnode-v22.node +0 -0
  18. package/dist/lib/linux_aarch64/libnode-v23.node +0 -0
  19. package/dist/lib/linux_aarch64/libnode-v24.node +0 -0
  20. package/dist/lib/linux_aarch64/libnode-v25.node +0 -0
  21. package/dist/lib/linux_aarch64/libselva.so +0 -0
  22. package/dist/lib/linux_x86_64/include/cdefs.h +4 -0
  23. package/dist/lib/linux_x86_64/include/selva/db.h +25 -5
  24. package/dist/lib/linux_x86_64/include/selva/fields.h +34 -72
  25. package/dist/lib/linux_x86_64/include/selva/selva_lang.h +7 -0
  26. package/dist/lib/linux_x86_64/include/selva/types.h +9 -13
  27. package/dist/lib/linux_x86_64/libdeflate.so +0 -0
  28. package/dist/lib/linux_x86_64/libnode-v22.node +0 -0
  29. package/dist/lib/linux_x86_64/libnode-v23.node +0 -0
  30. package/dist/lib/linux_x86_64/libnode-v24.node +0 -0
  31. package/dist/lib/linux_x86_64/libnode-v25.node +0 -0
  32. package/dist/lib/linux_x86_64/libselva.so +0 -0
  33. package/dist/src/client/modify/Tmp.d.ts +0 -1
  34. package/dist/src/client/modify/Tmp.js +14 -9
  35. package/dist/src/client/modify/create/index.js +6 -5
  36. package/dist/src/client/modify/drain.js +6 -2
  37. package/dist/src/client/modify/edges/binary.js +3 -2
  38. package/dist/src/client/modify/edges/reference.js +2 -3
  39. package/dist/src/client/modify/edges/references.js +2 -3
  40. package/dist/src/client/modify/edges/separate.js +4 -1
  41. package/dist/src/client/modify/edges/string.js +2 -3
  42. package/dist/src/client/modify/error.d.ts +29 -0
  43. package/dist/src/client/modify/error.js +10 -0
  44. package/dist/src/client/modify/props/alias.js +1 -1
  45. package/dist/src/client/modify/props/binary.js +1 -1
  46. package/dist/src/client/modify/props/cardinality.js +1 -1
  47. package/dist/src/client/modify/props/fixed.js +13 -14
  48. package/dist/src/client/modify/props/reference.js +2 -2
  49. package/dist/src/client/modify/props/references.js +7 -7
  50. package/dist/src/client/modify/props/string.js +1 -1
  51. package/dist/src/client/modify/props/vector.js +1 -11
  52. package/dist/src/client/modify/types.d.ts +1 -0
  53. package/dist/src/client/modify/types.js +1 -0
  54. package/dist/src/client/modify/validate.d.ts +1 -1
  55. package/dist/src/client/modify/validate.js +4 -3
  56. package/dist/src/client/query/BasedDbQuery.d.ts +4 -4
  57. package/dist/src/client/query/BasedDbQuery.js +23 -12
  58. package/dist/src/client/query/BasedQueryResponse.d.ts +0 -1
  59. package/dist/src/client/query/BasedQueryResponse.js +0 -3
  60. package/dist/src/client/query/aggregates/aggregation.d.ts +1 -1
  61. package/dist/src/client/query/aggregates/aggregation.js +123 -51
  62. package/dist/src/client/query/display.js +14 -8
  63. package/dist/src/client/query/filter/createFixedFilterBuffer.js +59 -22
  64. package/dist/src/client/query/filter/createReferenceFilter.js +13 -13
  65. package/dist/src/client/query/filter/createVariableFilterBuffer.js +6 -3
  66. package/dist/src/client/query/filter/filter.js +8 -0
  67. package/dist/src/client/query/filter/primitiveFilter.js +4 -1
  68. package/dist/src/client/query/filter/{toBuffer.d.ts → toByteCode.d.ts} +3 -2
  69. package/dist/src/client/query/filter/{toBuffer.js → toByteCode.js} +46 -12
  70. package/dist/src/client/query/filter/types.d.ts +2 -1
  71. package/dist/src/client/query/filter/types.js +33 -5
  72. package/dist/src/client/query/include/toByteCode.d.ts +2 -2
  73. package/dist/src/client/query/include/toByteCode.js +1 -1
  74. package/dist/src/client/query/query.d.ts +1 -1
  75. package/dist/src/client/query/query.js +1 -1
  76. package/dist/src/client/query/queryDef.js +6 -2
  77. package/dist/src/client/query/registerQuery.js +5 -9
  78. package/dist/src/client/query/subscription/index.js +5 -0
  79. package/dist/src/client/query/subscription/toByteCode.d.ts +6 -0
  80. package/dist/src/client/query/subscription/toByteCode.js +139 -0
  81. package/dist/src/client/query/subscription/types.d.ts +6 -0
  82. package/dist/src/client/query/subscription/types.js +7 -9
  83. package/dist/src/client/query/toByteCode/aggregates.d.ts +2 -0
  84. package/dist/src/client/query/toByteCode/aggregates.js +60 -0
  85. package/dist/src/client/query/toByteCode/alias.d.ts +2 -0
  86. package/dist/src/client/query/toByteCode/alias.js +24 -0
  87. package/dist/src/client/query/toByteCode/default.d.ts +2 -2
  88. package/dist/src/client/query/toByteCode/default.js +21 -24
  89. package/dist/src/client/query/toByteCode/id.d.ts +2 -0
  90. package/dist/src/client/query/toByteCode/id.js +17 -0
  91. package/dist/src/client/query/toByteCode/ids.d.ts +2 -0
  92. package/dist/src/client/query/toByteCode/ids.js +52 -0
  93. package/dist/src/client/query/toByteCode/offsets.d.ts +35 -0
  94. package/dist/src/client/query/toByteCode/offsets.js +36 -0
  95. package/dist/src/client/query/toByteCode/reference.d.ts +2 -0
  96. package/dist/src/client/query/toByteCode/reference.js +12 -0
  97. package/dist/src/client/query/toByteCode/references.d.ts +2 -0
  98. package/dist/src/client/query/toByteCode/references.js +35 -0
  99. package/dist/src/client/query/toByteCode/toByteCode.d.ts +4 -2
  100. package/dist/src/client/query/toByteCode/toByteCode.js +62 -189
  101. package/dist/src/client/query/types.d.ts +24 -5
  102. package/dist/src/client/query/validation.d.ts +5 -1
  103. package/dist/src/client/query/validation.js +15 -3
  104. package/dist/src/client/string.js +1 -1
  105. package/dist/src/hooks.js +2 -29
  106. package/dist/src/index.d.ts +1 -0
  107. package/dist/src/index.js +1 -0
  108. package/dist/src/native.d.ts +8 -1
  109. package/dist/src/native.js +23 -2
  110. package/dist/src/server/index.d.ts +2 -0
  111. package/dist/src/server/index.js +11 -2
  112. package/dist/src/server/schema.js +3 -2
  113. package/dist/src/server/schemaSelvaBuffer.d.ts +4 -0
  114. package/dist/src/server/schemaSelvaBuffer.js +182 -0
  115. package/dist/src/server/subscription.d.ts +32 -0
  116. package/dist/src/server/subscription.js +288 -0
  117. package/dist/src/utils.js +2 -3
  118. package/package.json +5 -6
@@ -5,7 +5,6 @@ import { ID_FIELD_DEF } from '@based/schema/def';
5
5
  import { start } from './start.js';
6
6
  import { destructureTreeKey, makeTreeKeyFromNodeId } from './tree.js';
7
7
  import { save } from './save.js';
8
- import { setTimeout } from 'node:timers/promises';
9
8
  import { migrate } from './migrate/index.js';
10
9
  import { debugServer } from '../utils.js';
11
10
  import { readUint16, readUint64 } from '@based/utils';
@@ -27,6 +26,15 @@ class SortIndex {
27
26
  export class DbServer extends DbShared {
28
27
  modifyDirtyRanges;
29
28
  dbCtxExternal; // pointer to zig dbCtx
29
+ subscriptions = {
30
+ subInterval: 200,
31
+ active: 0,
32
+ updateHandler: null,
33
+ ids: new Map(),
34
+ fullType: new Map(),
35
+ updateId: 1,
36
+ now: { listeners: new Set(), lastUpdated: 1 },
37
+ };
30
38
  migrating = null;
31
39
  saveInProgress = false;
32
40
  fileSystemPath;
@@ -382,6 +390,8 @@ export class DbServer extends DbShared {
382
390
  if (this.stopped) {
383
391
  return;
384
392
  }
393
+ clearTimeout(this.subscriptions.updateHandler);
394
+ this.subscriptions.updateHandler = null;
385
395
  this.stopped = true;
386
396
  this.unlistenExit();
387
397
  if (this.cleanupTimer) {
@@ -402,7 +412,6 @@ export class DbServer extends DbShared {
402
412
  this.workers = [];
403
413
  native.stop(this.dbCtxExternal);
404
414
  this.dbCtxExternal = null;
405
- await setTimeout(100);
406
415
  }
407
416
  catch (e) {
408
417
  this.stopped = false;
@@ -1,4 +1,4 @@
1
- import { schemaToSelvaBuffer, updateTypeDefs } from '@based/schema/def';
1
+ import { updateTypeDefs } from '@based/schema/def';
2
2
  import { serialize } from '@based/schema';
3
3
  import { join } from 'node:path';
4
4
  import { writeFile } from 'node:fs/promises';
@@ -8,6 +8,7 @@ import { saveSync } from './save.js';
8
8
  import { writeCreate } from '../client/modify/create/index.js';
9
9
  import { Ctx } from '../client/modify/Ctx.js';
10
10
  import { consume } from '../client/modify/drain.js';
11
+ import { schemaToSelvaBuffer } from './schemaSelvaBuffer.js';
11
12
  export const setSchemaOnServer = (server, schema) => {
12
13
  const { schemaTypesParsed, schemaTypesParsedById } = updateTypeDefs(schema);
13
14
  server.schema = schema;
@@ -40,7 +41,7 @@ export const setNativeSchema = (server, schema) => {
40
41
  const type = server.schemaTypesParsed[types[i]];
41
42
  maxTid = Math.max(maxTid, type.id);
42
43
  try {
43
- native.setSchemaType(type.id, new Uint8Array(s[i]), server.dbCtxExternal);
44
+ native.setSchemaType(server.dbCtxExternal, type.id, new Uint8Array(s[i]));
44
45
  }
45
46
  catch (err) {
46
47
  throw new Error(`Cannot update schema on selva (native) ${type.type} ${err.message}`);
@@ -0,0 +1,4 @@
1
+ import { SchemaTypeDef } from '@based/schema/def';
2
+ export declare function schemaToSelvaBuffer(schema: {
3
+ [key: string]: SchemaTypeDef;
4
+ }): ArrayBuffer[];
@@ -0,0 +1,182 @@
1
+ import { ENCODER, writeDoubleLE, writeUint16, writeUint32, writeUint64 } from '@based/utils';
2
+ import { ALIAS, ALIASES, BINARY, EMPTY_MICRO_BUFFER, CARDINALITY, MICRO_BUFFER, REFERENCE, REFERENCES, STRING, TEXT, VECTOR, JSON, COLVEC, VECTOR_BASE_TYPE_SIZE_MAP, INT8, UINT8, BOOLEAN, INT16, UINT16, INT32, UINT32, NUMBER, TIMESTAMP, ENUM, } from '@based/schema/def';
3
+ import { NOT_COMPRESSED } from '@based/protocol';
4
+ import native from '../native.js';
5
+ const selvaFieldType = {
6
+ NULL: 0,
7
+ MICRO_BUFFER: 1,
8
+ STRING: 2,
9
+ TEXT: 3,
10
+ REFERENCE: 4,
11
+ REFERENCES: 5,
12
+ ALIAS: 8,
13
+ ALIASES: 9,
14
+ COLVEC: 10,
15
+ };
16
+ const selvaTypeMap = new Uint8Array(32); // 1.2x faster than JS array
17
+ selvaTypeMap[MICRO_BUFFER] = selvaFieldType.MICRO_BUFFER;
18
+ selvaTypeMap[VECTOR] = selvaFieldType.MICRO_BUFFER;
19
+ selvaTypeMap[BINARY] = selvaFieldType.STRING;
20
+ selvaTypeMap[CARDINALITY] = selvaFieldType.STRING;
21
+ selvaTypeMap[JSON] = selvaFieldType.STRING;
22
+ selvaTypeMap[STRING] = selvaFieldType.STRING;
23
+ selvaTypeMap[TEXT] = selvaFieldType.TEXT;
24
+ selvaTypeMap[REFERENCE] = selvaFieldType.REFERENCE;
25
+ selvaTypeMap[REFERENCES] = selvaFieldType.REFERENCES;
26
+ selvaTypeMap[ALIAS] = selvaFieldType.ALIAS;
27
+ selvaTypeMap[ALIASES] = selvaFieldType.ALIASES;
28
+ selvaTypeMap[COLVEC] = selvaFieldType.COLVEC;
29
+ const EDGE_FIELD_CONSTRAINT_FLAG_DEPENDENT = 0x01;
30
+ function blockCapacity(blockCapacity) {
31
+ const buf = new Uint8Array(Uint32Array.BYTES_PER_ELEMENT);
32
+ const view = new DataView(buf.buffer);
33
+ view.setUint32(0, blockCapacity, true);
34
+ return buf;
35
+ }
36
+ function sepPropCount(props) {
37
+ return props.filter((prop) => prop.separate).length;
38
+ }
39
+ function makeEdgeConstraintFlags(prop) {
40
+ let flags = 0;
41
+ flags |= prop.dependent ? EDGE_FIELD_CONSTRAINT_FLAG_DEPENDENT : 0x00;
42
+ return flags;
43
+ }
44
+ const propDefBuffer = (schema, prop) => {
45
+ const type = prop.typeIndex;
46
+ const selvaType = selvaTypeMap[type];
47
+ if (prop.len && (type === MICRO_BUFFER || type === VECTOR)) {
48
+ const buf = new Uint8Array(4);
49
+ const view = new DataView(buf.buffer);
50
+ buf[0] = selvaType;
51
+ view.setUint16(1, prop.len, true);
52
+ if (prop.default) {
53
+ buf[3] = 1; // has default
54
+ return [...buf, ...prop.default];
55
+ }
56
+ else {
57
+ buf[3] = 0; // has default
58
+ return [...buf];
59
+ }
60
+ }
61
+ else if (prop.len && type === COLVEC) {
62
+ const buf = new Uint8Array(5);
63
+ const view = new DataView(buf.buffer);
64
+ buf[0] = selvaType;
65
+ const baseSize = VECTOR_BASE_TYPE_SIZE_MAP[prop.vectorBaseType];
66
+ view.setUint16(1, prop.len / baseSize, true); // elements
67
+ view.setUint16(3, baseSize, true); // element size
68
+ return [...buf];
69
+ }
70
+ else if (type === REFERENCE || type === REFERENCES) {
71
+ const buf = new Uint8Array(7);
72
+ const view = new DataView(buf.buffer);
73
+ const dstType = schema[prop.inverseTypeName];
74
+ buf[0] = selvaType; // field type
75
+ buf[1] = makeEdgeConstraintFlags(prop); // flags
76
+ view.setUint16(2, dstType.id, true); // dst_node_type
77
+ buf[4] = prop.inversePropNumber; // inverse_field
78
+ view.setUint16(5, prop.edgeNodeTypeId ?? 0, true); // meta_node_type
79
+ return [...buf];
80
+ }
81
+ else if (type === STRING ||
82
+ type === BINARY ||
83
+ type === CARDINALITY ||
84
+ type === JSON) {
85
+ return [selvaType, prop.len < 50 ? prop.len : 0];
86
+ }
87
+ {
88
+ return [selvaType];
89
+ }
90
+ };
91
+ // TODO rewrite
92
+ export function schemaToSelvaBuffer(schema) {
93
+ return Object.values(schema).map((t) => {
94
+ const props = Object.values(t.props);
95
+ const rest = [];
96
+ const nrFields = 1 + sepPropCount(props);
97
+ let refFields = 0;
98
+ let virtualFields = 0;
99
+ if (nrFields >= 250) {
100
+ throw new Error('Too many fields');
101
+ }
102
+ const main = {
103
+ ...EMPTY_MICRO_BUFFER,
104
+ len: t.mainLen === 0 ? 1 : t.mainLen,
105
+ };
106
+ for (const f of props) {
107
+ if (f.separate) {
108
+ if (f.typeIndex === REFERENCE || f.typeIndex === REFERENCES) {
109
+ refFields++;
110
+ }
111
+ else if (f.typeIndex === ALIAS ||
112
+ f.typeIndex === ALIASES ||
113
+ f.typeIndex === COLVEC) {
114
+ // We assume that these are always the last props!
115
+ virtualFields++;
116
+ }
117
+ rest.push(f);
118
+ }
119
+ else {
120
+ if (f.default) {
121
+ if (!main.default) {
122
+ main.default = new Uint8Array(main.len);
123
+ }
124
+ const buf = main.default;
125
+ switch (f.typeIndex) {
126
+ case INT8:
127
+ case UINT8:
128
+ case BOOLEAN:
129
+ case ENUM:
130
+ main.default[f.start] = f.default;
131
+ break;
132
+ case INT16:
133
+ case UINT16:
134
+ writeUint16(buf, f.default, f.start);
135
+ break;
136
+ case INT32:
137
+ case UINT32:
138
+ writeUint32(buf, f.default, f.start);
139
+ break;
140
+ case NUMBER:
141
+ writeDoubleLE(buf, f.default, f.start);
142
+ //const view = new DataView(
143
+ // buf.buffer,
144
+ // f.start,
145
+ // 8,
146
+ //)
147
+ //view.setFloat64(0, f.default, true)
148
+ break;
149
+ case TIMESTAMP:
150
+ writeUint64(buf, f.default, f.start);
151
+ break;
152
+ case BINARY:
153
+ case STRING:
154
+ if (f.default instanceof Uint8Array) {
155
+ buf.set(f.default, f.start);
156
+ }
157
+ else {
158
+ const value = f.default.normalize('NFKD');
159
+ buf[f.start] = 0; // lang
160
+ buf[f.start + 1] = NOT_COMPRESSED;
161
+ const { written: l } = ENCODER.encodeInto(value, buf.subarray(f.start + 2));
162
+ let crc = native.crc32(buf.subarray(f.start + 2, f.start + 2 + l));
163
+ writeUint32(buf, crc, f.start + 2 + l);
164
+ }
165
+ break;
166
+ }
167
+ }
168
+ }
169
+ }
170
+ rest.sort((a, b) => a.prop - b.prop);
171
+ return Uint8Array.from([
172
+ ...blockCapacity(t.blockCapacity), // u32 blockCapacity
173
+ nrFields, // u8 nrFields
174
+ 1 + refFields, // u8 nrFixedFields
175
+ virtualFields, // u8 nrVirtualFields
176
+ 6, // u8 version (generally follows the sdb version)
177
+ ...propDefBuffer(schema, main),
178
+ ...rest.map((f) => propDefBuffer(schema, f)).flat(1),
179
+ ]).buffer;
180
+ });
181
+ }
182
+ //# sourceMappingURL=schemaSelvaBuffer.js.map
@@ -0,0 +1,32 @@
1
+ import { OnError } from '../client/query/subscription/types.js';
2
+ import { DbServer } from '../index.js';
3
+ type OnData = (res: Uint8Array) => void;
4
+ export type SubscriptionFullType = {
5
+ listeners: Set<() => void>;
6
+ };
7
+ export type SubscriptionNow = {
8
+ lastEval: number;
9
+ next: number;
10
+ listeners: Set<() => void>;
11
+ };
12
+ export type SubscriptionId = {
13
+ types?: Uint16Array;
14
+ ids: Map<number, Set<() => void>>;
15
+ typesListener?: () => void;
16
+ nowListener?: () => void;
17
+ };
18
+ export type Subscriptions = {
19
+ updateId: number;
20
+ active: number;
21
+ updateHandler: ReturnType<typeof setTimeout>;
22
+ ids: Map<number, SubscriptionId>;
23
+ fullType: Map<number, SubscriptionFullType>;
24
+ now: {
25
+ listeners: Set<() => void>;
26
+ lastUpdated: number;
27
+ };
28
+ subInterval: number;
29
+ };
30
+ export declare const startUpdateHandler: (server: DbServer) => void;
31
+ export declare const registerSubscription: (server: DbServer, query: Uint8Array, sub: Uint8Array, onData: OnData, onError: OnError, subInterval?: number) => () => void;
32
+ export {};
@@ -0,0 +1,288 @@
1
+ import { readInt64, readUint16, readUint32, writeInt64 } from '@based/utils';
2
+ import { SubscriptionType, } from '../client/query/subscription/types.js';
3
+ import native from '../native.js';
4
+ import { MAX_ID } from '@based/schema';
5
+ import { styleText } from 'util';
6
+ export const startUpdateHandler = (server) => {
7
+ // skip next if queries are sitll in progress can add a number for each staged sub
8
+ // combine this with handled modify
9
+ const scheduleUpdate = () => {
10
+ if (server.stopped) {
11
+ return;
12
+ }
13
+ server.subscriptions.updateId++;
14
+ if (server.subscriptions.updateId > MAX_ID) {
15
+ server.subscriptions.updateId = 1;
16
+ }
17
+ // can do seperate timing for id / type
18
+ // scince multi queries are much heavier ofc
19
+ const markedIdSubs = native.getMarkedIdSubscriptions(server.dbCtxExternal);
20
+ if (markedIdSubs) {
21
+ const buffer = new Uint8Array(markedIdSubs);
22
+ for (let i = 0; i < buffer.byteLength; i += 8) {
23
+ const id = readUint32(buffer, i);
24
+ const subId = readUint32(buffer, i + 4);
25
+ const subContainer = server.subscriptions.ids.get(subId);
26
+ const ids = subContainer.ids.get(id);
27
+ if (ids) {
28
+ for (const fn of ids) {
29
+ fn();
30
+ }
31
+ }
32
+ }
33
+ }
34
+ const markedMultiSubs = native.getMarkedMultiSubscriptions(server.dbCtxExternal);
35
+ if (markedMultiSubs) {
36
+ const buffer = new Uint8Array(markedMultiSubs);
37
+ for (let i = 0; i < buffer.byteLength; i += 2) {
38
+ const typeId = readUint16(buffer, i);
39
+ const subs = server.subscriptions.fullType.get(typeId);
40
+ if (subs) {
41
+ for (const fn of subs.listeners) {
42
+ fn();
43
+ }
44
+ }
45
+ }
46
+ }
47
+ if (server.subscriptions.updateId - server.subscriptions.now.lastUpdated >
48
+ Math.max(1000 / server.subscriptions.subInterval, 1) // 1 time per second
49
+ ) {
50
+ server.subscriptions.now.lastUpdated = server.subscriptions.updateId;
51
+ for (const fn of server.subscriptions.now.listeners) {
52
+ fn();
53
+ }
54
+ }
55
+ server.subscriptions.updateHandler = setTimeout(scheduleUpdate, server.subscriptions.subInterval);
56
+ };
57
+ server.subscriptions.updateHandler = setTimeout(scheduleUpdate, server.subscriptions.subInterval);
58
+ };
59
+ const addToMultiSub = (server, typeId, runQuery) => {
60
+ let fullType;
61
+ let listeners;
62
+ if (!server.subscriptions.fullType.has(typeId)) {
63
+ listeners = new Set();
64
+ fullType = {
65
+ listeners,
66
+ };
67
+ server.subscriptions.fullType.set(typeId, fullType);
68
+ native.addMultiSubscription(server.dbCtxExternal, typeId);
69
+ }
70
+ else {
71
+ fullType = server.subscriptions.fullType.get(typeId);
72
+ listeners = fullType.listeners;
73
+ }
74
+ listeners.add(runQuery);
75
+ };
76
+ const removeFromMultiSub = (server, typeId, runQuery) => {
77
+ const typeSub = server.subscriptions.fullType.get(typeId);
78
+ if (!typeSub) {
79
+ return;
80
+ }
81
+ typeSub.listeners.delete(runQuery);
82
+ if (typeSub.listeners.size === 0) {
83
+ native.removeMultiSubscription(server.dbCtxExternal, typeId);
84
+ server.subscriptions.fullType.delete(typeId);
85
+ }
86
+ };
87
+ const replaceNowValues = (query, now) => {
88
+ const dateNow = Date.now();
89
+ for (let i = 0; i < now.byteLength; i += 16) {
90
+ const offset = readInt64(now, i + 4);
91
+ const byteIndex = readUint32(now, i + 12);
92
+ writeInt64(query, dateNow + offset, byteIndex);
93
+ }
94
+ };
95
+ let total = 0;
96
+ let exectime = 0;
97
+ let int;
98
+ export const registerSubscription = (server, query, sub, onData, onError, subInterval) => {
99
+ // this can change dynamicly
100
+ if (subInterval) {
101
+ server.subscriptions.subInterval = subInterval;
102
+ }
103
+ if (!int)
104
+ int = setInterval(() => {
105
+ console.log('EXECED', total, exectime / total, 'ms exec time');
106
+ if (server.stopped) {
107
+ clearInterval(int);
108
+ }
109
+ }, 1e3);
110
+ let killed = false;
111
+ // now maybe just once per second? (for now)
112
+ if (server.subscriptions.active === 0) {
113
+ startUpdateHandler(server);
114
+ }
115
+ let lastUpdated = 0;
116
+ let now;
117
+ const runQuery = () => {
118
+ if (lastUpdated !== server.subscriptions.updateId) {
119
+ lastUpdated = server.subscriptions.updateId;
120
+ if (now) {
121
+ replaceNowValues(query, now);
122
+ }
123
+ let d = Date.now();
124
+ server.getQueryBuf(query).then((res) => {
125
+ if (killed) {
126
+ return;
127
+ }
128
+ total++;
129
+ exectime += Date.now() - d;
130
+ if (res.byteLength >= 4) {
131
+ onData(res);
132
+ }
133
+ else if (res.byteLength === 1 && res[0] === 0) {
134
+ server.emit('info', `Subscribe schema mismatch - should resolve after update`);
135
+ return;
136
+ }
137
+ else {
138
+ let name = styleText('red', `QueryError[]\n`);
139
+ name += ` Incorrect buffer received in subscription (maybe server not started ${res.byteLength}) bytes\n`;
140
+ onError(new Error(name));
141
+ }
142
+ });
143
+ }
144
+ else {
145
+ // console.log('Allready fired block')
146
+ }
147
+ };
148
+ server.subscriptions.active++;
149
+ if (sub[0] === SubscriptionType.singleId) {
150
+ const subId = readUint32(sub, 1);
151
+ const id = readUint32(sub, 7);
152
+ const headerLen = 16;
153
+ let subContainer;
154
+ let listeners;
155
+ if (!server.subscriptions.ids.get(subId)) {
156
+ subContainer = { ids: new Map() };
157
+ server.subscriptions.ids.set(subId, subContainer);
158
+ const typesLen = readUint16(sub, 12);
159
+ const nowLen = readUint16(sub, 14);
160
+ const fLen = sub[11];
161
+ if (typesLen != 0) {
162
+ // double check if this is alignment correct with the byteOffset else copy
163
+ const byteOffset = sub.byteOffset + headerLen + fLen;
164
+ if (byteOffset % 2 === 0) {
165
+ subContainer.types = new Uint16Array(sub.buffer, byteOffset, typesLen);
166
+ }
167
+ else {
168
+ subContainer.types = new Uint16Array(sub.slice(headerLen + fLen, headerLen + fLen + typesLen * 2));
169
+ }
170
+ subContainer.typesListener = () => {
171
+ for (const set of subContainer.ids.values()) {
172
+ for (const fn of set) {
173
+ fn();
174
+ }
175
+ }
176
+ };
177
+ for (const typeId of subContainer.types) {
178
+ addToMultiSub(server, typeId, subContainer.typesListener);
179
+ }
180
+ }
181
+ if (nowLen != 0) {
182
+ // when this is the case do a completely different strategy
183
+ // keep track of last update on sub id container
184
+ // and get the date allways (as a seperate query)
185
+ // when getting the date mark next in line
186
+ // have to make a copy (subArray is weak)
187
+ now = sub.slice(headerLen + fLen + typesLen * 2);
188
+ subContainer.nowListener = () => {
189
+ // per id want to have a last eval and needs next eval
190
+ for (const set of subContainer.ids.values()) {
191
+ for (const fn of set) {
192
+ fn();
193
+ }
194
+ }
195
+ };
196
+ server.subscriptions.now.listeners.add(subContainer.nowListener);
197
+ }
198
+ }
199
+ else {
200
+ subContainer = server.subscriptions.ids.get(subId);
201
+ }
202
+ if (!subContainer.ids.has(id)) {
203
+ listeners = new Set();
204
+ subContainer.ids.set(id, listeners);
205
+ native.addIdSubscription(server.dbCtxExternal, sub);
206
+ }
207
+ else {
208
+ listeners = subContainer.ids.get(id);
209
+ }
210
+ listeners.add(runQuery);
211
+ process.nextTick(() => {
212
+ runQuery();
213
+ });
214
+ return () => {
215
+ killed = true;
216
+ listeners.delete(runQuery);
217
+ if (listeners.size === 0) {
218
+ native.removeIdSubscription(server.dbCtxExternal, sub);
219
+ subContainer.ids.delete(id);
220
+ }
221
+ if (subContainer.ids.size === 0) {
222
+ if (subContainer.types) {
223
+ for (const typeId of subContainer.types) {
224
+ removeFromMultiSub(server, typeId, subContainer.typesListener);
225
+ }
226
+ }
227
+ if (now) {
228
+ server.subscriptions.now.listeners.delete(subContainer.nowListener);
229
+ }
230
+ server.subscriptions.ids.delete(subId);
231
+ }
232
+ server.subscriptions.active--;
233
+ if (server.subscriptions.active === 0) {
234
+ clearTimeout(server.subscriptions.updateHandler);
235
+ server.subscriptions.updateHandler = null;
236
+ }
237
+ };
238
+ }
239
+ else if (sub[0] === SubscriptionType.fullType) {
240
+ const headerLen = 8;
241
+ const typeId = readUint16(sub, 1);
242
+ addToMultiSub(server, typeId, runQuery);
243
+ const typesLen = readUint16(sub, 3);
244
+ let types;
245
+ if (typesLen != 0) {
246
+ // double check if this is alignment correct with the byteOffset else copy
247
+ const byteOffset = sub.byteOffset + headerLen;
248
+ if (byteOffset % 2 === 0) {
249
+ types = new Uint16Array(sub.buffer, byteOffset, typesLen);
250
+ }
251
+ else {
252
+ types = new Uint16Array(sub.slice(headerLen, headerLen + typesLen * 2));
253
+ }
254
+ for (const typeId of types) {
255
+ addToMultiSub(server, typeId, runQuery);
256
+ }
257
+ }
258
+ if (readUint16(sub, 5) != 0) {
259
+ // have to make a copy (subArray is weak)
260
+ now = sub.slice(headerLen + typesLen * 2);
261
+ server.subscriptions.now.listeners.add(runQuery);
262
+ }
263
+ process.nextTick(() => {
264
+ runQuery();
265
+ });
266
+ return () => {
267
+ killed = true;
268
+ if (now) {
269
+ server.subscriptions.now.listeners.delete(runQuery);
270
+ }
271
+ removeFromMultiSub(server, typeId, runQuery);
272
+ if (types) {
273
+ for (const typeId of types) {
274
+ removeFromMultiSub(server, typeId, runQuery);
275
+ }
276
+ }
277
+ server.subscriptions.active--;
278
+ if (server.subscriptions.active === 0) {
279
+ clearTimeout(server.subscriptions.updateHandler);
280
+ server.subscriptions.updateHandler = null;
281
+ }
282
+ };
283
+ }
284
+ else {
285
+ throw new Error('Unhandled subscription!');
286
+ }
287
+ };
288
+ //# sourceMappingURL=subscription.js.map
package/dist/src/utils.js CHANGED
@@ -1,5 +1,4 @@
1
- import { inspect } from 'node:util';
2
- import picocolors from 'picocolors';
1
+ import { inspect, styleText } from 'node:util';
3
2
  export const debugMode = (target, getInfo = null) => {
4
3
  const opts = { showHidden: false, depth: null, colors: true };
5
4
  const info = (v) => (typeof v === 'object' ? inspect(v, opts) : v);
@@ -29,7 +28,7 @@ export const debugMode = (target, getInfo = null) => {
29
28
  let cnt = 0;
30
29
  const color = colors[colorKey++ % colors.length];
31
30
  target[key] = function () {
32
- const arr = [picocolors[color](`[${key}:${++cnt}]`)];
31
+ const arr = [styleText(color, `[${key}:${++cnt}]`)];
33
32
  const add = getInfo?.(key);
34
33
  if (add)
35
34
  arr.push(add);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@based/db",
3
- "version": "0.1.5",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "main": "./dist/src/index.js",
6
6
  "scripts": {
@@ -42,11 +42,10 @@
42
42
  ],
43
43
  "dependencies": {
44
44
  "@based/hash": "1.1.0",
45
- "@based/schema": "5.0.4",
46
- "@based/utils": "1.1.1",
47
- "@based/protocol": "0.0.5",
48
- "exit-hook": "^4.0.0",
49
- "picocolors": "^1.1.0"
45
+ "@based/schema": "5.1.1",
46
+ "@based/utils": "1.2.0",
47
+ "@based/protocol": "0.1.1",
48
+ "exit-hook": "^4.0.0"
50
49
  },
51
50
  "optionalDependencies": {
52
51
  "@based/locale-x86-64-gnu": "*"