web-dc-api 0.1.5 → 0.1.7
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/dist/cjs/index.js +1 -1
- package/dist/dc.min.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/index.d.ts +934 -878
- package/package.json +4 -8
- package/dist/cjs/helia-core-B1Xqha7a.js +0 -1
- package/dist/cjs/helia-core-D8Uv1KjQ.js +0 -1
- package/dist/cjs/polkadot-api-7PhQf3ws.js +0 -1
- package/dist/cjs/polkadot-api-CtrJVWuZ.js +0 -1
- package/dist/esm/chunks/helia-core-BxMqyK2Y.js +0 -1
- package/dist/esm/chunks/helia-core-DMXRpcO-.js +0 -1
- package/dist/esm/chunks/polkadot-api-5Y9Bw8VT.js +0 -1
- package/dist/esm/chunks/polkadot-api-D69Ioun_.js +0 -1
- package/lib/common/blowfish/block.ts +0 -259
- package/lib/common/blowfish/cipher.ts +0 -144
- package/lib/common/blowfish/const.ts +0 -195
- package/lib/common/chain.ts +0 -469
- package/lib/common/commonclient.ts +0 -202
- package/lib/common/constants.ts +0 -55
- package/lib/common/dc-key/ed25519.ts +0 -343
- package/lib/common/dc-key/keyManager.ts +0 -424
- package/lib/common/dcapi.ts +0 -98
- package/lib/common/dcutil.ts +0 -627
- package/lib/common/define.ts +0 -70
- package/lib/common/error.ts +0 -67
- package/lib/common/grpc-dc.ts +0 -104
- package/lib/common/module-system.ts +0 -184
- package/lib/common/service-worker.ts +0 -234
- package/lib/common/types/types.ts +0 -344
- package/lib/dc.ts +0 -701
- package/lib/implements/account/client.ts +0 -185
- package/lib/implements/account/manager.ts +0 -683
- package/lib/implements/aiproxy/client.ts +0 -357
- package/lib/implements/aiproxy/manager.ts +0 -670
- package/lib/implements/cache/client.ts +0 -105
- package/lib/implements/cache/manager.ts +0 -127
- package/lib/implements/comment/client.ts +0 -982
- package/lib/implements/comment/manager.ts +0 -1151
- package/lib/implements/dc/client.ts +0 -51
- package/lib/implements/dc/manager.ts +0 -33
- package/lib/implements/file/client.ts +0 -253
- package/lib/implements/file/file-cache-manager.ts +0 -142
- package/lib/implements/file/manager.ts +0 -1240
- package/lib/implements/file/seekableFileStream.ts +0 -344
- package/lib/implements/file/streamwriter.ts +0 -322
- package/lib/implements/keyvalue/client.ts +0 -376
- package/lib/implements/keyvalue/manager.ts +0 -759
- package/lib/implements/message/client.ts +0 -250
- package/lib/implements/message/manager.ts +0 -215
- package/lib/implements/threaddb/cbor/coding.ts +0 -62
- package/lib/implements/threaddb/cbor/event.ts +0 -336
- package/lib/implements/threaddb/cbor/node.ts +0 -542
- package/lib/implements/threaddb/cbor/record.ts +0 -398
- package/lib/implements/threaddb/common/AsyncMutex.ts +0 -24
- package/lib/implements/threaddb/common/addrinfo.ts +0 -135
- package/lib/implements/threaddb/common/dispatcher.ts +0 -81
- package/lib/implements/threaddb/common/idbstore-adapter.ts +0 -260
- package/lib/implements/threaddb/common/json-patcher.ts +0 -204
- package/lib/implements/threaddb/common/key.ts +0 -290
- package/lib/implements/threaddb/common/level-adapter.ts +0 -235
- package/lib/implements/threaddb/common/lineReader.ts +0 -79
- package/lib/implements/threaddb/common/logstore.ts +0 -215
- package/lib/implements/threaddb/common/transformed-datastore.ts +0 -308
- package/lib/implements/threaddb/core/app.ts +0 -206
- package/lib/implements/threaddb/core/core.ts +0 -230
- package/lib/implements/threaddb/core/db.ts +0 -249
- package/lib/implements/threaddb/core/event.ts +0 -54
- package/lib/implements/threaddb/core/head.ts +0 -89
- package/lib/implements/threaddb/core/identity.ts +0 -171
- package/lib/implements/threaddb/core/logstore.ts +0 -137
- package/lib/implements/threaddb/core/options.ts +0 -14
- package/lib/implements/threaddb/core/record.ts +0 -54
- package/lib/implements/threaddb/db/collection.ts +0 -1910
- package/lib/implements/threaddb/db/db.ts +0 -698
- package/lib/implements/threaddb/db/json2Query.ts +0 -192
- package/lib/implements/threaddb/db/query.ts +0 -524
- package/lib/implements/threaddb/dbclient.ts +0 -543
- package/lib/implements/threaddb/dbmanager.ts +0 -1906
- package/lib/implements/threaddb/lsstoreds/addr_book.ts +0 -549
- package/lib/implements/threaddb/lsstoreds/cache.ts +0 -36
- package/lib/implements/threaddb/lsstoreds/cyclic_batch.ts +0 -87
- package/lib/implements/threaddb/lsstoreds/global.ts +0 -151
- package/lib/implements/threaddb/lsstoreds/headbook.ts +0 -373
- package/lib/implements/threaddb/lsstoreds/keybook.ts +0 -297
- package/lib/implements/threaddb/lsstoreds/logstore.ts +0 -29
- package/lib/implements/threaddb/lsstoreds/metadata.ts +0 -223
- package/lib/implements/threaddb/net/define.ts +0 -149
- package/lib/implements/threaddb/net/grpcClient.ts +0 -589
- package/lib/implements/threaddb/net/grpcserver.ts +0 -146
- package/lib/implements/threaddb/net/net.ts +0 -2047
- package/lib/implements/threaddb/pb/lstore.proto +0 -38
- package/lib/implements/threaddb/pb/lstore.ts +0 -393
- package/lib/implements/threaddb/pb/lstore_pb.d.ts +0 -433
- package/lib/implements/threaddb/pb/lstore_pb.js +0 -1085
- package/lib/implements/threaddb/pb/net.proto +0 -194
- package/lib/implements/threaddb/pb/net_pb.d.ts +0 -2349
- package/lib/implements/threaddb/pb/net_pb.js +0 -5525
- package/lib/implements/threaddb/pb/proto-custom-types.ts +0 -212
- package/lib/implements/util/client.ts +0 -72
- package/lib/implements/util/manager.ts +0 -146
- package/lib/implements/wallet/manager.ts +0 -671
- package/lib/index.ts +0 -57
- package/lib/interfaces/DCContext.ts +0 -51
- package/lib/interfaces/aiproxy-interface.ts +0 -145
- package/lib/interfaces/auth-interface.ts +0 -118
- package/lib/interfaces/cache-interface.ts +0 -22
- package/lib/interfaces/client-interface.ts +0 -11
- package/lib/interfaces/comment-interface.ts +0 -167
- package/lib/interfaces/components/news-component.ts +0 -0
- package/lib/interfaces/database-interface.ts +0 -169
- package/lib/interfaces/file-interface.ts +0 -120
- package/lib/interfaces/index.ts +0 -10
- package/lib/interfaces/keyvalue-interface.ts +0 -156
- package/lib/interfaces/message-interface.ts +0 -22
- package/lib/interfaces/util-interface.ts +0 -31
- package/lib/modules/aiproxy-module.ts +0 -246
- package/lib/modules/auth-module.ts +0 -753
- package/lib/modules/cache-module.ts +0 -99
- package/lib/modules/client-module.ts +0 -71
- package/lib/modules/comment-module.ts +0 -429
- package/lib/modules/components/news-components.ts +0 -390
- package/lib/modules/database-module.ts +0 -598
- package/lib/modules/file-module.ts +0 -291
- package/lib/modules/index.ts +0 -13
- package/lib/modules/keyvalue-module.ts +0 -379
- package/lib/modules/message-module.ts +0 -107
- package/lib/modules/util-module.ts +0 -148
- package/lib/polyfills/process-env-browser.ts +0 -1
- package/lib/proto/datasource.ts +0 -93
- package/lib/proto/dcnet.proto +0 -1601
- package/lib/proto/dcnet_proto.d.ts +0 -22857
- package/lib/proto/dcnet_proto.js +0 -55204
- package/lib/proto/dcnet_proto_sparse.js +0 -55166
- package/lib/proto/oidfetch.proto +0 -25
- package/lib/proto/oidfetch_proto.d.ts +0 -585
- package/lib/proto/oidfetch_proto.js +0 -1247
- package/lib/serverless/babel-browser.ts +0 -39
- package/lib/serverless/base_entity.ts +0 -78
- package/lib/serverless/base_repository.ts +0 -414
- package/lib/serverless/browser_schema_extractor.ts +0 -283
- package/lib/serverless/decorator_factory.ts +0 -322
- package/lib/util/BrowserLineReader.ts +0 -73
- package/lib/util/base64.ts +0 -105
- package/lib/util/bcrypt.ts +0 -206
- package/lib/util/curve25519Encryption.ts +0 -418
- package/lib/util/dccrypt.ts +0 -73
- package/lib/util/logger.ts +0 -104
- package/lib/util/utils.ts +0 -289
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { Query,Criterion,Operation,Value as DbValue } from "./query";
|
|
3
|
-
// 查询条件定义
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// 查询对象结构
|
|
7
|
-
interface DCQuery {
|
|
8
|
-
condition: string; // [{"FieldPath": "name","Operation":"=","Value":""}}] //=,!=,<>,>,<,>=,<= aa >1 and bb > 1
|
|
9
|
-
ors: DCQuery[]; // 子查询对象
|
|
10
|
-
sort: any; // {"FieldPath": "Jimmy Kuu",}
|
|
11
|
-
seek: string; // 从指定instanceid开始获取结果
|
|
12
|
-
limit: number;
|
|
13
|
-
skip: number;
|
|
14
|
-
index: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// 错误定义
|
|
19
|
-
const ErrInvalidQueryConditionFormat = new Error("无效的查询条件格式");
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 解析JSON字符串为查询对象
|
|
23
|
-
* @param jsonQuery JSON查询字符串
|
|
24
|
-
* @returns 数据库查询对象
|
|
25
|
-
*/
|
|
26
|
-
export function parseJsonToQuery(jsonQuery: string): Query {
|
|
27
|
-
const queryObject: DCQuery = {
|
|
28
|
-
condition: '',
|
|
29
|
-
ors: [],
|
|
30
|
-
sort: {},
|
|
31
|
-
seek: '',
|
|
32
|
-
limit: 0,
|
|
33
|
-
skip: 0,
|
|
34
|
-
index: ''
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
if (jsonQuery === '') {
|
|
38
|
-
jsonQuery = '{}';
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
Object.assign(queryObject, JSON.parse(jsonQuery));
|
|
43
|
-
return dcQueryToDbQuery(queryObject);
|
|
44
|
-
} catch (err) {
|
|
45
|
-
throw new Error(`解析查询JSON失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 将自定义查询对象转换为数据库查询对象
|
|
51
|
-
* @param dcQuery 自定义查询对象
|
|
52
|
-
* @returns 数据库查询对象
|
|
53
|
-
*/
|
|
54
|
-
function dcQueryToDbQuery(dcQuery: DCQuery): Query {
|
|
55
|
-
try {
|
|
56
|
-
const ands = parseCondition(dcQuery.condition);
|
|
57
|
-
|
|
58
|
-
const dbQuery = new Query();
|
|
59
|
-
dbQuery.ands = ands;
|
|
60
|
-
dbQuery.sort = dcQuery.sort;
|
|
61
|
-
dbQuery.seek = dcQuery.seek;
|
|
62
|
-
dbQuery.limit = dcQuery.limit;
|
|
63
|
-
dbQuery.skip = dcQuery.skip;
|
|
64
|
-
dbQuery.index = dcQuery.index;
|
|
65
|
-
dbQuery.ors = [] as any[];
|
|
66
|
-
// 处理子查询
|
|
67
|
-
dbQuery.ors = dcQuery.ors?.map(query => dcQueryToDbQuery(query)) || [];
|
|
68
|
-
|
|
69
|
-
// 设置默认限制
|
|
70
|
-
if (dbQuery.limit === 0) {
|
|
71
|
-
dbQuery.limit = -1;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return dbQuery;
|
|
75
|
-
} catch (err) {
|
|
76
|
-
throw new Error(`转换查询对象失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* 解析条件字符串为条件对象数组
|
|
82
|
-
* @param condition 条件字符串
|
|
83
|
-
* @returns 条件对象数组
|
|
84
|
-
*/
|
|
85
|
-
function parseCondition(condition: string): Criterion[] {
|
|
86
|
-
// 根据 and 进行分解
|
|
87
|
-
if (!condition) return [];
|
|
88
|
-
|
|
89
|
-
const criterions = condition.split(' and ');
|
|
90
|
-
const ands: Criterion[] = [];
|
|
91
|
-
|
|
92
|
-
for (const criterion of criterions) {
|
|
93
|
-
// 解析出key,操作符以及值
|
|
94
|
-
try {
|
|
95
|
-
const parsed = parseSingleCondition(criterion);
|
|
96
|
-
if (!parsed || parsed.length !== 3) {
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const value = parseValue(parsed[2]!);
|
|
101
|
-
const queryCriterion = new Criterion(parsed[0]!, getDbQueryOperation(parsed[1]!), value);
|
|
102
|
-
ands.push(queryCriterion);
|
|
103
|
-
} catch (err) {
|
|
104
|
-
// 忽略解析错误的条件
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return ands;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* 解析值字符串为类型化的值对象
|
|
114
|
-
* @param strValue 值字符串
|
|
115
|
-
* @returns 类型化的值对象
|
|
116
|
-
*/
|
|
117
|
-
function parseValue(strValue: string): DbValue {
|
|
118
|
-
const value = new DbValue();
|
|
119
|
-
|
|
120
|
-
if (strValue[0] === "'" || strValue[0] === '"') {
|
|
121
|
-
const sValue = strValue.substring(1, strValue.length - 1);
|
|
122
|
-
value.string = sValue;
|
|
123
|
-
} else if (strValue === "true" || strValue === "false") {
|
|
124
|
-
const bValue = strValue === "true";
|
|
125
|
-
value.bool = bValue;
|
|
126
|
-
} else {
|
|
127
|
-
const fValue = parseFloat(strValue);
|
|
128
|
-
if (isNaN(fValue)) {
|
|
129
|
-
throw new Error(`无效的数字格式: ${strValue}`);
|
|
130
|
-
}
|
|
131
|
-
value.float = fValue;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return value;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// 支持的操作符
|
|
138
|
-
const splitOp = ["!=", ">=", "<=", "=", "<>", ">", "<"];
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* 解析单个条件字符串为操作数组
|
|
142
|
-
* @param condition 条件字符串
|
|
143
|
-
* @returns [字段路径, 操作符, 值] 数组
|
|
144
|
-
*/
|
|
145
|
-
function parseSingleCondition(condition: string): string[] {
|
|
146
|
-
for (const op of splitOp) {
|
|
147
|
-
const index = condition.indexOf(op);
|
|
148
|
-
if (index > 0) {
|
|
149
|
-
// 判断操作符是否出现在值的字符串中
|
|
150
|
-
const qStartIndex = condition.indexOf("'");
|
|
151
|
-
const dqStartIndex = condition.indexOf('"');
|
|
152
|
-
if ((qStartIndex > 0 && index > qStartIndex) || (dqStartIndex > 0 && index > dqStartIndex)) {
|
|
153
|
-
// 操作符出现在字符串中,不做处理,判断下一个操作符
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const parsedCondition: string[] = new Array(3);
|
|
158
|
-
parsedCondition[0] = condition.substring(0, index).trim();
|
|
159
|
-
parsedCondition[1] = op.trim();
|
|
160
|
-
parsedCondition[2] = condition.substring(index + op.length).trim();
|
|
161
|
-
return parsedCondition;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
throw ErrInvalidQueryConditionFormat;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* 获取数据库查询操作类型
|
|
170
|
-
* @param op 操作符字符串
|
|
171
|
-
* @returns 操作类型枚举值
|
|
172
|
-
*/
|
|
173
|
-
function getDbQueryOperation(op: string): Operation {
|
|
174
|
-
const top = op.trim();
|
|
175
|
-
switch (top) {
|
|
176
|
-
case "=":
|
|
177
|
-
return Operation.eq;
|
|
178
|
-
case "!=":
|
|
179
|
-
case "<>":
|
|
180
|
-
return Operation.ne;
|
|
181
|
-
case ">":
|
|
182
|
-
return Operation.gt;
|
|
183
|
-
case "<":
|
|
184
|
-
return Operation.lt;
|
|
185
|
-
case ">=":
|
|
186
|
-
return Operation.ge;
|
|
187
|
-
case "<=":
|
|
188
|
-
return Operation.le;
|
|
189
|
-
default:
|
|
190
|
-
return Operation.eq; // 默认等于
|
|
191
|
-
}
|
|
192
|
-
}
|
|
@@ -1,524 +0,0 @@
|
|
|
1
|
-
import { Key } from 'interface-datastore';
|
|
2
|
-
import { InstanceID,idFieldName } from '../core/db';
|
|
3
|
-
import { ThreadToken } from '../core/identity';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Query is a JSON-serializable query representation
|
|
8
|
-
*/
|
|
9
|
-
export class Query {
|
|
10
|
-
ands: Criterion[] = [];
|
|
11
|
-
ors: Query[] = [];
|
|
12
|
-
sort: Sort = new Sort();
|
|
13
|
-
seek: InstanceID = '';
|
|
14
|
-
limit: number = 0;
|
|
15
|
-
skip: number = 0;
|
|
16
|
-
index: string = '';
|
|
17
|
-
|
|
18
|
-
constructor() {
|
|
19
|
-
|
|
20
|
-
this.ands = [];
|
|
21
|
-
this.ors = [];
|
|
22
|
-
this.sort = new Sort();
|
|
23
|
-
this.seek = '';
|
|
24
|
-
this.limit = 0;
|
|
25
|
-
this.skip = 0;
|
|
26
|
-
this.index = '';
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Validate validates the entire query
|
|
32
|
-
*/
|
|
33
|
-
validate(): Error | null {
|
|
34
|
-
if (!this) return null;
|
|
35
|
-
|
|
36
|
-
for (const criterion of this.ands) {
|
|
37
|
-
const error = criterion.validate();
|
|
38
|
-
if (error) return error;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
for (const query of this.ors) {
|
|
42
|
-
const error = query.validate();
|
|
43
|
-
if (error) return error;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* And concatenates a new condition in an existing field
|
|
51
|
-
*/
|
|
52
|
-
and(field: string): Criterion {
|
|
53
|
-
return new Criterion(field);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Or concatenates a new condition that is sufficient
|
|
58
|
-
* for an instance to satisfy, independent of the current Query.
|
|
59
|
-
* Has left-associativity as: (a And b) Or c
|
|
60
|
-
*/
|
|
61
|
-
or(orQuery: Query): Query {
|
|
62
|
-
this.ors.push(orQuery);
|
|
63
|
-
return this;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* UseIndex specifies the index to use when running this query
|
|
68
|
-
*/
|
|
69
|
-
useIndex(path: string): Query {
|
|
70
|
-
this.index = path;
|
|
71
|
-
return this;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* OrderBy specifies ascending order for the query results
|
|
76
|
-
*/
|
|
77
|
-
orderBy(field: string): Query {
|
|
78
|
-
this.sort.fieldPath = field;
|
|
79
|
-
this.sort.desc = false;
|
|
80
|
-
return this;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* OrderByDesc specifies descending order for the query results
|
|
85
|
-
*/
|
|
86
|
-
orderByDesc(field: string): Query {
|
|
87
|
-
this.sort.fieldPath = field;
|
|
88
|
-
this.sort.desc = true;
|
|
89
|
-
return this;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* OrderByID specifies ascending ID order for the query results
|
|
94
|
-
*/
|
|
95
|
-
orderById(): Query {
|
|
96
|
-
this.sort.fieldPath = "_id";
|
|
97
|
-
this.sort.desc = false;
|
|
98
|
-
return this;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* OrderByIDDesc specifies descending ID order for the query results
|
|
103
|
-
*/
|
|
104
|
-
orderByIdDesc(): Query {
|
|
105
|
-
this.sort.fieldPath = "_id";
|
|
106
|
-
this.sort.desc = true;
|
|
107
|
-
return this;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* SeekID seeks to the given ID before returning query results
|
|
112
|
-
*/
|
|
113
|
-
seekId(id: InstanceID): Query {
|
|
114
|
-
this.seek = id;
|
|
115
|
-
return this;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* LimitTo sets the maximum number of results
|
|
120
|
-
*/
|
|
121
|
-
limitTo(limit: number): Query {
|
|
122
|
-
this.limit = limit;
|
|
123
|
-
return this;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* SkipNum skips the given number of results
|
|
128
|
-
*/
|
|
129
|
-
skipNum(num: number): Query {
|
|
130
|
-
this.skip = num;
|
|
131
|
-
return this;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Match checks if the given object matches this query
|
|
136
|
-
*/
|
|
137
|
-
match(v: Record<string, any>): boolean {
|
|
138
|
-
if (!this) {
|
|
139
|
-
throw new Error("query can't be null");
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Check all AND conditions
|
|
143
|
-
let andOk = true;
|
|
144
|
-
for (const c of this.ands) {
|
|
145
|
-
try {
|
|
146
|
-
const fieldRes = traverseFieldPathMap(v, c.fieldPath);
|
|
147
|
-
const ok = c.match(fieldRes);
|
|
148
|
-
andOk = andOk && ok;
|
|
149
|
-
if (!andOk) {
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
} catch (err) {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (andOk) {
|
|
158
|
-
return true;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Check all OR conditions if AND fails
|
|
162
|
-
for (const q of this.ors) {
|
|
163
|
-
try {
|
|
164
|
-
if (q.match(v)) {
|
|
165
|
-
return true;
|
|
166
|
-
}
|
|
167
|
-
} catch (err) {
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Criterion represents a restriction on a field
|
|
178
|
-
*/
|
|
179
|
-
export class Criterion {
|
|
180
|
-
fieldPath: string;
|
|
181
|
-
operation: Operation = Operation.eq;
|
|
182
|
-
value: Value = new Value();
|
|
183
|
-
private query: Query | null = null;
|
|
184
|
-
|
|
185
|
-
constructor(fieldPath: string, operation?:Operation,value?:Value) {
|
|
186
|
-
this.fieldPath = fieldPath;
|
|
187
|
-
this.operation = operation!;
|
|
188
|
-
this.value = value!;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Validate validates a single query criterion
|
|
193
|
-
*/
|
|
194
|
-
validate(): Error | null {
|
|
195
|
-
if (!this) return null;
|
|
196
|
-
|
|
197
|
-
let nonNullCount = 0;
|
|
198
|
-
if (this.value.bool !== null) nonNullCount++;
|
|
199
|
-
if (this.value.string !== null) nonNullCount++;
|
|
200
|
-
if (this.value.float !== null) nonNullCount++;
|
|
201
|
-
|
|
202
|
-
if (nonNullCount !== 1) {
|
|
203
|
-
return new Error("value type should describe exactly one type");
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Eq is an equality operator against a field
|
|
211
|
-
*/
|
|
212
|
-
eq(value: any): Query {
|
|
213
|
-
return this.createCriterion(Operation.eq, value);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Ne is a not equal operator against a field
|
|
218
|
-
*/
|
|
219
|
-
ne(value: any): Query {
|
|
220
|
-
return this.createCriterion(Operation.ne, value);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Gt is a greater operator against a field
|
|
225
|
-
*/
|
|
226
|
-
gt(value: any): Query {
|
|
227
|
-
return this.createCriterion(Operation.gt, value);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Lt is a less operation against a field
|
|
232
|
-
*/
|
|
233
|
-
lt(value: any): Query {
|
|
234
|
-
return this.createCriterion(Operation.lt, value);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Ge is a greater or equal operator against a field
|
|
239
|
-
*/
|
|
240
|
-
ge(value: any): Query {
|
|
241
|
-
return this.createCriterion(Operation.ge, value);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Le is a less or equal operator against a field
|
|
246
|
-
*/
|
|
247
|
-
le(value: any): Query {
|
|
248
|
-
return this.createCriterion(Operation.le, value);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Creates a criterion with the specified operation and value
|
|
253
|
-
*/
|
|
254
|
-
private createCriterion(op: Operation, val: any): Query {
|
|
255
|
-
this.operation = op;
|
|
256
|
-
this.value = createValue(val);
|
|
257
|
-
|
|
258
|
-
if (!this.query) {
|
|
259
|
-
this.query = new Query();
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
this.query.ands.push(this);
|
|
263
|
-
return this.query;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Match checks if the given value matches this criterion
|
|
268
|
-
*/
|
|
269
|
-
match(value: any): boolean {
|
|
270
|
-
try {
|
|
271
|
-
const result = compareValue(value, this.value);
|
|
272
|
-
|
|
273
|
-
switch (this.operation) {
|
|
274
|
-
case Operation.eq:
|
|
275
|
-
return result === 0;
|
|
276
|
-
case Operation.ne:
|
|
277
|
-
return result !== 0;
|
|
278
|
-
case Operation.gt:
|
|
279
|
-
return result > 0;
|
|
280
|
-
case Operation.lt:
|
|
281
|
-
return result < 0;
|
|
282
|
-
case Operation.le:
|
|
283
|
-
return result <= 0;
|
|
284
|
-
case Operation.ge:
|
|
285
|
-
return result >= 0;
|
|
286
|
-
default:
|
|
287
|
-
throw new Error("invalid operation");
|
|
288
|
-
}
|
|
289
|
-
} catch (err) {
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Value models a single value in JSON
|
|
297
|
-
*/
|
|
298
|
-
export class Value {
|
|
299
|
-
string: string | null = null;
|
|
300
|
-
bool: boolean | null = null;
|
|
301
|
-
float: number | null = null;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Sort represents a sort order on a field
|
|
306
|
-
*/
|
|
307
|
-
export class Sort {
|
|
308
|
-
fieldPath: string = '';
|
|
309
|
-
desc: boolean = false;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Operation models comparison operators
|
|
314
|
-
*/
|
|
315
|
-
export enum Operation {
|
|
316
|
-
eq = 0, // equals
|
|
317
|
-
ne = 1, // not equal to
|
|
318
|
-
gt = 2, // greater than
|
|
319
|
-
lt = 3, // less than
|
|
320
|
-
ge = 4, // greater than or equal to
|
|
321
|
-
le = 5, // less than or equal to
|
|
322
|
-
fn = 6 //func
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
export class TypeMismatchError extends Error {
|
|
327
|
-
constructor(value: any, expected: Value) {
|
|
328
|
-
let expectedType = "unknown";
|
|
329
|
-
if (expected.string !== null) expectedType = "string";
|
|
330
|
-
if (expected.bool !== null) expectedType = "boolean";
|
|
331
|
-
if (expected.float !== null) expectedType = "number";
|
|
332
|
-
|
|
333
|
-
super(`Type mismatch: value ${value} is not of expected type ${expectedType}`);
|
|
334
|
-
this.name = "TypeMismatchError";
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Helper functions
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Where starts to create a query condition for a field
|
|
342
|
-
*/
|
|
343
|
-
export function where(field: string): Criterion {
|
|
344
|
-
return new Criterion(field);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* OrderBy specifies ascending order for the query results
|
|
349
|
-
*/
|
|
350
|
-
export function orderBy(field: string): Query {
|
|
351
|
-
const q = new Query();
|
|
352
|
-
q.sort.fieldPath = field;
|
|
353
|
-
q.sort.desc = false;
|
|
354
|
-
return q;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* OrderByDesc specifies descending order for the query results
|
|
359
|
-
*/
|
|
360
|
-
export function orderByDesc(field: string): Query {
|
|
361
|
-
const q = new Query();
|
|
362
|
-
q.sort.fieldPath = field;
|
|
363
|
-
q.sort.desc = true;
|
|
364
|
-
return q;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* OrderByID specifies ascending ID order for the query results
|
|
369
|
-
*/
|
|
370
|
-
export function orderById(): Query {
|
|
371
|
-
const q = new Query();
|
|
372
|
-
q.sort.fieldPath = "_id";
|
|
373
|
-
q.sort.desc = false;
|
|
374
|
-
return q;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* OrderByIDDesc specifies descending ID order for the query results
|
|
379
|
-
*/
|
|
380
|
-
export function orderByIdDesc(): Query {
|
|
381
|
-
const q = new Query();
|
|
382
|
-
q.sort.fieldPath = "_id";
|
|
383
|
-
q.sort.desc = true;
|
|
384
|
-
return q;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Creates a Value from a JavaScript value
|
|
389
|
-
*/
|
|
390
|
-
function createValue(value: any): Value {
|
|
391
|
-
const v = new Value();
|
|
392
|
-
|
|
393
|
-
if (typeof value === "string") {
|
|
394
|
-
v.string = value;
|
|
395
|
-
} else if (typeof value === "boolean") {
|
|
396
|
-
v.bool = value;
|
|
397
|
-
} else if (typeof value === "number") {
|
|
398
|
-
v.float = value;
|
|
399
|
-
} else if (value === null) {
|
|
400
|
-
// Leave all properties null
|
|
401
|
-
} else {
|
|
402
|
-
console.warn("Unsupported value type:", value);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
return v;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Compares a JavaScript value to a Value
|
|
416
|
-
*/
|
|
417
|
-
function compareValue(value: any, critVal: Value): number {
|
|
418
|
-
if (critVal.string !== null) {
|
|
419
|
-
const s = typeof value === "string" ? value : "";
|
|
420
|
-
return s.localeCompare(critVal.string);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
if (critVal.bool !== null) {
|
|
424
|
-
const b = typeof value === "boolean" ? value : false;
|
|
425
|
-
return b === critVal.bool ? 0 : -1;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
if (critVal.float !== null) {
|
|
429
|
-
const f = typeof value === "number" ? value : 0;
|
|
430
|
-
if (f === critVal.float) return 0;
|
|
431
|
-
if (f < critVal.float) return -1;
|
|
432
|
-
return 1;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
throw new Error("no underlying value for criterion was provided");
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
* Returns a deeply nested property from an object
|
|
440
|
-
*/
|
|
441
|
-
export function traverseFieldPathMap(value: Record<string, any>, fieldPath: string): any {
|
|
442
|
-
const fields = fieldPath.split('.');
|
|
443
|
-
|
|
444
|
-
let curr: any = value;
|
|
445
|
-
for (const field of fields) {
|
|
446
|
-
if (!curr || typeof curr !== 'object') {
|
|
447
|
-
return undefined;
|
|
448
|
-
}
|
|
449
|
-
curr = curr[field];
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
return curr;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* Compares two values for sorting
|
|
457
|
-
*/
|
|
458
|
-
export function compare(a: any, b: any): number {
|
|
459
|
-
if (a === b) return 0;
|
|
460
|
-
|
|
461
|
-
if (typeof a !== typeof b) {
|
|
462
|
-
throw new Error("Cannot compare different types");
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
if (typeof a === "string") {
|
|
466
|
-
return a.localeCompare(b);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
if (typeof a === "number") {
|
|
470
|
-
return a - b;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
if (typeof a === "boolean") {
|
|
474
|
-
return (a === b) ? 0 : (a ? 1 : -1);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
throw new Error("Cannot compare values of type " + typeof a);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
// Class for handling modified since queries
|
|
481
|
-
export class ModifiedSinceHandler {
|
|
482
|
-
/**
|
|
483
|
-
* Gets instances modified since a specific time
|
|
484
|
-
*/
|
|
485
|
-
static async modifiedSince(
|
|
486
|
-
txn: any,
|
|
487
|
-
dsDispatcherPrefix: Key,
|
|
488
|
-
collectionName: string,
|
|
489
|
-
time: number
|
|
490
|
-
): Promise<InstanceID[]> {
|
|
491
|
-
// Convert time to string for key operations
|
|
492
|
-
const timestr = time.toString();
|
|
493
|
-
|
|
494
|
-
// Create the query filter function
|
|
495
|
-
const collectionFilter = (item: any) => {
|
|
496
|
-
const key = new Key(item.key.toString());
|
|
497
|
-
return key.type() === collectionName;
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
// Execute query
|
|
501
|
-
const res = await txn.queryExtended({
|
|
502
|
-
prefix: dsDispatcherPrefix.toString(),
|
|
503
|
-
filters: [collectionFilter],
|
|
504
|
-
keysOnly: true,
|
|
505
|
-
seekPrefix: dsDispatcherPrefix.child(new Key(timestr)).toString()
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
// Create a set to store unique instance IDs
|
|
509
|
-
const instanceIdSet = new Set<InstanceID>();
|
|
510
|
-
|
|
511
|
-
// Process query results
|
|
512
|
-
for await (const entry of res) {
|
|
513
|
-
if (entry.error) {
|
|
514
|
-
throw new Error(`Query error: ${entry.error}`);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
const key = new Key(entry.key);
|
|
518
|
-
instanceIdSet.add(key.name() as InstanceID);
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// Convert set to array
|
|
522
|
-
return Array.from(instanceIdSet);
|
|
523
|
-
}
|
|
524
|
-
}
|