@based/db 0.0.7 → 0.0.9
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.
- package/README.md +425 -8
- package/dist/lib/darwin_aarch64/include/selva/db.h +12 -3
- package/dist/lib/darwin_aarch64/include/selva/fields.h +22 -11
- package/dist/lib/darwin_aarch64/include/selva/history.h +49 -0
- package/dist/lib/darwin_aarch64/include/selva/hll.h +21 -0
- package/dist/lib/darwin_aarch64/include/selva/sort.h +14 -0
- package/dist/lib/darwin_aarch64/include/selva/types.h +9 -2
- package/dist/lib/darwin_aarch64/include/selva/vector.h +22 -1
- package/dist/lib/darwin_aarch64/include/selva/xxhash64.h +23 -0
- package/dist/lib/darwin_aarch64/libnode-v20.11.1.node +0 -0
- package/dist/lib/darwin_aarch64/libnode-v20.18.1.node +0 -0
- package/dist/lib/darwin_aarch64/libnode-v22.13.0.node +0 -0
- package/dist/lib/darwin_aarch64/libnode-v22.8.0.node +0 -0
- package/dist/lib/darwin_aarch64/libselva.dylib +0 -0
- package/dist/lib/linux_aarch64/include/selva/db.h +12 -3
- package/dist/lib/linux_aarch64/include/selva/fields.h +22 -11
- package/dist/lib/linux_aarch64/include/selva/history.h +49 -0
- package/dist/lib/linux_aarch64/include/selva/hll.h +21 -0
- package/dist/lib/linux_aarch64/include/selva/sort.h +14 -0
- package/dist/lib/linux_aarch64/include/selva/types.h +9 -2
- package/dist/lib/linux_aarch64/include/selva/vector.h +22 -1
- package/dist/lib/linux_aarch64/include/selva/xxhash64.h +23 -0
- package/dist/lib/linux_aarch64/libnode-v20.11.1.node +0 -0
- package/dist/lib/linux_aarch64/libnode-v20.18.1.node +0 -0
- package/dist/lib/linux_aarch64/libnode-v22.13.0.node +0 -0
- package/dist/lib/linux_aarch64/libselva.so +0 -0
- package/dist/lib/linux_x86_64/include/selva/db.h +12 -3
- package/dist/lib/linux_x86_64/include/selva/fields.h +22 -11
- package/dist/lib/linux_x86_64/include/selva/history.h +49 -0
- package/dist/lib/linux_x86_64/include/selva/hll.h +21 -0
- package/dist/lib/linux_x86_64/include/selva/sort.h +14 -0
- package/dist/lib/linux_x86_64/include/selva/types.h +9 -2
- package/dist/lib/linux_x86_64/include/selva/vector.h +22 -1
- package/dist/lib/linux_x86_64/include/selva/xxhash64.h +23 -0
- package/dist/lib/linux_x86_64/libnode-v20.11.1.node +0 -0
- package/dist/lib/linux_x86_64/libnode-v20.18.1.node +0 -0
- package/dist/lib/linux_x86_64/libnode-v22.13.0.node +0 -0
- package/dist/lib/linux_x86_64/libselva.so +0 -0
- package/dist/src/client/bitWise.js +21 -1
- package/dist/src/client/index.d.ts +11 -5
- package/dist/src/client/index.js +57 -11
- package/dist/src/client/modify/ModifyRes.d.ts +4 -1
- package/dist/src/client/modify/ModifyRes.js +8 -1
- package/dist/src/client/modify/alias.js +3 -3
- package/dist/src/client/modify/binary.js +5 -2
- package/dist/src/client/modify/cardinality.d.ts +4 -0
- package/dist/src/client/modify/cardinality.js +50 -0
- package/dist/src/client/modify/create copy.d.ts +5 -0
- package/dist/src/client/modify/create copy.js +112 -0
- package/dist/src/client/modify/create.d.ts +2 -1
- package/dist/src/client/modify/create.js +11 -7
- package/dist/src/client/modify/delete.d.ts +2 -0
- package/dist/src/client/modify/delete.js +37 -0
- package/dist/src/client/modify/expire.d.ts +3 -0
- package/dist/src/client/modify/expire.js +25 -0
- package/dist/src/client/modify/fixed.js +11 -1
- package/dist/src/client/modify/index.d.ts +1 -1
- package/dist/src/client/modify/index.js +1 -1
- package/dist/src/client/modify/json.d.ts +4 -0
- package/dist/src/client/modify/json.js +5 -0
- package/dist/src/client/modify/modify.js +11 -7
- package/dist/src/client/modify/references/edge.js +21 -6
- package/dist/src/client/modify/references/reference.js +2 -2
- package/dist/src/client/modify/references/references.d.ts +0 -1
- package/dist/src/client/modify/references/references.js +4 -4
- package/dist/src/client/modify/remove.d.ts +1 -2
- package/dist/src/client/modify/remove.js +9 -6
- package/dist/src/client/modify/setCursor.d.ts +1 -1
- package/dist/src/client/modify/setCursor.js +4 -1
- package/dist/src/client/modify/string.js +2 -2
- package/dist/src/client/modify/text.d.ts +2 -1
- package/dist/src/client/modify/text.js +13 -7
- package/dist/src/client/modify/types.d.ts +8 -1
- package/dist/src/client/modify/types.js +1 -0
- package/dist/src/client/modify/update.d.ts +2 -1
- package/dist/src/client/modify/update.js +9 -5
- package/dist/src/client/modify/upsert.d.ts +2 -1
- package/dist/src/client/modify/upsert.js +3 -3
- package/dist/src/client/modify/vector copy.d.ts +4 -0
- package/dist/src/client/modify/vector copy.js +46 -0
- package/dist/src/client/modify/vector.js +6 -4
- package/dist/src/client/query/BasedDbQuery.d.ts +4 -3
- package/dist/src/client/query/BasedDbQuery.js +39 -16
- package/dist/src/client/query/BasedIterable.js +3 -3
- package/dist/src/client/query/filter/FilterBranch.d.ts +2 -2
- package/dist/src/client/query/filter/FilterBranch.js +2 -2
- package/dist/src/client/query/filter/createFixedFilterBuffer.d.ts +3 -2
- package/dist/src/client/query/filter/createFixedFilterBuffer.js +14 -11
- package/dist/src/client/query/filter/createReferenceFilter.d.ts +2 -1
- package/dist/src/client/query/filter/createReferenceFilter.js +6 -5
- package/dist/src/client/query/filter/createVariableFilterBuffer.d.ts +2 -1
- package/dist/src/client/query/filter/createVariableFilterBuffer.js +61 -30
- package/dist/src/client/query/filter/filter.d.ts +2 -2
- package/dist/src/client/query/filter/filter.js +27 -22
- package/dist/src/client/query/filter/parseFilterValue.js +9 -64
- package/dist/src/client/query/filter/primitiveFilter.js +7 -11
- package/dist/src/client/query/filter/toBuffer.js +5 -7
- package/dist/src/client/query/filter/types.d.ts +51 -2
- package/dist/src/client/query/filter/types.js +114 -0
- package/dist/src/client/query/include/props.d.ts +2 -0
- package/dist/src/client/query/include/props.js +25 -6
- package/dist/src/client/query/include/toBuffer.js +21 -1
- package/dist/src/client/query/include/walk.js +17 -2
- package/dist/src/client/query/queryDef.js +1 -0
- package/dist/src/client/query/read/read.js +85 -21
- package/dist/src/client/query/search/index.d.ts +2 -0
- package/dist/src/client/query/search/index.js +79 -23
- package/dist/src/client/query/subscription/index.js +2 -2
- package/dist/src/client/query/subscription/markers.d.ts +1 -1
- package/dist/src/client/query/subscription/markers.js +2 -2
- package/dist/src/client/query/toBuffer.js +0 -4
- package/dist/src/client/query/types.d.ts +10 -0
- package/dist/src/client/query/validation.d.ts +3 -2
- package/dist/src/client/query/validation.js +17 -2
- package/dist/src/client/timestamp.d.ts +1 -0
- package/dist/src/client/timestamp.js +68 -0
- package/dist/src/client/xxHash64.d.ts +1 -0
- package/dist/src/client/xxHash64.js +5 -0
- package/dist/src/index.d.ts +4 -1
- package/dist/src/index.js +13 -3
- package/dist/src/native.d.ts +1 -0
- package/dist/src/native.js +4 -1
- package/dist/src/server/csmt/tree.js +12 -2
- package/dist/src/server/index.d.ts +12 -4
- package/dist/src/server/index.js +63 -17
- package/dist/src/server/migrate/index.js +6 -2
- package/dist/src/server/migrate/worker.js +3 -3
- package/dist/src/server/schema/selvaBuffer.js +20 -11
- package/dist/src/server/schema/typeDef.d.ts +2 -2
- package/dist/src/server/schema/typeDef.js +14 -5
- package/dist/src/server/schema/types.d.ts +7 -2
- package/dist/src/server/schema/types.js +6 -3
- package/package.json +1 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { langCodesMap } from '@based/schema';
|
|
2
|
+
import { STRING, TEXT, VECTOR } from '../../../server/schema/types.js';
|
|
3
|
+
import { getVectorFn } from '../filter/types.js';
|
|
2
4
|
const makeSize = (nr, u8 = false) => {
|
|
3
5
|
if (u8) {
|
|
4
6
|
const size = Buffer.allocUnsafe(1);
|
|
@@ -9,10 +11,31 @@ const makeSize = (nr, u8 = false) => {
|
|
|
9
11
|
size.writeUint16LE(nr);
|
|
10
12
|
return size;
|
|
11
13
|
};
|
|
14
|
+
// vector
|
|
15
|
+
export const vectorSearch = (def, q, field, opts) => {
|
|
16
|
+
const prop = def.props[field];
|
|
17
|
+
if (!prop) {
|
|
18
|
+
throw new Error(`Cannot find prop ${field}`);
|
|
19
|
+
}
|
|
20
|
+
if (prop.typeIndex !== VECTOR) {
|
|
21
|
+
throw new Error('Can only search trough strings / text');
|
|
22
|
+
}
|
|
23
|
+
// [isVec] [q len] [q len] [field] [fn] [score] [score] [score] [score] [q..]
|
|
24
|
+
let size = 9;
|
|
25
|
+
const vec = Buffer.from(q.buffer);
|
|
26
|
+
size += vec.byteLength;
|
|
27
|
+
def.search = {
|
|
28
|
+
size: size,
|
|
29
|
+
prop: prop.prop,
|
|
30
|
+
query: vec,
|
|
31
|
+
isVector: true,
|
|
32
|
+
opts,
|
|
33
|
+
};
|
|
34
|
+
};
|
|
12
35
|
export const search = (def, q, s) => {
|
|
36
|
+
const bufs = [];
|
|
13
37
|
let blocks = 0;
|
|
14
38
|
const x = q.toLowerCase().trim().split(' ');
|
|
15
|
-
const bufs = [];
|
|
16
39
|
for (const s of x) {
|
|
17
40
|
if (s) {
|
|
18
41
|
const b = Buffer.from(s);
|
|
@@ -23,9 +46,10 @@ export const search = (def, q, s) => {
|
|
|
23
46
|
bufs.unshift(makeSize(blocks, true));
|
|
24
47
|
const query = Buffer.concat(bufs);
|
|
25
48
|
def.search = {
|
|
26
|
-
size: query.byteLength +
|
|
49
|
+
size: query.byteLength + 3,
|
|
27
50
|
query,
|
|
28
51
|
fields: [],
|
|
52
|
+
isVector: false,
|
|
29
53
|
};
|
|
30
54
|
if (typeof s === 'string') {
|
|
31
55
|
s = [s];
|
|
@@ -35,7 +59,7 @@ export const search = (def, q, s) => {
|
|
|
35
59
|
for (const k in def.props) {
|
|
36
60
|
const prop = def.props[k];
|
|
37
61
|
// if title / name / headline add ROLE:
|
|
38
|
-
if (prop.typeIndex === STRING) {
|
|
62
|
+
if (prop.typeIndex === STRING || prop.typeIndex === TEXT) {
|
|
39
63
|
s[k] = k === 'title' || k === 'name' || k === 'headline' ? 0 : 2;
|
|
40
64
|
}
|
|
41
65
|
}
|
|
@@ -48,35 +72,67 @@ export const search = (def, q, s) => {
|
|
|
48
72
|
s = x;
|
|
49
73
|
}
|
|
50
74
|
for (const key in s) {
|
|
51
|
-
|
|
75
|
+
let prop = def.props[key];
|
|
76
|
+
let lang = def.lang;
|
|
52
77
|
if (!prop) {
|
|
53
|
-
|
|
78
|
+
if (key.includes('.')) {
|
|
79
|
+
const k = key.split('.');
|
|
80
|
+
prop = def.props[k.slice(0, -1).join('.')];
|
|
81
|
+
if (prop && prop.typeIndex === TEXT) {
|
|
82
|
+
lang = langCodesMap.get(k[k.length - 1]);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
throw new Error('field ' + key + ' does not exist on type');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
throw new Error('field ' + key + ' does not exist on type');
|
|
90
|
+
}
|
|
54
91
|
}
|
|
55
|
-
if (prop.typeIndex !== STRING) {
|
|
56
|
-
throw new Error('Can only search trough strings');
|
|
92
|
+
if (prop.typeIndex !== STRING && prop.typeIndex !== TEXT) {
|
|
93
|
+
throw new Error('Can only search trough strings / text');
|
|
57
94
|
}
|
|
58
|
-
def.search.size +=
|
|
95
|
+
def.search.size += 5;
|
|
59
96
|
def.search.fields.push({
|
|
60
97
|
weight: s[key],
|
|
98
|
+
lang,
|
|
61
99
|
field: prop.prop,
|
|
62
|
-
start: prop.start ?? 0,
|
|
100
|
+
start: prop.start ?? 0, // also need lang ofc if you have start
|
|
63
101
|
});
|
|
64
102
|
}
|
|
65
103
|
};
|
|
66
104
|
export const searchToBuffer = (search) => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
result
|
|
77
|
-
|
|
78
|
-
|
|
105
|
+
if (search.isVector) {
|
|
106
|
+
// [isVec] [q len] [q len] [field] [fn] [score] [score] [score] [score] [q..]
|
|
107
|
+
const result = Buffer.allocUnsafe(search.size);
|
|
108
|
+
result[0] = 1; // search.isVector 1
|
|
109
|
+
result.writeUint16LE(search.query.byteLength, 1);
|
|
110
|
+
result[3] = search.prop;
|
|
111
|
+
result[4] = getVectorFn(search.opts.fn);
|
|
112
|
+
result.set(Buffer.from(new Float32Array([search.opts.score ?? 0.5]).buffer), 5);
|
|
113
|
+
result.set(search.query, 9);
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
const result = Buffer.allocUnsafe(search.size);
|
|
118
|
+
result[0] = 0; // search.isVector 0
|
|
119
|
+
result.writeUint16LE(search.query.byteLength, 1);
|
|
120
|
+
result.set(search.query, 3);
|
|
121
|
+
const offset = search.query.byteLength + 3;
|
|
122
|
+
// @ts-ignore
|
|
123
|
+
search.fields.sort((a, b) => {
|
|
124
|
+
return a.weight - b.weight;
|
|
125
|
+
});
|
|
126
|
+
// @ts-ignore
|
|
127
|
+
for (let i = 0; i < search.fields.length * 5; i += 5) {
|
|
128
|
+
// @ts-ignore
|
|
129
|
+
const f = search.fields[i / 5];
|
|
130
|
+
result[i + offset] = f.field;
|
|
131
|
+
result[i + 1 + offset] = f.weight;
|
|
132
|
+
result.writeUInt16LE(f.start, i + 2 + offset);
|
|
133
|
+
result[i + 4 + offset] = f.lang;
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
79
136
|
}
|
|
80
|
-
return result;
|
|
81
137
|
};
|
|
82
138
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { includeFields } from '../query.js';
|
|
2
2
|
import { registerQuery } from '../registerQuery.js';
|
|
3
3
|
import { runSubscription } from './run.js';
|
|
4
|
-
import { addSubscriptionMarkers,
|
|
4
|
+
import { addSubscriptionMarkers, deleteSubscriptionMarkers } from './markers.js';
|
|
5
5
|
export * from './types.js';
|
|
6
6
|
export * from './markers.js';
|
|
7
7
|
export const subscribe = (q, onData, onError) => {
|
|
@@ -35,7 +35,7 @@ export const subscribe = (q, onData, onError) => {
|
|
|
35
35
|
sub.subs.delete(fn);
|
|
36
36
|
if (sub.subs.size === 0) {
|
|
37
37
|
q.db.subscriptions.delete(q.id);
|
|
38
|
-
|
|
38
|
+
deleteSubscriptionMarkers(q);
|
|
39
39
|
}
|
|
40
40
|
closed = true;
|
|
41
41
|
return q;
|
|
@@ -7,4 +7,4 @@ export declare const checkSubscriptionMarkers: (db: DbClient, m: SubscriptionMar
|
|
|
7
7
|
export declare const createSubscriptionMarkerMap: () => SubscriptionMarkerMap;
|
|
8
8
|
export declare const addSubscriptionMarkers: (q: BasedDbQuery, subscription: Subscription) => void;
|
|
9
9
|
export declare const resetSubscriptionMarkers: (db: DbClient) => void;
|
|
10
|
-
export declare const
|
|
10
|
+
export declare const deleteSubscriptionMarkers: (q: BasedDbQuery) => void;
|
|
@@ -206,8 +206,8 @@ export const resetSubscriptionMarkers = (db) => {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
};
|
|
209
|
-
export const
|
|
209
|
+
export const deleteSubscriptionMarkers = (q) => {
|
|
210
210
|
// derp
|
|
211
|
-
console.log('
|
|
211
|
+
console.log('delete markers!');
|
|
212
212
|
};
|
|
213
213
|
//# sourceMappingURL=markers.js.map
|
|
@@ -223,10 +223,6 @@ export function defToBuffer(db, def) {
|
|
|
223
223
|
metaEdgeBuffer.writeUint16LE(edgesSize, 1);
|
|
224
224
|
result.push(metaEdgeBuffer, ...edges);
|
|
225
225
|
}
|
|
226
|
-
// 8 byte crc 32
|
|
227
|
-
if (def.type === QueryDefType.Root) {
|
|
228
|
-
result.push(Buffer.from([def.lang]));
|
|
229
|
-
}
|
|
230
226
|
return result;
|
|
231
227
|
}
|
|
232
228
|
//# sourceMappingURL=toBuffer.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LangCode } from '@based/schema';
|
|
2
2
|
import { PropDef, PropDefEdge, SchemaTypeDef } from '../../server/schema/schema.js';
|
|
3
|
+
import { FilterOpts } from './filter/types.js';
|
|
3
4
|
export type MainIncludes = {
|
|
4
5
|
[start: string]: [number, PropDef];
|
|
5
6
|
};
|
|
@@ -34,11 +35,19 @@ export type QueryDefFilter = {
|
|
|
34
35
|
export type QueryDefSearch = {
|
|
35
36
|
size: number;
|
|
36
37
|
query: Buffer;
|
|
38
|
+
isVector: false;
|
|
37
39
|
fields: {
|
|
38
40
|
weight: number;
|
|
39
41
|
field: number;
|
|
40
42
|
start: number;
|
|
43
|
+
lang: LangCode;
|
|
41
44
|
}[];
|
|
45
|
+
} | {
|
|
46
|
+
size: number;
|
|
47
|
+
query: Buffer;
|
|
48
|
+
prop: number;
|
|
49
|
+
isVector: true;
|
|
50
|
+
opts: FilterOpts;
|
|
42
51
|
};
|
|
43
52
|
export type QueryDefSort = {
|
|
44
53
|
prop: PropDefEdge | PropDef;
|
|
@@ -55,6 +64,7 @@ export type QueryDefShared = {
|
|
|
55
64
|
limit: number;
|
|
56
65
|
};
|
|
57
66
|
include: {
|
|
67
|
+
langTextFields: Map<number, Set<LangCode>>;
|
|
58
68
|
stringFields: Set<string>;
|
|
59
69
|
props: Set<number>;
|
|
60
70
|
propsRead: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PropDef, PropDefEdge } from '../../server/schema/types.js';
|
|
2
|
-
import { Operator } from './filter/
|
|
3
|
-
import { QueryByAliasObj } from './types.js';
|
|
2
|
+
import { Operator } from './filter/types.js';
|
|
3
|
+
import { QueryByAliasObj, QueryDef } from './types.js';
|
|
4
4
|
export declare const isValidId: (id: number) => void;
|
|
5
5
|
export declare const checkMaxIdsPerQuery: (ids: (number | QueryByAliasObj)[]) => void;
|
|
6
6
|
export declare const checkMaxBufferSize: (buf: Buffer) => void;
|
|
@@ -10,6 +10,7 @@ export declare const hasFields: (fields: {
|
|
|
10
10
|
} | {
|
|
11
11
|
[path: string]: PropDef;
|
|
12
12
|
}) => void;
|
|
13
|
+
export declare const isValidAlias: (def: QueryDef, id: QueryByAliasObj) => void;
|
|
13
14
|
export declare const hasField: (field: string) => void;
|
|
14
15
|
export declare const checkOperator: (operator: Operator | boolean) => void;
|
|
15
16
|
export declare const checkValue: (value: any, operator: Operator) => void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { ALIAS } from '../../server/schema/types.js';
|
|
1
2
|
import { MAX_IDS_PER_QUERY, MIN_ID_VALUE, MAX_ID_VALUE, MAX_BUFFER_SIZE, } from './thresholds.js';
|
|
2
|
-
import { validOperators } from './filter/
|
|
3
|
+
import { validOperators } from './filter/types.js';
|
|
3
4
|
export const isValidId = (id) => {
|
|
4
5
|
if (typeof id != 'number') {
|
|
5
6
|
throw new Error('Id has to be a number');
|
|
@@ -29,12 +30,24 @@ export const checkTotalBufferSize = (bufers) => {
|
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
};
|
|
32
|
-
export const hasFields = (
|
|
33
|
+
export const hasFields = (
|
|
34
|
+
// get schema see if it actualy has the value (can find it on def)
|
|
35
|
+
fields) => {
|
|
33
36
|
if (Object.keys(fields).length === 0) {
|
|
34
37
|
throw new Error('No fields available to include');
|
|
35
38
|
}
|
|
36
39
|
};
|
|
40
|
+
export const isValidAlias = (def, id) => {
|
|
41
|
+
for (const key in id) {
|
|
42
|
+
const prop = def.schema.props[key];
|
|
43
|
+
if (!prop || prop.typeIndex !== ALIAS) {
|
|
44
|
+
throw new Error(`Incorrect alias provided for query "${key}"`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
// also wrong
|
|
37
49
|
export const hasField = (field) => {
|
|
50
|
+
// get schema see if it actualy has the value (can find it on def)
|
|
38
51
|
if (!field) {
|
|
39
52
|
throw new Error(`Invalid field: ${field}`);
|
|
40
53
|
}
|
|
@@ -43,6 +56,7 @@ export const hasField = (field) => {
|
|
|
43
56
|
}
|
|
44
57
|
};
|
|
45
58
|
export const checkOperator = (operator) => {
|
|
59
|
+
// pass schema value (def) and complete for each prop + operator combination
|
|
46
60
|
if (operator !== undefined &&
|
|
47
61
|
typeof operator !== 'boolean' &&
|
|
48
62
|
!validOperators.includes(operator)) {
|
|
@@ -50,6 +64,7 @@ export const checkOperator = (operator) => {
|
|
|
50
64
|
}
|
|
51
65
|
};
|
|
52
66
|
export const checkValue = (value, operator) => {
|
|
67
|
+
// pass schema value (def) and complete for each prop + operator combination
|
|
53
68
|
if (operator === '..' || operator === '!..') {
|
|
54
69
|
if (!Array.isArray(value) || value.length !== 2) {
|
|
55
70
|
throw new Error(`Invalid value for operator ${operator}: expected an array with two elements`);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const convertToTimestamp: (value: string | Date | number) => number;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const timeToNumber = (ex) => {
|
|
2
|
+
if (ex === 's') {
|
|
3
|
+
return 1000;
|
|
4
|
+
}
|
|
5
|
+
if (ex === 'm') {
|
|
6
|
+
return 1000 * 60;
|
|
7
|
+
}
|
|
8
|
+
if (ex === 'h') {
|
|
9
|
+
return 1000 * 60 * 60;
|
|
10
|
+
}
|
|
11
|
+
if (ex === 'd') {
|
|
12
|
+
return 1000 * 60 * 60 * 24;
|
|
13
|
+
}
|
|
14
|
+
if (ex === 'y') {
|
|
15
|
+
return 31556952000;
|
|
16
|
+
}
|
|
17
|
+
return 1;
|
|
18
|
+
};
|
|
19
|
+
export const convertToTimestamp = (value) => {
|
|
20
|
+
if (value instanceof Date) {
|
|
21
|
+
return value.valueOf();
|
|
22
|
+
}
|
|
23
|
+
if (typeof value === 'string') {
|
|
24
|
+
if (value === 'now') {
|
|
25
|
+
return Date.now();
|
|
26
|
+
}
|
|
27
|
+
// MAKE THIS INTO A UTIL
|
|
28
|
+
const y = value.replace(/([+-])/g, ' $1 ');
|
|
29
|
+
const arr = y.split(/ +/);
|
|
30
|
+
let newValue = 0;
|
|
31
|
+
let now;
|
|
32
|
+
let op = 1;
|
|
33
|
+
for (const seg of arr) {
|
|
34
|
+
if (seg === '-') {
|
|
35
|
+
op = -1;
|
|
36
|
+
}
|
|
37
|
+
else if (seg === '+') {
|
|
38
|
+
op = 1;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
var v = 0;
|
|
42
|
+
if (seg === 'now') {
|
|
43
|
+
if (!now) {
|
|
44
|
+
now = Date.now();
|
|
45
|
+
}
|
|
46
|
+
v = now;
|
|
47
|
+
}
|
|
48
|
+
else if (/[smhdy]$/.test(seg)) {
|
|
49
|
+
const ex = seg[seg.length - 1];
|
|
50
|
+
const number = parseInt(seg, 10);
|
|
51
|
+
v = number * timeToNumber(ex);
|
|
52
|
+
}
|
|
53
|
+
else if (seg) {
|
|
54
|
+
v = new Date(seg).valueOf();
|
|
55
|
+
}
|
|
56
|
+
if (op === -1) {
|
|
57
|
+
newValue -= v;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
newValue += v;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return newValue;
|
|
65
|
+
}
|
|
66
|
+
return value;
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=timestamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const xxHash64: (buf: Buffer) => any;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -17,9 +17,12 @@ export declare class BasedDb {
|
|
|
17
17
|
maxModifySize?: number;
|
|
18
18
|
});
|
|
19
19
|
create: DbClient['create'];
|
|
20
|
+
copy: DbClient['copy'];
|
|
20
21
|
update: DbClient['update'];
|
|
21
22
|
upsert: DbClient['upsert'];
|
|
22
|
-
|
|
23
|
+
delete: DbClient['delete'];
|
|
24
|
+
expire: DbClient['expire'];
|
|
25
|
+
remove: DbClient['delete'];
|
|
23
26
|
query: DbClient['query'];
|
|
24
27
|
putSchema: DbClient['putSchema'];
|
|
25
28
|
drain: DbClient['drain'];
|
package/dist/src/index.js
CHANGED
|
@@ -27,9 +27,9 @@ export class BasedDb {
|
|
|
27
27
|
return Promise.resolve(server.putSchema(schema, fromStart));
|
|
28
28
|
},
|
|
29
29
|
flushModify(buf) {
|
|
30
|
-
server.modify(buf);
|
|
30
|
+
const offsets = server.modify(buf);
|
|
31
31
|
return Promise.resolve({
|
|
32
|
-
offsets
|
|
32
|
+
offsets,
|
|
33
33
|
});
|
|
34
34
|
},
|
|
35
35
|
getQueryBuf(buf) {
|
|
@@ -44,14 +44,24 @@ export class BasedDb {
|
|
|
44
44
|
create = function () {
|
|
45
45
|
return this.client.create.apply(this.client, arguments);
|
|
46
46
|
};
|
|
47
|
+
copy = function () {
|
|
48
|
+
return this.client.copy.apply(this.client, arguments);
|
|
49
|
+
};
|
|
47
50
|
update = function () {
|
|
48
51
|
return this.client.update.apply(this.client, arguments);
|
|
49
52
|
};
|
|
50
53
|
upsert = function () {
|
|
51
54
|
return this.client.upsert.apply(this.client, arguments);
|
|
52
55
|
};
|
|
56
|
+
delete = function () {
|
|
57
|
+
return this.client.delete.apply(this.client, arguments);
|
|
58
|
+
};
|
|
59
|
+
expire = function () {
|
|
60
|
+
return this.client.expire.apply(this.client, arguments);
|
|
61
|
+
};
|
|
53
62
|
remove = function () {
|
|
54
|
-
|
|
63
|
+
console.warn('WARNING: db.remove() is deprecated. Use db.delete() instead');
|
|
64
|
+
return this.client.delete.apply(this.client, arguments);
|
|
55
65
|
};
|
|
56
66
|
query = function () {
|
|
57
67
|
return this.client.query.apply(this.client, arguments);
|
package/dist/src/native.d.ts
CHANGED
package/dist/src/native.js
CHANGED
|
@@ -3,6 +3,7 @@ import { distance, min, max } from './tree-utils.js';
|
|
|
3
3
|
import membershipProof from './memebership-proof.js';
|
|
4
4
|
export function createTree(createHash) {
|
|
5
5
|
let root = null;
|
|
6
|
+
const emptyHash = genHash(Buffer.from(''));
|
|
6
7
|
function genHash(s) {
|
|
7
8
|
return createHash().update(s).digest();
|
|
8
9
|
}
|
|
@@ -12,7 +13,7 @@ export function createTree(createHash) {
|
|
|
12
13
|
function createNode(left, right) {
|
|
13
14
|
const hash = left && right
|
|
14
15
|
? genNodeHash(left.hash, right.hash)
|
|
15
|
-
:
|
|
16
|
+
: emptyHash;
|
|
16
17
|
return {
|
|
17
18
|
hash,
|
|
18
19
|
key: max(left, right),
|
|
@@ -80,7 +81,16 @@ export function createTree(createHash) {
|
|
|
80
81
|
const left = node.left;
|
|
81
82
|
const right = node.right;
|
|
82
83
|
if (!left || !right) {
|
|
83
|
-
|
|
84
|
+
console.log(node, k);
|
|
85
|
+
if (node.data) {
|
|
86
|
+
if (node.key === k) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`k=${k} does not exist`);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
throw new Error('The tree is broken');
|
|
93
|
+
}
|
|
84
94
|
}
|
|
85
95
|
if (checkForLeaf(left, k) || checkForLeaf(right, k)) {
|
|
86
96
|
if (left.key === k) {
|
|
@@ -3,6 +3,12 @@ import { SchemaTypeDef } from './schema/types.js';
|
|
|
3
3
|
import { createTree } from './csmt/index.js';
|
|
4
4
|
import { Worker, MessagePort } from 'node:worker_threads';
|
|
5
5
|
import { TransformFns } from './migrate/index.js';
|
|
6
|
+
declare class SortIndex {
|
|
7
|
+
constructor(buf: Buffer, dbCtxExternal: any);
|
|
8
|
+
buf: Buffer;
|
|
9
|
+
idx: any;
|
|
10
|
+
cnt: number;
|
|
11
|
+
}
|
|
6
12
|
export declare class DbWorker {
|
|
7
13
|
constructor(address: BigInt, db: DbServer);
|
|
8
14
|
db: DbServer;
|
|
@@ -59,17 +65,19 @@ export declare class DbServer {
|
|
|
59
65
|
sortIndexes: {
|
|
60
66
|
[type: number]: {
|
|
61
67
|
[field: number]: {
|
|
62
|
-
[start: number]:
|
|
68
|
+
[start: number]: SortIndex;
|
|
63
69
|
};
|
|
64
70
|
};
|
|
65
71
|
};
|
|
66
|
-
|
|
72
|
+
cleanupTimer: NodeJS.Timeout;
|
|
73
|
+
cleanup(): void;
|
|
74
|
+
createSortIndex(type: string, field: string): SortIndex;
|
|
67
75
|
destroySortIndex(type: string, field: string): any;
|
|
68
|
-
|
|
76
|
+
getSortIndex(typeId: number, field: number, start: number): SortIndex;
|
|
69
77
|
migrateSchema(schema: StrictSchema, transform?: Record<string, (node: Record<string, any>) => Record<string, any> | [string, Record<string, any>]>): Promise<StrictSchema & {
|
|
70
78
|
lastId: number;
|
|
71
79
|
}>;
|
|
72
|
-
createSortIndexBuffer(typeId: number, field: number, start: number):
|
|
80
|
+
createSortIndexBuffer(typeId: number, field: number, start: number): SortIndex;
|
|
73
81
|
updateMerkleTree(): void;
|
|
74
82
|
putSchema(strictSchema: StrictSchema, fromStart?: boolean, transformFns?: TransformFns): (StrictSchema & {
|
|
75
83
|
lastId: number;
|
package/dist/src/server/index.js
CHANGED
|
@@ -16,6 +16,15 @@ const SCHEMA_FILE = 'schema.json';
|
|
|
16
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
17
17
|
const __dirname = dirname(__filename);
|
|
18
18
|
const workerPath = join(__dirname, 'worker.js');
|
|
19
|
+
class SortIndex {
|
|
20
|
+
constructor(buf, dbCtxExternal) {
|
|
21
|
+
this.buf = buf;
|
|
22
|
+
this.idx = native.createSortIndex(buf, dbCtxExternal);
|
|
23
|
+
}
|
|
24
|
+
buf;
|
|
25
|
+
idx;
|
|
26
|
+
cnt = 0;
|
|
27
|
+
}
|
|
19
28
|
export class DbWorker {
|
|
20
29
|
constructor(address, db) {
|
|
21
30
|
const { port1, port2 } = new MessageChannel();
|
|
@@ -91,6 +100,35 @@ export class DbServer {
|
|
|
91
100
|
return this.csmtHashFun;
|
|
92
101
|
};
|
|
93
102
|
sortIndexes;
|
|
103
|
+
cleanupTimer;
|
|
104
|
+
cleanup() {
|
|
105
|
+
if (!this.cleanupTimer) {
|
|
106
|
+
// amount accessed
|
|
107
|
+
// current mem available
|
|
108
|
+
this.cleanupTimer = global.setTimeout(() => {
|
|
109
|
+
this.cleanupTimer = null;
|
|
110
|
+
let remaining;
|
|
111
|
+
for (const type in this.sortIndexes) {
|
|
112
|
+
for (const field in this.sortIndexes[type]) {
|
|
113
|
+
for (const start in this.sortIndexes[type][field]) {
|
|
114
|
+
const sortIndex = this.sortIndexes[type][field][start];
|
|
115
|
+
sortIndex.cnt /= 2;
|
|
116
|
+
if (sortIndex.cnt < 1) {
|
|
117
|
+
native.destroySortIndex(sortIndex.buf, this.dbCtxExternal);
|
|
118
|
+
delete this.sortIndexes[type][field][start];
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
remaining = true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (remaining) {
|
|
127
|
+
this.cleanup();
|
|
128
|
+
}
|
|
129
|
+
}, 60e3);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
94
132
|
createSortIndex(type, field) {
|
|
95
133
|
const t = this.schemaTypesParsed[type];
|
|
96
134
|
const prop = t.props[field];
|
|
@@ -113,7 +151,7 @@ export class DbServer {
|
|
|
113
151
|
buf.writeUint16LE(prop.start, 3);
|
|
114
152
|
buf.writeUint16LE(prop.len, 5);
|
|
115
153
|
buf[7] = prop.typeIndex;
|
|
116
|
-
sortIndex =
|
|
154
|
+
sortIndex = new SortIndex(buf, this.dbCtxExternal);
|
|
117
155
|
fields[prop.start] = sortIndex;
|
|
118
156
|
return sortIndex;
|
|
119
157
|
}
|
|
@@ -138,7 +176,7 @@ export class DbServer {
|
|
|
138
176
|
delete fields[prop.start];
|
|
139
177
|
}
|
|
140
178
|
}
|
|
141
|
-
|
|
179
|
+
getSortIndex(typeId, field, start) {
|
|
142
180
|
let types = this.sortIndexes[typeId];
|
|
143
181
|
if (!types) {
|
|
144
182
|
types = this.sortIndexes[typeId] = {};
|
|
@@ -147,11 +185,7 @@ export class DbServer {
|
|
|
147
185
|
if (!fields) {
|
|
148
186
|
fields = types[field] = {};
|
|
149
187
|
}
|
|
150
|
-
|
|
151
|
-
if (sortIndex) {
|
|
152
|
-
return true;
|
|
153
|
-
}
|
|
154
|
-
return false;
|
|
188
|
+
return fields[start];
|
|
155
189
|
}
|
|
156
190
|
migrateSchema(schema, transform) {
|
|
157
191
|
return migrate(this, schema, transform);
|
|
@@ -185,7 +219,7 @@ export class DbServer {
|
|
|
185
219
|
buf.writeUint16LE(prop.len, 5);
|
|
186
220
|
buf[7] = prop.typeIndex;
|
|
187
221
|
// put in modify stuff
|
|
188
|
-
const sortIndex =
|
|
222
|
+
const sortIndex = new SortIndex(buf, this.dbCtxExternal);
|
|
189
223
|
const types = this.sortIndexes[typeId];
|
|
190
224
|
const fields = types[field];
|
|
191
225
|
fields[start] = sortIndex;
|
|
@@ -279,7 +313,7 @@ export class DbServer {
|
|
|
279
313
|
}
|
|
280
314
|
if (strictSchema.props) {
|
|
281
315
|
// insert a root node
|
|
282
|
-
const data = [2, 1, 0, 0, 0, 9, 1, 0, 0, 0, 7, 1, 0, 1];
|
|
316
|
+
const data = [2, 1, 0, 0, 0, 17, 9, 1, 0, 0, 0, 7, 1, 0, 1];
|
|
283
317
|
const blockKey = makeCsmtKey(1, 1);
|
|
284
318
|
const buf = Buffer.alloc(data.length + 2 + 8 + 4);
|
|
285
319
|
// add content
|
|
@@ -353,14 +387,18 @@ export class DbServer {
|
|
|
353
387
|
const sort = buf.slice(s + 2, s + 2 + sortLen);
|
|
354
388
|
const field = sort[1];
|
|
355
389
|
const start = sort.readUint16LE(2 + 1);
|
|
356
|
-
|
|
390
|
+
let sortIndex = this.getSortIndex(typeId, field, start);
|
|
391
|
+
if (!sortIndex) {
|
|
357
392
|
if (this.processingQueries) {
|
|
358
393
|
return new Promise((resolve) => {
|
|
359
394
|
this.queryQueue.set(resolve, buf);
|
|
360
395
|
});
|
|
361
396
|
}
|
|
362
|
-
this.createSortIndexBuffer(typeId, field, start);
|
|
397
|
+
sortIndex = this.createSortIndexBuffer(typeId, field, start);
|
|
363
398
|
}
|
|
399
|
+
// increment
|
|
400
|
+
sortIndex.cnt++;
|
|
401
|
+
this.cleanup();
|
|
364
402
|
}
|
|
365
403
|
}
|
|
366
404
|
else if (queryType == 1) {
|
|
@@ -392,13 +430,21 @@ export class DbServer {
|
|
|
392
430
|
if (this.stopped) {
|
|
393
431
|
return;
|
|
394
432
|
}
|
|
395
|
-
|
|
396
|
-
|
|
433
|
+
this.stopped = true;
|
|
434
|
+
clearTimeout(this.cleanupTimer);
|
|
435
|
+
try {
|
|
436
|
+
if (!noSave) {
|
|
437
|
+
await this.save();
|
|
438
|
+
}
|
|
439
|
+
await Promise.all(this.workers.map(({ worker }) => worker.terminate()));
|
|
440
|
+
this.workers = [];
|
|
441
|
+
native.stop(this.dbCtxExternal);
|
|
442
|
+
await setTimeout();
|
|
443
|
+
}
|
|
444
|
+
catch (e) {
|
|
445
|
+
this.stopped = false;
|
|
446
|
+
throw e;
|
|
397
447
|
}
|
|
398
|
-
await Promise.all(this.workers.map(({ worker }) => worker.terminate()));
|
|
399
|
-
this.workers = [];
|
|
400
|
-
native.stop(this.dbCtxExternal);
|
|
401
|
-
await setTimeout();
|
|
402
448
|
}
|
|
403
449
|
async destroy() {
|
|
404
450
|
await this.stop(true);
|