@based/db 0.1.3-alpha.1 → 0.1.4

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 (89) hide show
  1. package/dist/basedDbNative.cjs +23 -0
  2. package/dist/lib/darwin_aarch64/include/cdefs.h +4 -1
  3. package/dist/lib/darwin_aarch64/include/selva/db.h +28 -5
  4. package/dist/lib/darwin_aarch64/include/selva/fast_linear_search.h +2 -2
  5. package/dist/lib/darwin_aarch64/include/selva/fields.h +13 -41
  6. package/dist/lib/darwin_aarch64/include/selva/selva_string.h +4 -0
  7. package/dist/lib/darwin_aarch64/include/selva/types.h +1 -11
  8. package/dist/lib/darwin_aarch64/libdeflate.dylib +0 -0
  9. package/dist/lib/darwin_aarch64/libjemalloc_selva.2.dylib +0 -0
  10. package/dist/lib/darwin_aarch64/libnode-v22.node +0 -0
  11. package/dist/lib/darwin_aarch64/libnode-v23.node +0 -0
  12. package/dist/lib/darwin_aarch64/libnode-v24.node +0 -0
  13. package/dist/lib/darwin_aarch64/libselva.dylib +0 -0
  14. package/dist/lib/darwin_aarch64/libxxhash.dylib +0 -0
  15. package/dist/lib/linux_aarch64/include/cdefs.h +4 -1
  16. package/dist/lib/linux_aarch64/include/selva/db.h +28 -5
  17. package/dist/lib/linux_aarch64/include/selva/fast_linear_search.h +2 -2
  18. package/dist/lib/linux_aarch64/include/selva/fields.h +13 -41
  19. package/dist/lib/linux_aarch64/include/selva/selva_string.h +4 -0
  20. package/dist/lib/linux_aarch64/include/selva/types.h +1 -11
  21. package/dist/lib/linux_aarch64/libdeflate.so +0 -0
  22. package/dist/lib/linux_aarch64/libnode-v22.node +0 -0
  23. package/dist/lib/linux_aarch64/libnode-v23.node +0 -0
  24. package/dist/lib/linux_aarch64/libnode-v24.node +0 -0
  25. package/dist/lib/linux_aarch64/libselva.so +0 -0
  26. package/dist/lib/linux_x86_64/include/cdefs.h +4 -1
  27. package/dist/lib/linux_x86_64/include/selva/db.h +28 -5
  28. package/dist/lib/linux_x86_64/include/selva/fast_linear_search.h +2 -2
  29. package/dist/lib/linux_x86_64/include/selva/fields.h +13 -41
  30. package/dist/lib/linux_x86_64/include/selva/selva_string.h +4 -0
  31. package/dist/lib/linux_x86_64/include/selva/types.h +1 -11
  32. package/dist/lib/linux_x86_64/libdeflate.so +0 -0
  33. package/dist/lib/linux_x86_64/libnode-v22.node +0 -0
  34. package/dist/lib/linux_x86_64/libnode-v23.node +0 -0
  35. package/dist/lib/linux_x86_64/libnode-v24.node +0 -0
  36. package/dist/lib/linux_x86_64/libselva.so +0 -0
  37. package/dist/src/client/index.d.ts +2 -0
  38. package/dist/src/client/index.js +11 -2
  39. package/dist/src/client/modify/Ctx.d.ts +3 -5
  40. package/dist/src/client/modify/Ctx.js +0 -3
  41. package/dist/src/client/modify/Tmp.d.ts +2 -2
  42. package/dist/src/client/modify/Tmp.js +27 -23
  43. package/dist/src/client/modify/create/index.js +36 -25
  44. package/dist/src/client/modify/cursor.d.ts +0 -1
  45. package/dist/src/client/modify/cursor.js +10 -26
  46. package/dist/src/client/modify/delete/index.js +6 -6
  47. package/dist/src/client/modify/drain.js +20 -23
  48. package/dist/src/client/modify/edges/references.js +3 -2
  49. package/dist/src/client/modify/error.d.ts +2 -1
  50. package/dist/src/client/modify/error.js +2 -2
  51. package/dist/src/client/modify/expire/index.js +5 -6
  52. package/dist/src/client/modify/props/object.js +3 -2
  53. package/dist/src/client/modify/props/reference.js +3 -3
  54. package/dist/src/client/modify/props/references.js +2 -1
  55. package/dist/src/client/modify/types.d.ts +4 -1
  56. package/dist/src/client/modify/types.js +4 -0
  57. package/dist/src/client/modify/update/index.d.ts +3 -0
  58. package/dist/src/client/modify/update/index.js +33 -20
  59. package/dist/src/client/modify/upsert/index.d.ts +2 -1
  60. package/dist/src/client/modify/upsert/index.js +67 -44
  61. package/dist/src/client/query/BasedDbQuery.js +12 -7
  62. package/dist/src/client/query/aggregates/aggregation.d.ts +1 -1
  63. package/dist/src/client/query/aggregates/aggregation.js +24 -3
  64. package/dist/src/client/query/filter/convertFilter.js +16 -3
  65. package/dist/src/client/query/filter/types.d.ts +1 -1
  66. package/dist/src/client/query/include/include.js +2 -5
  67. package/dist/src/client/query/queryDefToReadSchema.js +20 -1
  68. package/dist/src/client/query/search/index.js +9 -1
  69. package/dist/src/client/string.d.ts +1 -1
  70. package/dist/src/client/string.js +1 -1
  71. package/dist/src/hooks.d.ts +3 -6
  72. package/dist/src/hooks.js +5 -12
  73. package/dist/src/index.d.ts +3 -3
  74. package/dist/src/index.js +5 -3
  75. package/dist/src/native.d.ts +4 -3
  76. package/dist/src/native.js +11 -10
  77. package/dist/src/server/blocks.js +1 -1
  78. package/dist/src/server/index.d.ts +3 -2
  79. package/dist/src/server/index.js +23 -47
  80. package/dist/src/server/migrate/index.js +4 -0
  81. package/dist/src/server/resizeModifyDirtyRanges.js +1 -1
  82. package/dist/src/server/save.d.ts +0 -1
  83. package/dist/src/server/save.js +2 -2
  84. package/dist/src/server/schema.js +6 -1
  85. package/dist/src/server/start.js +0 -2
  86. package/dist/src/shared/Emitter.d.ts +1 -1
  87. package/dist/src/utils.d.ts +0 -2
  88. package/dist/src/utils.js +1 -3
  89. package/package.json +17 -7
@@ -1,11 +1,9 @@
1
- import { writeUint16, writeUint32 } from '@based/utils';
2
1
  import { rejectTmp, resolveTmp } from './Tmp.js';
3
2
  export const reset = (ctx) => {
4
3
  ctx.index = 8;
5
4
  ctx.max = ctx.array.buffer.maxByteLength - 4;
6
5
  ctx.size = ctx.array.buffer.byteLength - 4;
7
6
  ctx.cursor = {};
8
- ctx.created = {};
9
7
  ctx.batch = {};
10
8
  };
11
9
  export const cancel = (ctx, error) => {
@@ -18,17 +16,7 @@ export const consume = (ctx) => {
18
16
  if (ctx.index > ctx.array.byteLength) {
19
17
  throw new Error('Invalid size - modify buffer length mismatch');
20
18
  }
21
- const typeIds = Object.keys(ctx.created);
22
- const typeSize = typeIds.length * 6 + 4;
23
- const payload = ctx.array.subarray(0, ctx.index + typeSize);
24
- let i = payload.byteLength - 4;
25
- writeUint32(payload, ctx.index, i);
26
- for (const typeId of typeIds) {
27
- const count = ctx.created[typeId];
28
- i -= 6;
29
- writeUint16(payload, Number(typeId), i);
30
- writeUint32(payload, count, i + 2);
31
- }
19
+ const payload = ctx.array.subarray(0, ctx.index);
32
20
  reset(ctx);
33
21
  return payload;
34
22
  };
@@ -36,21 +24,30 @@ export const drain = (db, ctx) => {
36
24
  if (ctx.index > 8) {
37
25
  const { batch } = ctx;
38
26
  const payload = consume(ctx);
27
+ let start;
39
28
  ctx.draining = db.hooks
40
29
  .flushModify(payload)
41
- .then(({ offsets, dbWriteTime }) => {
42
- db.writeTime += dbWriteTime ?? 0;
43
- batch.ready = true;
44
- batch.offsets = offsets;
45
- batch.promises?.forEach(resolveTmp);
46
- batch.promises = null;
30
+ .then((res) => {
31
+ if (res === null) {
32
+ throw Error('Schema mismatch');
33
+ }
34
+ batch.res = res;
47
35
  })
48
36
  .catch((e) => {
49
- console.error(e);
50
- batch.ready = true;
51
37
  batch.error = e;
52
- batch.promises?.forEach(rejectTmp);
53
- batch.promises = null;
38
+ })
39
+ .finally(() => {
40
+ batch.ready = true;
41
+ if (batch.promises) {
42
+ start = ctx.index;
43
+ batch.promises.forEach(batch.error ? rejectTmp : resolveTmp);
44
+ batch.promises = null;
45
+ }
46
+ })
47
+ .then(() => {
48
+ if (start && start !== ctx.index) {
49
+ return drain(db, ctx);
50
+ }
54
51
  });
55
52
  }
56
53
  return ctx.draining;
@@ -1,6 +1,6 @@
1
1
  import { REFERENCES } from '@based/schema/def';
2
2
  import { reserve } from '../resize.js';
3
- import { writeU32 } from '../uint.js';
3
+ import { writePadding, writeU32 } from '../uint.js';
4
4
  import { writeEdgeHeader } from './header.js';
5
5
  export const writeReferencesEdge = (ctx, edge, vals) => {
6
6
  if (vals === null) {
@@ -12,7 +12,7 @@ export const writeReferencesEdge = (ctx, edge, vals) => {
12
12
  if (!Array.isArray(vals)) {
13
13
  throw [edge, vals];
14
14
  }
15
- const size = vals.length * 4;
15
+ const size = vals.length * 4 + 3; // add 3 padding
16
16
  reserve(ctx, 3 + 4 + size);
17
17
  writeEdgeHeader(ctx, edge, REFERENCES);
18
18
  writeU32(ctx, size);
@@ -34,5 +34,6 @@ export const writeReferencesEdge = (ctx, edge, vals) => {
34
34
  }
35
35
  throw [edge, vals];
36
36
  }
37
+ writePadding(ctx, 3);
37
38
  };
38
39
  //# sourceMappingURL=references.js.map
@@ -4,4 +4,5 @@ import { Ctx } from './Ctx.js';
4
4
  import { del } from './delete/index.js';
5
5
  import { expire } from './expire/index.js';
6
6
  import { update } from './update/index.js';
7
- export declare const handleError: (db: DbClient, ctx: Ctx, fn: typeof create | typeof update | typeof del | typeof expire, args: IArguments, e: any) => Promise<number>;
7
+ import { upsert } from './upsert/index.js';
8
+ export declare const handleError: (db: DbClient, ctx: Ctx, fn: typeof create | typeof update | typeof del | typeof expire | typeof upsert, args: IArguments, e: any) => Promise<number>;
@@ -27,7 +27,7 @@ const parseVal = (val) => {
27
27
  }
28
28
  return val;
29
29
  };
30
- const parseErrorMsg = (prop, val, msg) => {
30
+ const parseErrorArr = (prop, val, msg) => {
31
31
  if (isPropDef(prop)) {
32
32
  if (msg) {
33
33
  return `Invalid value at '${prop.path.join('.')}'. Expected ${msg} received '${parseVal(val)}'`;
@@ -59,7 +59,7 @@ export const handleError = (db, ctx, fn, args, e) => {
59
59
  }
60
60
  if (Array.isArray(e)) {
61
61
  const [def, val, msg] = e;
62
- throw Error(parseErrorMsg(def, val, msg));
62
+ throw Error(parseErrorArr(def, val, msg));
63
63
  }
64
64
  throw e;
65
65
  };
@@ -1,8 +1,8 @@
1
1
  import { getValidSchema, validateId } from '../validate.js';
2
2
  import { handleError } from '../error.js';
3
3
  import { reserve } from '../resize.js';
4
- import { NODE_CURSOR_SIZE, TYPE_CURSOR_SIZE, writeNodeCursor, writeTypeCursor, } from '../cursor.js';
5
- import { EXPIRE } from '../types.js';
4
+ import { NODE_CURSOR_SIZE, TYPE_CURSOR_SIZE, writeTypeCursor, } from '../cursor.js';
5
+ import { EXPIRE, SWITCH_ID_UPDATE } from '../types.js';
6
6
  import { schedule } from '../drain.js';
7
7
  import { Tmp } from '../Tmp.js';
8
8
  import { writeU32, writeU8 } from '../uint.js';
@@ -10,17 +10,16 @@ export function expire(db, type, id, seconds) {
10
10
  const ctx = db.modifyCtx;
11
11
  const schema = getValidSchema(db, type);
12
12
  try {
13
- ctx.id = id;
14
13
  ctx.start = ctx.index;
15
14
  ctx.schema = schema;
16
- ctx.operation = EXPIRE;
17
15
  validateId(id);
18
16
  reserve(ctx, TYPE_CURSOR_SIZE + NODE_CURSOR_SIZE + 5);
19
17
  writeTypeCursor(ctx);
20
- writeNodeCursor(ctx);
18
+ writeU8(ctx, SWITCH_ID_UPDATE);
19
+ writeU32(ctx, id);
21
20
  writeU8(ctx, EXPIRE);
22
21
  writeU32(ctx, seconds);
23
- const tmp = new Tmp(ctx, id);
22
+ const tmp = new Tmp(ctx);
24
23
  schedule(db, ctx);
25
24
  return tmp;
26
25
  }
@@ -2,11 +2,12 @@ import { isPropDef } from '@based/schema/def';
2
2
  import { writeSeparate } from './separate.js';
3
3
  import { writeMainValue } from './main.js';
4
4
  import { writeIncrement } from './increment.js';
5
+ import { CREATE } from '../types.js';
5
6
  const writeProp = (ctx, def, val) => {
6
7
  if (def.separate) {
7
8
  writeSeparate(ctx, def, val);
8
9
  }
9
- else if (ctx.overwrite) {
10
+ else if (ctx.operation === CREATE) {
10
11
  writeMainValue(ctx, def, val);
11
12
  }
12
13
  else if (typeof val === 'object' && val !== null) {
@@ -24,7 +25,7 @@ export const writeObjectSafe = (ctx, tree, obj) => {
24
25
  }
25
26
  const def = tree[key];
26
27
  if (def === undefined) {
27
- throw [def, val];
28
+ throw [tree, val];
28
29
  }
29
30
  if (isPropDef(def)) {
30
31
  writeProp(ctx, def, val);
@@ -5,10 +5,8 @@ import { EDGE_NOINDEX_REALID, EDGE_NOINDEX_TMPID, NOEDGE_NOINDEX_REALID, NOEDGE_
5
5
  import { writeEdges } from '../edges/index.js';
6
6
  import { deleteProp } from './delete.js';
7
7
  import { writeU32, writeU8 } from '../uint.js';
8
+ import { validate } from '../validate.js';
8
9
  const writeReferenceId = (ctx, def, val, refOp) => {
9
- if (!def.validation(val, def)) {
10
- throw [def, val];
11
- }
12
10
  reserve(ctx, PROP_CURSOR_SIZE + 6);
13
11
  writePropCursor(ctx, def);
14
12
  writeU8(ctx, ctx.operation);
@@ -21,6 +19,7 @@ export const writeReference = (ctx, def, val) => {
21
19
  return;
22
20
  }
23
21
  if (typeof val === 'number') {
22
+ validate(def, val);
24
23
  if (def.hasDefaultEdges) {
25
24
  writeReferenceId(ctx, def, val, EDGE_NOINDEX_REALID);
26
25
  writeEdges(ctx, def, {}, true);
@@ -45,6 +44,7 @@ export const writeReference = (ctx, def, val) => {
45
44
  }
46
45
  }
47
46
  if (typeof val.id === 'number') {
47
+ validate(def, val.id);
48
48
  if (!def.edges || val instanceof Tmp || val instanceof Promise) {
49
49
  writeReferenceId(ctx, def, val.id, NOEDGE_NOINDEX_REALID);
50
50
  }
@@ -101,6 +101,7 @@ const updateReferences = (ctx, def, val, index, length, refOp) => {
101
101
  throw id;
102
102
  }
103
103
  if (typeof id.id === 'number') {
104
+ validate(def, id.id);
104
105
  writeReferenceObj(ctx, def, id.id, id, false);
105
106
  continue;
106
107
  }
@@ -109,6 +110,7 @@ const updateReferences = (ctx, def, val, index, length, refOp) => {
109
110
  }
110
111
  if (typeof id.id.then === 'function') {
111
112
  if (id.id.id) {
113
+ validate(def, id.id.id);
112
114
  writeReferenceObj(ctx, def, id.id.id, id, false);
113
115
  continue;
114
116
  }
@@ -151,7 +153,6 @@ const putOrUpdateReferences = (ctx, def, val, refOp) => {
151
153
  const writeReferenceObj = (ctx, def, id, obj, isTmp) => {
152
154
  const hasIndex = typeof obj.$index === 'number';
153
155
  const hasEdges = hasAnEdge(def, obj);
154
- validate(def, id);
155
156
  if (hasIndex) {
156
157
  if (hasEdges) {
157
158
  writeU8(ctx, isTmp ? EDGE_INDEX_TMPID : EDGE_INDEX_REALID);
@@ -12,10 +12,14 @@ export declare const EXPIRE = 14;
12
12
  export declare const ADD_EMPTY_SORT_TEXT = 15;
13
13
  export declare const ADD_EMPTY_SORT = 7;
14
14
  export declare const DELETE_TEXT_FIELD = 16;
15
+ export declare const PADDING = 255;
15
16
  export declare const SWITCH_TYPE = 2;
16
17
  export declare const SWITCH_FIELD = 0;
17
18
  export declare const SWITCH_ID_CREATE = 9;
19
+ export declare const SWITCH_ID_CREATE_UNSAFE = 8;
18
20
  export declare const SWITCH_ID_UPDATE = 1;
21
+ export declare const UPSERT = 17;
22
+ export declare const INSERT = 18;
19
23
  export type ModifyOp = typeof CREATE | typeof UPDATE | typeof INCREMENT | typeof EXPIRE;
20
24
  export declare const MOD_OPS_TO_STRING: Record<ModifyOp, 'create' | 'update'>;
21
25
  export declare const enum SIZE {
@@ -24,7 +28,6 @@ export declare const enum SIZE {
24
28
  export type ModifyOpts = {
25
29
  unsafe?: boolean;
26
30
  locale?: LangName;
27
- overwrite?: boolean;
28
31
  };
29
32
  export declare const NOEDGE_NOINDEX_REALID = 0;
30
33
  export declare const EDGE_NOINDEX_REALID = 1;
@@ -11,10 +11,14 @@ export const EXPIRE = 14;
11
11
  export const ADD_EMPTY_SORT_TEXT = 15;
12
12
  export const ADD_EMPTY_SORT = 7;
13
13
  export const DELETE_TEXT_FIELD = 16;
14
+ export const PADDING = 255;
14
15
  export const SWITCH_TYPE = 2;
15
16
  export const SWITCH_FIELD = 0;
16
17
  export const SWITCH_ID_CREATE = 9;
18
+ export const SWITCH_ID_CREATE_UNSAFE = 8;
17
19
  export const SWITCH_ID_UPDATE = 1;
20
+ export const UPSERT = 17;
21
+ export const INSERT = 18;
18
22
  export const MOD_OPS_TO_STRING = {
19
23
  [CREATE]: 'create',
20
24
  [UPDATE]: 'update',
@@ -1,3 +1,6 @@
1
+ import { Ctx } from '../Ctx.js';
1
2
  import { ModifyOpts } from '../types.js';
2
3
  import { DbClient } from '../../../index.js';
4
+ import { SchemaTypeDef } from '@based/schema/def';
5
+ export declare const writeUpdate: (ctx: Ctx, schema: SchemaTypeDef, id: number, payload: any, opts: ModifyOpts) => void;
3
6
  export declare function update(db: DbClient, type: string, id: number, payload: any, opts: ModifyOpts): Promise<number>;
@@ -1,13 +1,13 @@
1
- import { UPDATE, UPDATE_PARTIAL } from '../types.js';
1
+ import { SWITCH_ID_UPDATE, UPDATE, UPDATE_PARTIAL, } from '../types.js';
2
2
  import { getValidSchema, validateId, validatePayload } from '../validate.js';
3
3
  import { langCodesMap } from '@based/schema';
4
4
  import { handleError } from '../error.js';
5
5
  import { Tmp } from '../Tmp.js';
6
6
  import { writeObject } from '../props/object.js';
7
7
  import { reserve } from '../resize.js';
8
- import { FULL_CURSOR_SIZE, PROP_CURSOR_SIZE, writeMainCursor, writeNodeCursor, writeTypeCursor, } from '../cursor.js';
8
+ import { FULL_CURSOR_SIZE, PROP_CURSOR_SIZE, writeMainCursor, writeTypeCursor, } from '../cursor.js';
9
9
  import { getByPath, writeUint32 } from '@based/utils';
10
- import { writeU16, writeU8 } from '../uint.js';
10
+ import { writeU16, writeU32, writeU8 } from '../uint.js';
11
11
  import { writeFixed } from '../props/fixed.js';
12
12
  import { schedule } from '../drain.js';
13
13
  const writeUpdateTs = (ctx, payload) => {
@@ -37,10 +37,35 @@ const writeMergeMain = (ctx) => {
37
37
  writeUint32(ctx.array, ctx.index - start, index);
38
38
  }
39
39
  };
40
- const writeUpdate = (ctx, payload) => {
40
+ export const writeUpdate = (ctx, schema, id, payload, opts) => {
41
+ validatePayload(payload);
42
+ if (schema.propHooks?.update) {
43
+ for (const def of schema.propHooks.update) {
44
+ let val = payload;
45
+ let obj;
46
+ let key;
47
+ for (key of def.path) {
48
+ obj = val;
49
+ val = val?.[key];
50
+ }
51
+ if (val !== undefined) {
52
+ obj[key] = def.hooks.update(val, obj);
53
+ }
54
+ }
55
+ }
56
+ if (schema.hooks?.update) {
57
+ payload = schema.hooks.update(payload) || payload;
58
+ }
59
+ ctx.schema = schema;
60
+ ctx.operation = UPDATE;
61
+ ctx.locale = opts?.locale && langCodesMap.get(opts.locale);
62
+ if (ctx.main.size) {
63
+ ctx.main.clear();
64
+ }
41
65
  reserve(ctx, FULL_CURSOR_SIZE);
42
66
  writeTypeCursor(ctx);
43
- writeNodeCursor(ctx);
67
+ writeU8(ctx, SWITCH_ID_UPDATE);
68
+ writeU32(ctx, id);
44
69
  writeObject(ctx, ctx.schema.tree, payload);
45
70
  writeUpdateTs(ctx, payload);
46
71
  writeMergeMain(ctx);
@@ -48,23 +73,11 @@ const writeUpdate = (ctx, payload) => {
48
73
  export function update(db, type, id, payload, opts) {
49
74
  const schema = getValidSchema(db, type);
50
75
  const ctx = db.modifyCtx;
76
+ ctx.start = ctx.index;
51
77
  try {
52
- validatePayload(payload);
53
78
  validateId(id);
54
- if (schema.hooks?.update) {
55
- payload = schema.hooks.update(payload) || payload;
56
- }
57
- ctx.id = id;
58
- ctx.schema = schema;
59
- ctx.operation = UPDATE;
60
- ctx.overwrite = opts?.overwrite;
61
- ctx.locale = opts?.locale && langCodesMap.get(opts.locale);
62
- ctx.start = ctx.index;
63
- if (ctx.main.size) {
64
- ctx.main.clear();
65
- }
66
- writeUpdate(ctx, payload);
67
- const tmp = new Tmp(ctx, id);
79
+ writeUpdate(ctx, schema, id, payload, opts);
80
+ const tmp = new Tmp(ctx);
68
81
  schedule(db, ctx);
69
82
  return tmp;
70
83
  }
@@ -1,3 +1,4 @@
1
1
  import { DbClient } from '../../../index.js';
2
2
  import { ModifyOpts } from '../types.js';
3
- export declare const upsert: (db: DbClient, type: string, obj: any, opts: ModifyOpts) => Promise<number>;
3
+ export declare function upsert(db: DbClient, type: string, payload: any, opts: ModifyOpts): Promise<number>;
4
+ export declare function insert(db: DbClient, type: string, payload: any, opts: ModifyOpts): Promise<number>;
@@ -1,54 +1,77 @@
1
1
  import { ALIAS, isPropDef } from '@based/schema/def';
2
- import { deepMerge } from '@based/utils';
3
- const filterAliases = (obj, tree) => {
4
- let aliases;
2
+ import { INSERT, UPSERT } from '../types.js';
3
+ import { getValidSchema } from '../validate.js';
4
+ import { writeU32, writeU8, writeU8Array } from '../uint.js';
5
+ import { reserve } from '../resize.js';
6
+ import { ENCODER, writeUint32 } from '@based/utils';
7
+ import { writeCreate } from '../create/index.js';
8
+ import { handleError } from '../error.js';
9
+ import { writeUpdate } from '../update/index.js';
10
+ import { schedule } from '../drain.js';
11
+ import { TYPE_CURSOR_SIZE, writeTypeCursor } from '../cursor.js';
12
+ import { Tmp } from '../Tmp.js';
13
+ const writeAliases = (ctx, tree, obj) => {
5
14
  for (const key in obj) {
6
15
  const def = tree[key];
7
- if (def === undefined) {
8
- return;
16
+ const val = obj[key];
17
+ if (def === undefined || val === undefined) {
18
+ continue;
9
19
  }
10
- if (isPropDef(def)) {
11
- if (def.typeIndex === ALIAS) {
12
- aliases ??= {};
13
- aliases[key] = obj[key];
14
- }
20
+ if (!isPropDef(def)) {
21
+ writeAliases(ctx, def, val);
15
22
  }
16
- else {
17
- const nested = filterAliases(obj[key], def);
18
- if (nested) {
19
- aliases ??= {};
20
- aliases[key] = nested;
21
- }
23
+ else if (def.typeIndex === ALIAS) {
24
+ const buf = ENCODER.encode(val);
25
+ reserve(ctx, 1 + 4 + buf.byteLength);
26
+ writeU8(ctx, def.prop);
27
+ writeU32(ctx, buf.byteLength);
28
+ writeU8Array(ctx, buf);
22
29
  }
23
30
  }
24
- return aliases;
25
31
  };
26
- export const upsert = (db, type, obj, opts) => {
27
- const tree = db.schemaTypesParsed[type].tree;
28
- const aliases = filterAliases(obj, tree);
29
- const q = db.query(type, aliases);
30
- q.register();
31
- if (db.upserting.has(q.id)) {
32
- const store = db.upserting.get(q.id);
33
- deepMerge(store.o, obj);
34
- return store.p;
32
+ export function upsert(db, type, payload, opts) {
33
+ const schema = getValidSchema(db, type);
34
+ const ctx = db.modifyCtx;
35
+ ctx.start = ctx.index;
36
+ ctx.schema = schema;
37
+ try {
38
+ reserve(ctx, TYPE_CURSOR_SIZE + 1 + 4 + 4);
39
+ writeTypeCursor(ctx);
40
+ writeU8(ctx, UPSERT);
41
+ const start = ctx.index;
42
+ ctx.index += 8;
43
+ writeAliases(ctx, schema.tree, payload);
44
+ writeUint32(ctx.array, ctx.index - start, start);
45
+ writeCreate(ctx, schema, {}, opts);
46
+ writeUint32(ctx.array, ctx.index - start, start + 4);
47
+ writeUpdate(ctx, schema, 0, payload, opts);
48
+ schedule(db, ctx);
49
+ return new Tmp(ctx);
35
50
  }
36
- const store = {
37
- o: obj,
38
- p: q.get().then((res) => {
39
- db.upserting.delete(q.id);
40
- if (res.length === 0) {
41
- return db.create(type, store.o, opts);
42
- }
43
- else {
44
- const obj = res.toObject();
45
- const id = Array.isArray(obj) ? obj[0].id : obj.id;
46
- // don't call update if it's not necessary
47
- return db.update(type, id, store.o, opts);
48
- }
49
- }),
50
- };
51
- db.upserting.set(q.id, store);
52
- return store.p;
53
- };
51
+ catch (e) {
52
+ return handleError(db, ctx, upsert, arguments, e);
53
+ }
54
+ }
55
+ export function insert(db, type, payload, opts) {
56
+ const schema = getValidSchema(db, type);
57
+ const ctx = db.modifyCtx;
58
+ ctx.start = ctx.index;
59
+ ctx.schema = schema;
60
+ try {
61
+ reserve(ctx, TYPE_CURSOR_SIZE + 1 + 4 + 4);
62
+ writeTypeCursor(ctx);
63
+ writeU8(ctx, INSERT);
64
+ const start = ctx.index;
65
+ ctx.index += 8;
66
+ writeAliases(ctx, schema.tree, payload);
67
+ writeUint32(ctx.array, ctx.index - start, start);
68
+ writeCreate(ctx, schema, payload, opts);
69
+ writeUint32(ctx.array, ctx.index - start, start + 4);
70
+ schedule(db, ctx);
71
+ return new Tmp(ctx);
72
+ }
73
+ catch (e) {
74
+ return handleError(db, ctx, insert, arguments, e);
75
+ }
76
+ }
54
77
  //# sourceMappingURL=index.js.map
@@ -123,13 +123,7 @@ export class QueryBranch {
123
123
  });
124
124
  }
125
125
  else {
126
- const groupByHook = this.def.schema.hooks?.groupBy;
127
- if (groupByHook) {
128
- this.def.schema.hooks.groupBy = null;
129
- groupByHook(this, field);
130
- this.def.schema.hooks.groupBy = groupByHook;
131
- }
132
- groupBy(this.def, field, step);
126
+ groupBy(this, field, step);
133
127
  }
134
128
  // only works with aggregates for now
135
129
  // @ts-ignore
@@ -347,6 +341,17 @@ export class QueryBranch {
347
341
  }
348
342
  else {
349
343
  include(this, fields);
344
+ if (this.def.schema.propHooks?.include) {
345
+ for (const field of this.def.include.stringFields.keys()) {
346
+ const hooks = this.def.schema.props[field]?.hooks;
347
+ const includeHook = hooks?.include;
348
+ if (includeHook) {
349
+ hooks.include = null;
350
+ includeHook(this, this.def.include.stringFields);
351
+ hooks.include = includeHook;
352
+ }
353
+ }
354
+ }
350
355
  const includeHook = this.def.schema.hooks?.include;
351
356
  if (includeHook) {
352
357
  this.def.schema.hooks.include = null;
@@ -3,6 +3,6 @@ import { StepInput, aggFnOptions } from './types.js';
3
3
  import { QueryBranch } from '../BasedDbQuery.js';
4
4
  import { AggregateType } from '@based/protocol/db-read';
5
5
  export declare const aggregateToBuffer: (aggregates: QueryDefAggregation) => Uint8Array;
6
- export declare const groupBy: (def: QueryDef, field: string, StepInput: StepInput) => void;
6
+ export declare const groupBy: (q: QueryBranch<any>, field: string, StepInput: StepInput) => void;
7
7
  export declare const addAggregate: (query: QueryBranch<any>, type: AggregateType, fields: string[], option?: aggFnOptions) => void;
8
8
  export declare const isRootCountOnly: (def: QueryDef, filterSize: number) => boolean;
@@ -70,11 +70,24 @@ const ensureAggregate = (def) => {
70
70
  };
71
71
  }
72
72
  };
73
- export const groupBy = (def, field, StepInput) => {
73
+ export const groupBy = (q, field, StepInput) => {
74
+ const def = q.def;
74
75
  const fieldDef = def.schema.props[field];
75
76
  if (!fieldDef) {
76
77
  aggregationFieldDoesNotExist(def, field);
77
78
  }
79
+ const groupByPropHook = fieldDef.hooks?.groupBy;
80
+ if (groupByPropHook) {
81
+ fieldDef.hooks.groupBy = null;
82
+ groupByPropHook(q, field);
83
+ fieldDef.hooks.groupBy = groupByPropHook;
84
+ }
85
+ const groupByHook = def.schema.hooks?.groupBy;
86
+ if (groupByHook) {
87
+ def.schema.hooks.groupBy = null;
88
+ groupByHook(q, field);
89
+ def.schema.hooks.groupBy = groupByHook;
90
+ }
78
91
  ensureAggregate(def);
79
92
  if (!def.aggregate.groupBy) {
80
93
  def.aggregate.size += 12;
@@ -113,10 +126,11 @@ export const groupBy = (def, field, StepInput) => {
113
126
  };
114
127
  export const addAggregate = (query, type, fields, option) => {
115
128
  const def = query.def;
116
- def.schema.hooks?.aggregate?.(def, new Set(fields));
129
+ let hookFields;
117
130
  ensureAggregate(def);
118
- if (option?.mode)
131
+ if (option?.mode) {
119
132
  def.aggregate.option = option;
133
+ }
120
134
  const aggregates = def.aggregate.aggregates;
121
135
  for (const field of fields) {
122
136
  const fieldDef = type === AggregateType.COUNT
@@ -135,6 +149,10 @@ export const addAggregate = (query, type, fields, option) => {
135
149
  if (!fieldDef) {
136
150
  aggregationFieldDoesNotExist(def, field);
137
151
  }
152
+ if (fieldDef.hooks?.aggregate) {
153
+ hookFields ??= new Set(fields);
154
+ fieldDef.hooks.aggregate(query, hookFields);
155
+ }
138
156
  if (!aggregates.get(fieldDef.prop)) {
139
157
  aggregates.set(fieldDef.prop, []);
140
158
  def.aggregate.size += 3;
@@ -158,6 +176,9 @@ export const addAggregate = (query, type, fields, option) => {
158
176
  // needs to add an extra field WRITE TO
159
177
  def.aggregate.size += 8;
160
178
  }
179
+ if (def.schema.hooks?.aggregate) {
180
+ def.schema.hooks.aggregate(query, hookFields || new Set(fields));
181
+ }
161
182
  };
162
183
  export const isRootCountOnly = (def, filterSize) => {
163
184
  if (filterSize != 0) {
@@ -8,16 +8,29 @@ const normalizeNeedle = (s) => {
8
8
  };
9
9
  export const convertFilter = (query, field, operator, value, opts) => {
10
10
  const def = query.def;
11
- const filterHook = def.schema.hooks?.filter;
11
+ const propHooks = def.schema.props[field]?.hooks;
12
+ const hooks = def.schema.hooks;
13
+ const propFilterHook = propHooks?.filter;
14
+ const filterHook = hooks?.filter;
15
+ if (propFilterHook) {
16
+ propHooks.filter = null;
17
+ if (typeof operator === 'boolean') {
18
+ propFilterHook(query, field, '=', operator);
19
+ }
20
+ else {
21
+ propFilterHook(query, field, operator, value);
22
+ }
23
+ propHooks.filter = propFilterHook;
24
+ }
12
25
  if (filterHook) {
13
- def.schema.hooks.filter = null;
26
+ hooks.filter = null;
14
27
  if (typeof operator === 'boolean') {
15
28
  filterHook(query, field, '=', operator);
16
29
  }
17
30
  else {
18
31
  filterHook(query, field, operator, value);
19
32
  }
20
- def.schema.hooks.filter = filterHook;
33
+ hooks.filter = filterHook;
21
34
  }
22
35
  if (operator === undefined) {
23
36
  operator = '=';
@@ -54,7 +54,7 @@ export declare const VECTOR_DOT_PRODUCT = 0;
54
54
  export declare const VECTOR_MANHATTAN_DIST = 1;
55
55
  export declare const VECTOR_COSTINE_SIMILARITY = 2;
56
56
  export declare const VECTOR_EUCLIDEAN_DIST = 3;
57
- export declare const getVectorFn: (optsFn?: FilterOpts["fn"]) => 0 | 1 | 3 | 2;
57
+ export declare const getVectorFn: (optsFn?: FilterOpts["fn"]) => 1 | 0 | 3 | 2;
58
58
  export declare const toFilterCtx: (def: QueryDef, op: Operator, opts?: FilterOpts) => FilterCtx;
59
59
  export declare const operatorReverseMap: Record<OPERATOR, string>;
60
60
  export declare const ALIGNMENT_NOT_SET = 255;
@@ -16,7 +16,7 @@ export const include = (query, fields) => {
16
16
  }
17
17
  else if (typeof f === 'function') {
18
18
  f((field) => {
19
- if (field[0] == '$') {
19
+ if (field[0] === '$') {
20
20
  // @ts-ignore
21
21
  const prop = query.def.target?.propDef?.edges[field];
22
22
  if (prop &&
@@ -28,10 +28,7 @@ export const include = (query, fields) => {
28
28
  throw new Error(`No edge reference or edge references field named "${field}"`);
29
29
  }
30
30
  else {
31
- const prop = field[0] == '$'
32
- ? // @ts-ignore
33
- query.def.target?.propDef?.edges[field]
34
- : query.def.props[field];
31
+ const prop = query.def.props[field];
35
32
  if (prop &&
36
33
  (prop.typeIndex === REFERENCE || prop.typeIndex === REFERENCES)) {
37
34
  const refDef = createOrGetRefQueryDef(query.db, query.def, prop);