@based/db 0.0.48 → 0.0.50

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.
Binary file
Binary file
@@ -10,7 +10,8 @@ import { deleteFn } from './modify/delete.js';
10
10
  import { wait } from '@saulx/utils';
11
11
  import { hash } from '@saulx/hash';
12
12
  import { expire } from './modify/expire.js';
13
- import { debugMode, schemaLooseEqual } from '../utils.js';
13
+ import { debugMode } from '../utils.js';
14
+ import { parseSchema, schemaLooseEqual } from '../schema.js';
14
15
  const makeFlushIsReady = (dbClient) => {
15
16
  dbClient.flushIsReady = new Promise((resolve) => {
16
17
  dbClient.flushReady = () => {
@@ -48,8 +49,9 @@ export class DbClient {
48
49
  schemaPromise;
49
50
  async setSchema(schema, fromStart, transformFns) {
50
51
  const strictSchema = fromStart ? schema : parse(schema).schema;
52
+ const parsedSchema = parseSchema(strictSchema);
51
53
  // this one excludes all the ids
52
- if (schemaLooseEqual(strictSchema, this.schema)) {
54
+ if (schemaLooseEqual(parsedSchema, this.schema)) {
53
55
  return this.schema;
54
56
  }
55
57
  // drain current things
@@ -1,7 +1,7 @@
1
1
  import { REFERENCES } from '@based/schema/def';
2
2
  import { ModifyError, ModifyState } from '../ModifyRes.js';
3
3
  import { setCursor } from '../setCursor.js';
4
- import { DELETE, EDGE_INDEX_REALID, EDGE_INDEX_TMPID, EDGE_NOINDEX_REALID, EDGE_NOINDEX_TMPID, NOEDGE_INDEX_REALID, NOEDGE_INDEX_TMPID, NOEDGE_NOINDEX_REALID, NOEDGE_NOINDEX_TMPID, RANGE_ERR, REF_OP_UPDATE, } from '../types.js';
4
+ import { DELETE, EDGE_INDEX_REALID, EDGE_INDEX_TMPID, EDGE_NOINDEX_REALID, EDGE_NOINDEX_TMPID, NOEDGE_INDEX_REALID, NOEDGE_INDEX_TMPID, NOEDGE_NOINDEX_REALID, NOEDGE_NOINDEX_TMPID, RANGE_ERR, REF_OP_OVERWRITE, REF_OP_PUT_ADD, REF_OP_PUT_OVERWRITE, REF_OP_UPDATE, } from '../types.js';
5
5
  import { writeEdges } from './edge.js';
6
6
  export function writeReferences(value, ctx, schema, def, res, mod) {
7
7
  if (typeof value !== 'object') {
@@ -266,8 +266,8 @@ function putRefs(def, ctx, modifyOp, refs, op) {
266
266
  ctx.buf[ctx.len++] = size >>>= 8;
267
267
  ctx.buf[ctx.len++] = size >>>= 8;
268
268
  ctx.buf[ctx.len++] = size >>>= 8;
269
- ctx.buf[ctx.len++] = op === 0 ? 3 : 4;
270
- ctx.len = (ctx.len + 3) & ~3;
269
+ ctx.buf[ctx.len++] =
270
+ op === REF_OP_OVERWRITE ? REF_OP_PUT_OVERWRITE : REF_OP_PUT_ADD;
271
271
  let i = 0;
272
272
  for (; i < refs.length; i++) {
273
273
  let ref = refs[i];
@@ -37,4 +37,6 @@ export declare const EDGE_INDEX_TMPID = 6;
37
37
  export declare const NOEDGE_INDEX_TMPID = 7;
38
38
  export declare const REF_OP_UPDATE = 1;
39
39
  export declare const REF_OP_OVERWRITE = 0;
40
+ export declare const REF_OP_PUT_OVERWRITE = 3;
41
+ export declare const REF_OP_PUT_ADD = 4;
40
42
  export type REF_OP = typeof REF_OP_OVERWRITE | typeof REF_OP_UPDATE;
@@ -25,4 +25,6 @@ export const EDGE_INDEX_TMPID = 6;
25
25
  export const NOEDGE_INDEX_TMPID = 7;
26
26
  export const REF_OP_UPDATE = 1;
27
27
  export const REF_OP_OVERWRITE = 0;
28
+ export const REF_OP_PUT_OVERWRITE = 3;
29
+ export const REF_OP_PUT_ADD = 4;
28
30
  //# sourceMappingURL=types.js.map
@@ -12,6 +12,8 @@ import { convertFilter } from './filter/convertFilter.js';
12
12
  import { validateLocale, validateRange } from './validation.js';
13
13
  import { DEF_RANGE_PROP_LIMIT } from './thresholds.js';
14
14
  import { concatUint8Arr } from '@saulx/utils';
15
+ import { displayTarget } from './display.js';
16
+ import picocolors from 'picocolors';
15
17
  export class QueryBranch {
16
18
  db;
17
19
  def;
@@ -325,6 +327,10 @@ export class BasedDbQuery extends QueryBranch {
325
327
  const res = await this.db.hooks.getQueryBuf(buf);
326
328
  if (res.byteLength === 1) {
327
329
  if (res[0] === 0) {
330
+ if (this.db.schema?.hash !== this.def.schemaChecksum) {
331
+ this.reBuildQuery();
332
+ return this.#getInternal(resolve, reject);
333
+ }
328
334
  reject(new Error('schema mismatch'));
329
335
  }
330
336
  else {
@@ -353,7 +359,19 @@ export class BasedDbQuery extends QueryBranch {
353
359
  return this;
354
360
  }
355
361
  subscribe(onData, onError) {
356
- return subscribe(this, onData, onError ??
362
+ return subscribe(this, (res) => {
363
+ try {
364
+ onData(res);
365
+ }
366
+ catch (err) {
367
+ // const t = displayTarget(this.def)
368
+ const def = this.def;
369
+ let name = picocolors.red(`QueryError[${displayTarget(def)}]\n`);
370
+ name += ` Error executing onData handler in subscription\n`;
371
+ name += ` ${err.message}\n`;
372
+ console.error(name);
373
+ }
374
+ }, onError ??
357
375
  ((err) => {
358
376
  console.error(err);
359
377
  }));
@@ -0,0 +1,3 @@
1
+ import { StrictSchema } from '@based/schema';
2
+ export declare const schemaLooseEqual: (a: any, b: any, key?: string) => boolean;
3
+ export declare const parseSchema: (strictSchema: StrictSchema) => StrictSchema;
@@ -0,0 +1,94 @@
1
+ import { getPropType } from '@based/schema';
2
+ const exclude = new Set(['id', 'lastId', 'hash']);
3
+ export const schemaLooseEqual = (a, b, key) => {
4
+ if (a === b) {
5
+ return true;
6
+ }
7
+ const typeofA = typeof a;
8
+ if (typeofA !== 'object') {
9
+ return exclude.has(key);
10
+ }
11
+ const typeofB = typeof b;
12
+ if (typeofA !== typeofB) {
13
+ return exclude.has(key);
14
+ }
15
+ if (a === null || b === null) {
16
+ return false;
17
+ }
18
+ if (a.constructor !== b.constructor) {
19
+ return false;
20
+ }
21
+ if (Array.isArray(a)) {
22
+ let i = a.length;
23
+ if (i !== b.length) {
24
+ return false;
25
+ }
26
+ while (i--) {
27
+ if (!schemaLooseEqual(a[i], b[i])) {
28
+ return false;
29
+ }
30
+ }
31
+ }
32
+ else {
33
+ for (const k in a) {
34
+ if (!schemaLooseEqual(a[k], b[k], k)) {
35
+ return false;
36
+ }
37
+ }
38
+ for (const k in b) {
39
+ if (k in a) {
40
+ continue;
41
+ }
42
+ if (!schemaLooseEqual(a[k], b[k], k)) {
43
+ return false;
44
+ }
45
+ }
46
+ }
47
+ return true;
48
+ };
49
+ export const parseSchema = (strictSchema) => {
50
+ let parsedSchema = strictSchema;
51
+ if (strictSchema.props) {
52
+ parsedSchema = {
53
+ ...strictSchema,
54
+ types: { ...parsedSchema.types },
55
+ };
56
+ const props = { ...strictSchema.props };
57
+ for (const key in props) {
58
+ const prop = props[key];
59
+ const propType = getPropType(prop);
60
+ let refProp;
61
+ if (propType === 'reference') {
62
+ refProp = prop;
63
+ }
64
+ else if (propType === 'references') {
65
+ refProp = prop.items;
66
+ }
67
+ if (refProp) {
68
+ const type = parsedSchema.types[refProp.ref];
69
+ const inverseKey = '_' + key;
70
+ parsedSchema.types[refProp.ref] = {
71
+ ...type,
72
+ props: {
73
+ ...type.props,
74
+ [inverseKey]: {
75
+ items: {
76
+ ref: '_root',
77
+ prop: key,
78
+ },
79
+ },
80
+ },
81
+ };
82
+ refProp.prop = inverseKey;
83
+ }
84
+ }
85
+ // @ts-ignore This creates an internal type to use for root props
86
+ parsedSchema.types._root = {
87
+ id: 1,
88
+ props,
89
+ };
90
+ delete parsedSchema.props;
91
+ }
92
+ return parsedSchema;
93
+ };
94
+ //# sourceMappingURL=schema.js.map
@@ -2,7 +2,7 @@ import native from '../native.js';
2
2
  import createDbHash from './dbHash.js';
3
3
  import { rm, writeFile } from 'node:fs/promises';
4
4
  import { dirname, join } from 'node:path';
5
- import { getPropType, langCodesMap, } from '@based/schema';
5
+ import { langCodesMap } from '@based/schema';
6
6
  import { updateTypeDefs, schemaToSelvaBuffer, } from '@based/schema/def';
7
7
  import { start } from './start.js';
8
8
  import { initCsmt, makeCsmtKey, makeCsmtKeyFromNodeId, } from './tree.js';
@@ -11,10 +11,11 @@ import { Worker, MessageChannel } from 'node:worker_threads';
11
11
  import { fileURLToPath } from 'node:url';
12
12
  import { setTimeout } from 'node:timers/promises';
13
13
  import { migrate } from './migrate/index.js';
14
- import { debugServer, schemaLooseEqual } from '../utils.js';
14
+ import { debugServer } from '../utils.js';
15
15
  import { readUint16, readUint32, readUint64, writeUint64 } from '@saulx/utils';
16
- import { hash } from '@saulx/hash';
17
16
  import { QueryType } from '../client/query/types.js';
17
+ import { parseSchema, schemaLooseEqual } from '../schema.js';
18
+ import { hash } from '@saulx/hash';
18
19
  export const SCHEMA_FILE = 'schema.json';
19
20
  export const WRITELOG_FILE = 'writelog.json';
20
21
  const __filename = fileURLToPath(import.meta.url);
@@ -281,64 +282,26 @@ export class DbServer {
281
282
  return sortIndex;
282
283
  }
283
284
  setSchema(strictSchema, fromStart = false, transformFns) {
285
+ const parsedSchema = parseSchema(strictSchema);
284
286
  if (!fromStart && Object.keys(this.schema.types).length > 0) {
285
- if (schemaLooseEqual(strictSchema, this.schema)) {
287
+ if (schemaLooseEqual(parsedSchema, this.schema)) {
286
288
  return this.schema;
287
289
  }
288
290
  return this.migrateSchema(strictSchema, transformFns);
289
291
  }
290
- const { lastId } = this.schema;
291
292
  this.schema = {
292
- lastId,
293
- ...strictSchema,
293
+ lastId: this.schema.lastId,
294
+ ...parsedSchema,
294
295
  };
295
- if (strictSchema.props) {
296
- this.schema.types ??= {};
297
- const props = { ...strictSchema.props };
298
- for (const key in props) {
299
- const prop = props[key];
300
- const propType = getPropType(prop);
301
- let refProp;
302
- if (propType === 'reference') {
303
- refProp = prop;
304
- }
305
- else if (propType === 'references') {
306
- refProp = prop.items;
307
- }
308
- if (refProp) {
309
- const type = this.schema.types[refProp.ref];
310
- const inverseKey = '_' + key;
311
- this.schema.types[refProp.ref] = {
312
- ...type,
313
- props: {
314
- ...type.props,
315
- [inverseKey]: {
316
- items: {
317
- ref: '_root',
318
- prop: key,
319
- },
320
- },
321
- },
322
- };
323
- refProp.prop = inverseKey;
324
- }
325
- }
326
- // @ts-ignore This creates an internal type to use for root props
327
- this.schema.types._root = {
328
- id: 1,
329
- props,
330
- };
331
- delete this.schema.props;
332
- }
333
296
  for (const field in this.schema.types) {
334
297
  if (!('id' in this.schema.types[field])) {
335
298
  this.schema.lastId++;
336
299
  this.schema.types[field].id = this.schema.lastId;
337
300
  }
338
301
  }
302
+ const { hash: _, ...rest } = this.schema;
303
+ this.schema.hash = hash(rest);
339
304
  updateTypeDefs(this.schema, this.schemaTypesParsed, this.schemaTypesParsedById);
340
- const { hash: _, ...schemaWithoutHash } = this.schema;
341
- this.schema.hash = hash(schemaWithoutHash);
342
305
  if (!fromStart) {
343
306
  writeFile(join(this.fileSystemPath, SCHEMA_FILE), JSON.stringify(this.schema)).catch((err) => console.error('!!!', SCHEMA_FILE, err));
344
307
  let types = Object.keys(this.schemaTypesParsed);
@@ -354,7 +317,7 @@ export class DbServer {
354
317
  console.error('Cannot update schema on selva', type.type, err, s[i]);
355
318
  }
356
319
  }
357
- if (strictSchema.props) {
320
+ if (strictSchema.props || strictSchema.types?._root) {
358
321
  // insert a root node
359
322
  // TODO fix this add it in schema at least
360
323
  const data = [2, 1, 0, 0, 0, 1, 9, 1, 0, 0, 0, 7, 1, 0, 1];
@@ -2,13 +2,12 @@ import { DbWorker, SCHEMA_FILE, WRITELOG_FILE } from './index.js';
2
2
  import native from '../native.js';
3
3
  import { rm, mkdir, readFile } from 'node:fs/promises';
4
4
  import { join } from 'node:path';
5
- import { hashEq } from './csmt/index.js';
6
- import { foreachBlock, initCsmt, makeCsmtKey } from './tree.js';
5
+ import { destructureCsmtKey, foreachBlock, initCsmt, makeCsmtKey, specialBlock } from './tree.js';
7
6
  import { availableParallelism } from 'node:os';
8
7
  import exitHook from 'exit-hook';
9
8
  import { save } from './save.js';
10
9
  import { DEFAULT_BLOCK_CAPACITY } from '@based/schema/def';
11
- import { bufToHex, hexToBuf } from '@saulx/utils';
10
+ import { bufToHex } from '@saulx/utils';
12
11
  export async function start(db, opts) {
13
12
  const path = db.fileSystemPath;
14
13
  const noop = () => { };
@@ -74,10 +73,27 @@ export async function start(db, opts) {
74
73
  }, true);
75
74
  }
76
75
  if (writelog?.hash) {
77
- const oldHash = hexToBuf(writelog.hash);
78
- const newHash = db.merkleTree.getRoot()?.hash;
79
- if (!hashEq(oldHash, newHash)) {
80
- console.error(`WARN: CSMT hash mismatch. expected: ${writelog.hash} actual: ${bufToHex(newHash)}`);
76
+ // FIXME FDN-1301
77
+ //const oldHash = hexToBuf(writelog.hash)
78
+ //const newHash = db.merkleTree.getRoot()?.hash
79
+ //if (!hashEq(oldHash, newHash)) {
80
+ // console.error(
81
+ // `WARN: CSMT hash mismatch. expected: ${writelog.hash} actual: ${bufToHex(newHash)}`,
82
+ // )
83
+ //}
84
+ const oldHashSet = new Set();
85
+ const newHashSet = new Set();
86
+ for (let k in writelog.rangeDumps)
87
+ writelog.rangeDumps[k].forEach(({ hash }) => oldHashSet.add(hash));
88
+ db.merkleTree.visitLeafNodes(({ key, hash }) => {
89
+ const [_typeId, start] = destructureCsmtKey(key);
90
+ if (start == specialBlock)
91
+ return; // skip the type specialBlock
92
+ newHashSet.add(bufToHex(hash));
93
+ });
94
+ const setEq = (a, b) => a.size === b.size && [...a].every(value => b.has(value));
95
+ if (!setEq(oldHashSet, newHashSet)) {
96
+ console.error(`WARN: CSMT hash mismatch.`);
81
97
  }
82
98
  }
83
99
  // start workers
@@ -3,4 +3,3 @@ export declare const DECODER: TextDecoder;
3
3
  export declare const ENCODER: TextEncoder;
4
4
  export declare const debugMode: (target: any, getInfo?: any) => void;
5
5
  export declare const debugServer: (server: DbServer) => void;
6
- export declare const schemaLooseEqual: (a: any, b: any, key?: string) => boolean;
package/dist/src/utils.js CHANGED
@@ -43,51 +43,4 @@ export const debugMode = (target, getInfo = null) => {
43
43
  }
44
44
  };
45
45
  export const debugServer = (server) => debugMode(server, () => `p: ${server.processingQueries} m: ${server.modifyQueue.length} q: ${server.queryQueue.size}`);
46
- const exclude = new Set(['id', 'lastId', 'hash']);
47
- export const schemaLooseEqual = (a, b, key) => {
48
- if (a === b) {
49
- return true;
50
- }
51
- const typeofA = typeof a;
52
- if (typeofA !== 'object') {
53
- return exclude.has(key);
54
- }
55
- const typeofB = typeof b;
56
- if (typeofA !== typeofB) {
57
- return exclude.has(key);
58
- }
59
- if (a === null || b === null) {
60
- return false;
61
- }
62
- if (a.constructor !== b.constructor) {
63
- return false;
64
- }
65
- if (Array.isArray(a)) {
66
- let i = a.length;
67
- if (i !== b.length) {
68
- return false;
69
- }
70
- while (i--) {
71
- if (!schemaLooseEqual(a[i], b[i])) {
72
- return false;
73
- }
74
- }
75
- }
76
- else {
77
- for (const k in a) {
78
- if (!schemaLooseEqual(a[k], b[k], k)) {
79
- return false;
80
- }
81
- }
82
- for (const k in b) {
83
- if (k in a) {
84
- continue;
85
- }
86
- if (!schemaLooseEqual(a[k], b[k], k)) {
87
- return false;
88
- }
89
- }
90
- }
91
- return true;
92
- };
93
46
  //# sourceMappingURL=utils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@based/db",
3
- "version": "0.0.48",
3
+ "version": "0.0.50",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",