@yanit/jsondb 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/README.md +903 -0
  2. package/dist/bin/cli-export.d.ts +7 -0
  3. package/dist/bin/cli-export.d.ts.map +1 -0
  4. package/dist/bin/cli-export.js +318 -0
  5. package/dist/bin/cli-export.js.map +1 -0
  6. package/dist/bin/cli-import.d.ts +7 -0
  7. package/dist/bin/cli-import.d.ts.map +1 -0
  8. package/dist/bin/cli-import.js +298 -0
  9. package/dist/bin/cli-import.js.map +1 -0
  10. package/dist/bin/server.d.ts +7 -0
  11. package/dist/bin/server.d.ts.map +1 -0
  12. package/dist/bin/server.js +92 -0
  13. package/dist/bin/server.js.map +1 -0
  14. package/dist/examples/sql-example.d.ts +7 -0
  15. package/dist/examples/sql-example.d.ts.map +1 -0
  16. package/dist/examples/sql-example.js +131 -0
  17. package/dist/examples/sql-example.js.map +1 -0
  18. package/dist/src/BulkOp.d.ts +74 -0
  19. package/dist/src/BulkOp.d.ts.map +1 -0
  20. package/dist/src/BulkOp.js +143 -0
  21. package/dist/src/BulkOp.js.map +1 -0
  22. package/dist/src/Collection.d.ts +232 -0
  23. package/dist/src/Collection.d.ts.map +1 -0
  24. package/dist/src/Collection.js +705 -0
  25. package/dist/src/Collection.js.map +1 -0
  26. package/dist/src/Cursor.d.ts +94 -0
  27. package/dist/src/Cursor.d.ts.map +1 -0
  28. package/dist/src/Cursor.js +259 -0
  29. package/dist/src/Cursor.js.map +1 -0
  30. package/dist/src/Database.d.ts +98 -0
  31. package/dist/src/Database.d.ts.map +1 -0
  32. package/dist/src/Database.js +198 -0
  33. package/dist/src/Database.js.map +1 -0
  34. package/dist/src/Operators.d.ts +73 -0
  35. package/dist/src/Operators.d.ts.map +1 -0
  36. package/dist/src/Operators.js +339 -0
  37. package/dist/src/Operators.js.map +1 -0
  38. package/dist/src/QueryCache.d.ts +87 -0
  39. package/dist/src/QueryCache.d.ts.map +1 -0
  40. package/dist/src/QueryCache.js +155 -0
  41. package/dist/src/QueryCache.js.map +1 -0
  42. package/dist/src/SQLExecutor.d.ts +60 -0
  43. package/dist/src/SQLExecutor.d.ts.map +1 -0
  44. package/dist/src/SQLExecutor.js +317 -0
  45. package/dist/src/SQLExecutor.js.map +1 -0
  46. package/dist/src/SQLParser.d.ts +181 -0
  47. package/dist/src/SQLParser.d.ts.map +1 -0
  48. package/dist/src/SQLParser.js +640 -0
  49. package/dist/src/SQLParser.js.map +1 -0
  50. package/dist/src/Schema.d.ts +92 -0
  51. package/dist/src/Schema.d.ts.map +1 -0
  52. package/dist/src/Schema.js +253 -0
  53. package/dist/src/Schema.js.map +1 -0
  54. package/dist/src/Transaction.d.ts +118 -0
  55. package/dist/src/Transaction.d.ts.map +1 -0
  56. package/dist/src/Transaction.js +233 -0
  57. package/dist/src/Transaction.js.map +1 -0
  58. package/dist/src/Utils.d.ts +68 -0
  59. package/dist/src/Utils.d.ts.map +1 -0
  60. package/dist/src/Utils.js +187 -0
  61. package/dist/src/Utils.js.map +1 -0
  62. package/dist/src/errors.d.ts +58 -0
  63. package/dist/src/errors.d.ts.map +1 -0
  64. package/dist/src/errors.js +85 -0
  65. package/dist/src/errors.js.map +1 -0
  66. package/dist/src/index.d.ts +39 -0
  67. package/dist/src/index.d.ts.map +1 -0
  68. package/dist/src/index.js +44 -0
  69. package/dist/src/index.js.map +1 -0
  70. package/dist/test/basic.test.d.ts +5 -0
  71. package/dist/test/basic.test.d.ts.map +1 -0
  72. package/dist/test/basic.test.js +283 -0
  73. package/dist/test/basic.test.js.map +1 -0
  74. package/dist/test/index.test.d.ts +5 -0
  75. package/dist/test/index.test.d.ts.map +1 -0
  76. package/dist/test/index.test.js +126 -0
  77. package/dist/test/index.test.js.map +1 -0
  78. package/dist/test/jsonb.test.d.ts +5 -0
  79. package/dist/test/jsonb.test.d.ts.map +1 -0
  80. package/dist/test/jsonb.test.js +165 -0
  81. package/dist/test/jsonb.test.js.map +1 -0
  82. package/dist/test/optimization.test.d.ts +6 -0
  83. package/dist/test/optimization.test.d.ts.map +1 -0
  84. package/dist/test/optimization.test.js +196 -0
  85. package/dist/test/optimization.test.js.map +1 -0
  86. package/dist/test/schema.test.d.ts +5 -0
  87. package/dist/test/schema.test.d.ts.map +1 -0
  88. package/dist/test/schema.test.js +197 -0
  89. package/dist/test/schema.test.js.map +1 -0
  90. package/dist/test/sql.test.d.ts +7 -0
  91. package/dist/test/sql.test.d.ts.map +1 -0
  92. package/dist/test/sql.test.js +21 -0
  93. package/dist/test/sql.test.js.map +1 -0
  94. package/package.json +73 -0
  95. package/src/BulkOp.js +181 -0
  96. package/src/BulkOp.ts +191 -0
  97. package/src/Collection.js +843 -0
  98. package/src/Collection.ts +896 -0
  99. package/src/Cursor.js +315 -0
  100. package/src/Cursor.ts +319 -0
  101. package/src/Database.js +244 -0
  102. package/src/Database.ts +268 -0
  103. package/src/Operators.js +382 -0
  104. package/src/Operators.ts +375 -0
  105. package/src/QueryCache.js +190 -0
  106. package/src/QueryCache.ts +208 -0
  107. package/src/SQLExecutor.ts +391 -0
  108. package/src/SQLParser.ts +814 -0
  109. package/src/Schema.js +292 -0
  110. package/src/Schema.ts +317 -0
  111. package/src/Transaction.js +291 -0
  112. package/src/Transaction.ts +313 -0
  113. package/src/Utils.js +205 -0
  114. package/src/Utils.ts +205 -0
  115. package/src/errors.js +93 -0
  116. package/src/errors.ts +93 -0
  117. package/src/index.js +90 -0
  118. package/src/index.ts +106 -0
@@ -0,0 +1,382 @@
1
+ /**
2
+ * 查询和操作符实现
3
+ */
4
+
5
+ import { getNestedValue, isType, setNestedValue, deleteNestedValue } from './Utils.js';
6
+
7
+ /**
8
+ * 比较操作符
9
+ */
10
+ export const comparisonOperators = {
11
+ $eq: (value, queryValue) => value === queryValue,
12
+
13
+ $ne: (value, queryValue) => value !== queryValue,
14
+
15
+ $gt: (value, queryValue) => value > queryValue,
16
+
17
+ $gte: (value, queryValue) => value >= queryValue,
18
+
19
+ $lt: (value, queryValue) => value < queryValue,
20
+
21
+ $lte: (value, queryValue) => value <= queryValue,
22
+
23
+ $in: (value, queryValue) => {
24
+ if (!Array.isArray(queryValue)) {
25
+ throw new Error('$in 操作符需要数组');
26
+ }
27
+ return queryValue.includes(value);
28
+ },
29
+
30
+ $nin: (value, queryValue) => {
31
+ if (!Array.isArray(queryValue)) {
32
+ throw new Error('$nin 操作符需要数组');
33
+ }
34
+ return !queryValue.includes(value);
35
+ }
36
+ };
37
+
38
+ /**
39
+ * 逻辑操作符
40
+ */
41
+ export const logicalOperators = {
42
+ $and: (doc, conditions) => {
43
+ if (!Array.isArray(conditions)) {
44
+ throw new Error('$and 操作符需要数组');
45
+ }
46
+ return conditions.every(condition => matchQuery(doc, condition));
47
+ },
48
+
49
+ $or: (doc, conditions) => {
50
+ if (!Array.isArray(conditions)) {
51
+ throw new Error('$or 操作符需要数组');
52
+ }
53
+ return conditions.some(condition => matchQuery(doc, condition));
54
+ },
55
+
56
+ $nor: (doc, conditions) => {
57
+ if (!Array.isArray(conditions)) {
58
+ throw new Error('$nor 操作符需要数组');
59
+ }
60
+ return !conditions.some(condition => matchQuery(doc, condition));
61
+ },
62
+
63
+ $not: (doc, condition, field) => {
64
+ return !matchField(doc, field, condition);
65
+ }
66
+ };
67
+
68
+ /**
69
+ * 元素操作符
70
+ */
71
+ export const elementOperators = {
72
+ $exists: (value, queryValue) => {
73
+ return queryValue ? value !== undefined : value === undefined;
74
+ },
75
+
76
+ $type: (value, queryValue) => {
77
+ return isType(value, queryValue);
78
+ }
79
+ };
80
+
81
+ /**
82
+ * 数组操作符
83
+ */
84
+ export const arrayOperators = {
85
+ $all: (value, queryValue) => {
86
+ if (!Array.isArray(value)) {
87
+ return false;
88
+ }
89
+ if (!Array.isArray(queryValue)) {
90
+ throw new Error('$all 操作符需要数组');
91
+ }
92
+ return queryValue.every(item => value.includes(item));
93
+ },
94
+
95
+ $elemMatch: (value, queryValue) => {
96
+ if (!Array.isArray(value)) {
97
+ return false;
98
+ }
99
+ // 处理数组元素匹配
100
+ return value.some(item => {
101
+ // 如果 queryValue 是对象,需要匹配所有条件
102
+ if (typeof queryValue === 'object' && queryValue !== null) {
103
+ for (const [key, condition] of Object.entries(queryValue)) {
104
+ const itemValue = item[key] !== undefined ? item[key] : (typeof key === 'string' && item[key] !== undefined ? item[key] : undefined);
105
+ if (typeof condition === 'object' && condition !== null) {
106
+ // 处理操作符条件
107
+ for (const [op, opValue] of Object.entries(condition)) {
108
+ if (op === '$gte' && !(itemValue >= opValue)) return false;
109
+ if (op === '$lte' && !(itemValue <= opValue)) return false;
110
+ if (op === '$gt' && !(itemValue > opValue)) return false;
111
+ if (op === '$lt' && !(itemValue < opValue)) return false;
112
+ if (op === '$eq' && !(itemValue === opValue)) return false;
113
+ if (op === '$ne' && !(itemValue !== opValue)) return false;
114
+ }
115
+ } else if (itemValue !== condition) {
116
+ return false;
117
+ }
118
+ }
119
+ return true;
120
+ }
121
+ return item === queryValue;
122
+ });
123
+ },
124
+
125
+ $size: (value, queryValue) => {
126
+ if (!Array.isArray(value)) {
127
+ return false;
128
+ }
129
+ return value.length === queryValue;
130
+ }
131
+ };
132
+
133
+ /**
134
+ * 正则表达式操作符
135
+ */
136
+ export function matchRegex(value, options) {
137
+ if (typeof value !== 'string') {
138
+ return false;
139
+ }
140
+
141
+ const { $regex, $options = '' } = options;
142
+
143
+ try {
144
+ const regex = typeof $regex === 'string' ? new RegExp($regex, $options) : $regex;
145
+ return regex.test(value);
146
+ } catch (e) {
147
+ throw new Error(`无效的正则表达式:${$regex}`);
148
+ }
149
+ }
150
+
151
+ /**
152
+ * 匹配字段值
153
+ * @param {Object} doc - 文档
154
+ * @param {string} field - 字段名
155
+ * @param {Object} condition - 条件
156
+ * @returns {boolean}
157
+ */
158
+ function matchField(doc, field, condition) {
159
+ const value = getNestedValue(doc, field);
160
+
161
+ // 如果条件是普通值,直接比较
162
+ if (!condition || typeof condition !== 'object') {
163
+ return value === condition;
164
+ }
165
+
166
+ // 处理操作符
167
+ let hasOperatorMatch = false;
168
+
169
+ for (const [operator, queryValue] of Object.entries(condition)) {
170
+ if (operator.startsWith('$')) {
171
+ // $options 是 $regex 的修饰符,跳过
172
+ if (operator === '$options') {
173
+ continue;
174
+ }
175
+
176
+ hasOperatorMatch = true;
177
+ let result;
178
+
179
+ // 比较操作符
180
+ if (comparisonOperators[operator]) {
181
+ result = comparisonOperators[operator](value, queryValue);
182
+ }
183
+ // 元素操作符
184
+ else if (elementOperators[operator]) {
185
+ result = elementOperators[operator](value, queryValue);
186
+ }
187
+ // 数组操作符
188
+ else if (arrayOperators[operator]) {
189
+ result = arrayOperators[operator](value, queryValue);
190
+ }
191
+ // 正则操作符
192
+ else if (operator === '$regex') {
193
+ result = matchRegex(value, condition);
194
+ }
195
+ // 未知操作符
196
+ else {
197
+ throw new Error(`未知操作符:${operator}`);
198
+ }
199
+
200
+ if (!result) {
201
+ return false;
202
+ }
203
+ }
204
+ }
205
+
206
+ // 如果没有操作符匹配,直接比较值
207
+ if (!hasOperatorMatch) {
208
+ return value === condition;
209
+ }
210
+
211
+ return true;
212
+ }
213
+
214
+ /**
215
+ * 匹配查询条件
216
+ * @param {Object} doc - 文档
217
+ * @param {Object} query - 查询条件
218
+ * @returns {boolean}
219
+ */
220
+ export function matchQuery(doc, query) {
221
+ if (!query || typeof query !== 'object') {
222
+ return true;
223
+ }
224
+
225
+ for (const [key, condition] of Object.entries(query)) {
226
+ // 逻辑操作符
227
+ if (key.startsWith('$')) {
228
+ if (logicalOperators[key]) {
229
+ const result = logicalOperators[key](doc, condition);
230
+ if (!result) {
231
+ return false;
232
+ }
233
+ } else {
234
+ throw new Error(`未知逻辑操作符:${key}`);
235
+ }
236
+ } else {
237
+ // 字段匹配
238
+ const result = matchField(doc, key, condition);
239
+ if (!result) {
240
+ return false;
241
+ }
242
+ }
243
+ }
244
+
245
+ return true;
246
+ }
247
+
248
+ /**
249
+ * 更新操作符实现
250
+ */
251
+ export const updateOperators = {
252
+ $set: (doc, updates) => {
253
+ for (const [path, value] of Object.entries(updates)) {
254
+ setNestedValue(doc, path, value);
255
+ }
256
+ },
257
+
258
+ $unset: (doc, paths) => {
259
+ for (const path of Object.keys(paths)) {
260
+ deleteNestedValue(doc, path);
261
+ }
262
+ },
263
+
264
+ $inc: (doc, updates) => {
265
+ for (const [path, value] of Object.entries(updates)) {
266
+ const currentValue = getNestedValue(doc, path) || 0;
267
+ setNestedValue(doc, path, currentValue + value);
268
+ }
269
+ },
270
+
271
+ $mul: (doc, updates) => {
272
+ for (const [path, value] of Object.entries(updates)) {
273
+ const currentValue = getNestedValue(doc, path) || 1;
274
+ setNestedValue(doc, path, currentValue * value);
275
+ }
276
+ },
277
+
278
+ $rename: (doc, renames) => {
279
+ for (const [oldPath, newPath] of Object.entries(renames)) {
280
+ const value = getNestedValue(doc, oldPath);
281
+ if (value !== undefined) {
282
+ setNestedValue(doc, newPath, value);
283
+ deleteNestedValue(doc, oldPath);
284
+ }
285
+ }
286
+ },
287
+
288
+ $setOnInsert: (doc, updates, isInsert) => {
289
+ if (isInsert) {
290
+ updateOperators.$set(doc, updates);
291
+ }
292
+ },
293
+
294
+ $min: (doc, updates) => {
295
+ for (const [path, value] of Object.entries(updates)) {
296
+ const currentValue = getNestedValue(doc, path);
297
+ if (currentValue === undefined || value < currentValue) {
298
+ setNestedValue(doc, path, value);
299
+ }
300
+ }
301
+ },
302
+
303
+ $max: (doc, updates) => {
304
+ for (const [path, value] of Object.entries(updates)) {
305
+ const currentValue = getNestedValue(doc, path);
306
+ if (currentValue === undefined || value > currentValue) {
307
+ setNestedValue(doc, path, value);
308
+ }
309
+ }
310
+ },
311
+
312
+ $push: (doc, updates) => {
313
+ for (const [path, value] of Object.entries(updates)) {
314
+ const currentValue = getNestedValue(doc, path);
315
+ const array = Array.isArray(currentValue) ? currentValue : [];
316
+ setNestedValue(doc, path, [...array, value]);
317
+ }
318
+ },
319
+
320
+ $pop: (doc, updates) => {
321
+ for (const [path, direction] of Object.entries(updates)) {
322
+ const currentValue = getNestedValue(doc, path);
323
+ if (Array.isArray(currentValue) && currentValue.length > 0) {
324
+ if (direction === 1) {
325
+ setNestedValue(doc, path, currentValue.slice(0, -1));
326
+ } else if (direction === -1) {
327
+ setNestedValue(doc, path, currentValue.slice(1));
328
+ }
329
+ }
330
+ }
331
+ },
332
+
333
+ $pull: (doc, updates) => {
334
+ for (const [path, condition] of Object.entries(updates)) {
335
+ const currentValue = getNestedValue(doc, path);
336
+ if (Array.isArray(currentValue)) {
337
+ const filtered = currentValue.filter(item => {
338
+ if (typeof condition === 'object') {
339
+ return !matchQuery(item, condition);
340
+ }
341
+ return item !== condition;
342
+ });
343
+ setNestedValue(doc, path, filtered);
344
+ }
345
+ }
346
+ },
347
+
348
+ $addToSet: (doc, updates) => {
349
+ for (const [path, value] of Object.entries(updates)) {
350
+ const currentValue = getNestedValue(doc, path);
351
+ const array = Array.isArray(currentValue) ? currentValue : [];
352
+ if (!array.some(item => JSON.stringify(item) === JSON.stringify(value))) {
353
+ setNestedValue(doc, path, [...array, value]);
354
+ }
355
+ }
356
+ }
357
+ };
358
+
359
+ /**
360
+ * 应用更新到文档
361
+ * @param {Object} doc - 原文档
362
+ * @param {Object} update - 更新对象
363
+ * @param {boolean} isInsert - 是否是插入操作
364
+ * @returns {Object} 更新后的文档
365
+ */
366
+ export function applyUpdate(doc, update, isInsert = false) {
367
+ const result = JSON.parse(JSON.stringify(doc));
368
+
369
+ for (const [operator, updates] of Object.entries(update)) {
370
+ if (!operator.startsWith('$')) {
371
+ throw new Error('更新操作必须使用操作符');
372
+ }
373
+
374
+ if (updateOperators[operator]) {
375
+ updateOperators[operator](result, updates, isInsert);
376
+ } else {
377
+ throw new Error(`未知更新操作符:${operator}`);
378
+ }
379
+ }
380
+
381
+ return result;
382
+ }