jsonbadger 0.5.0
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/LICENSE +21 -0
- package/README.md +114 -0
- package/docs/api.md +152 -0
- package/docs/examples.md +612 -0
- package/docs/local-integration-testing.md +17 -0
- package/docs/query-translation.md +98 -0
- package/index.js +2 -0
- package/package.json +58 -0
- package/src/connection/connect.js +56 -0
- package/src/connection/disconnect.js +16 -0
- package/src/connection/pool-store.js +46 -0
- package/src/connection/server-capabilities.js +59 -0
- package/src/constants/defaults.js +20 -0
- package/src/constants/id-strategies.js +29 -0
- package/src/debug/debug-logger.js +15 -0
- package/src/errors/query-error.js +23 -0
- package/src/errors/validation-error.js +23 -0
- package/src/field-types/base-field-type.js +140 -0
- package/src/field-types/builtins/advanced.js +365 -0
- package/src/field-types/builtins/index.js +585 -0
- package/src/field-types/registry.js +122 -0
- package/src/index.js +36 -0
- package/src/migration/ensure-index.js +155 -0
- package/src/migration/ensure-schema.js +16 -0
- package/src/migration/ensure-table.js +31 -0
- package/src/migration/schema-indexes-resolver.js +6 -0
- package/src/model/document-instance.js +540 -0
- package/src/model/model-factory.js +555 -0
- package/src/query/limit-skip-compiler.js +31 -0
- package/src/query/operators/all.js +10 -0
- package/src/query/operators/contains.js +7 -0
- package/src/query/operators/elem-match.js +3 -0
- package/src/query/operators/eq.js +6 -0
- package/src/query/operators/gt.js +16 -0
- package/src/query/operators/gte.js +16 -0
- package/src/query/operators/has-all-keys.js +11 -0
- package/src/query/operators/has-any-keys.js +11 -0
- package/src/query/operators/has-key.js +6 -0
- package/src/query/operators/in.js +12 -0
- package/src/query/operators/index.js +60 -0
- package/src/query/operators/jsonpath-exists.js +15 -0
- package/src/query/operators/jsonpath-match.js +15 -0
- package/src/query/operators/lt.js +16 -0
- package/src/query/operators/lte.js +16 -0
- package/src/query/operators/ne.js +6 -0
- package/src/query/operators/nin.js +12 -0
- package/src/query/operators/regex.js +8 -0
- package/src/query/operators/size.js +16 -0
- package/src/query/path-parser.js +43 -0
- package/src/query/query-builder.js +93 -0
- package/src/query/sort-compiler.js +30 -0
- package/src/query/where-compiler.js +477 -0
- package/src/schema/field-definition-parser.js +218 -0
- package/src/schema/path-introspection.js +82 -0
- package/src/schema/schema-compiler.js +212 -0
- package/src/schema/schema.js +234 -0
- package/src/sql/parameter-binder.js +13 -0
- package/src/sql/sql-runner.js +31 -0
- package/src/utils/array.js +31 -0
- package/src/utils/assert.js +27 -0
- package/src/utils/json-safe.js +9 -0
- package/src/utils/json.js +21 -0
- package/src/utils/object-path.js +33 -0
- package/src/utils/object.js +168 -0
- package/src/utils/value.js +30 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import {is_object} from '#src/utils/value.js';
|
|
2
|
+
|
|
3
|
+
function has_own(target, key) {
|
|
4
|
+
return Object.prototype.hasOwnProperty.call(target, key);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// Optimized deep clone with fallback and circular reference handling
|
|
8
|
+
function deep_clone(value, cache = new WeakMap()) {
|
|
9
|
+
// Use native high-performance clone if available
|
|
10
|
+
if(typeof globalThis.structuredClone === 'function') {
|
|
11
|
+
return globalThis.structuredClone(value);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if(value === null || typeof value !== 'object') {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if(cache.has(value)) {
|
|
19
|
+
return cache.get(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if(Array.isArray(value)) {
|
|
23
|
+
const result = [];
|
|
24
|
+
cache.set(value, result);
|
|
25
|
+
|
|
26
|
+
for(let i = 0; i < value.length; i++) {
|
|
27
|
+
result[i] = deep_clone(value[i], cache);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const result = {};
|
|
34
|
+
const keys = Object.keys(value);
|
|
35
|
+
cache.set(value, result);
|
|
36
|
+
|
|
37
|
+
for(let i = 0; i < keys.length; i++) {
|
|
38
|
+
const key = keys[i];
|
|
39
|
+
result[key] = deep_clone(value[key], cache);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// TODO: rename this? maybe?
|
|
46
|
+
function normalize(schema, value, cache = new WeakMap()) {
|
|
47
|
+
// 1. Array Handling
|
|
48
|
+
if(Array.isArray(schema)) {
|
|
49
|
+
const item_schema = schema.length ? schema[0] : undefined;
|
|
50
|
+
if(item_schema === undefined) return []; // Empty schema enforces empty array
|
|
51
|
+
|
|
52
|
+
const source_list = Array.isArray(value) ? value : [];
|
|
53
|
+
|
|
54
|
+
if(cache.has(source_list)) return cache.get(source_list);
|
|
55
|
+
|
|
56
|
+
const result_list = [];
|
|
57
|
+
cache.set(source_list, result_list);
|
|
58
|
+
|
|
59
|
+
for(let i = 0; i < source_list.length; i++) {
|
|
60
|
+
const item = source_list[i];
|
|
61
|
+
// If strict object matching is needed, skip invalid items
|
|
62
|
+
if(is_object(item_schema) && !is_object(item)) continue;
|
|
63
|
+
|
|
64
|
+
result_list.push(normalize(item_schema, item, cache));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return result_list;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 2. Object Handling
|
|
71
|
+
if(is_object(schema)) {
|
|
72
|
+
const source_obj = is_object(value) ? value : null;
|
|
73
|
+
|
|
74
|
+
if(source_obj && cache.has(source_obj)) return cache.get(source_obj);
|
|
75
|
+
|
|
76
|
+
const result_obj = {};
|
|
77
|
+
if(source_obj) cache.set(source_obj, result_obj);
|
|
78
|
+
|
|
79
|
+
// Iterate schema keys (sanitization: ignores extra keys in value)
|
|
80
|
+
const keys = Object.keys(schema);
|
|
81
|
+
for(let i = 0; i < keys.length; i++) {
|
|
82
|
+
const key = keys[i];
|
|
83
|
+
const sub_value = source_obj ? source_obj[key] : undefined;
|
|
84
|
+
result_obj[key] = normalize(schema[key], sub_value, cache);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return result_obj;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 3. Primitives & Defaults
|
|
91
|
+
if(value === undefined || value === null) {
|
|
92
|
+
// Return cloned default to prevent shared reference issues
|
|
93
|
+
return typeof schema === 'object' ? deep_clone(schema) : schema;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const type = typeof schema;
|
|
97
|
+
|
|
98
|
+
if(type === 'string') {
|
|
99
|
+
return String(value).trim();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if(type === 'number') {
|
|
103
|
+
const num = Number(value);
|
|
104
|
+
if(!Number.isFinite(num)) return schema; // Invalid number returns default
|
|
105
|
+
|
|
106
|
+
// Apply specific integer/positive logic based on schema default
|
|
107
|
+
const normalized = Number.isInteger(schema) ? Math.floor(num) : num;
|
|
108
|
+
return normalized >= 0 ? normalized : schema;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if(type === 'boolean') {
|
|
112
|
+
return Boolean(value);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return deep_clone(schema);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function merge(schema, base, value, cache = new WeakMap()) {
|
|
119
|
+
if(value === undefined) return base;
|
|
120
|
+
|
|
121
|
+
if(Array.isArray(schema)) {
|
|
122
|
+
if(!Array.isArray(value)) return base;
|
|
123
|
+
// Arrays are replaced by the new list (normalized), not merged element-wise
|
|
124
|
+
return normalize(schema, value, cache);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if(is_object(schema)) {
|
|
128
|
+
if(!is_object(value)) return base;
|
|
129
|
+
|
|
130
|
+
if(cache.has(value)) return cache.get(value);
|
|
131
|
+
|
|
132
|
+
const merged = {};
|
|
133
|
+
cache.set(value, merged);
|
|
134
|
+
|
|
135
|
+
const keys = Object.keys(schema);
|
|
136
|
+
for(let i = 0; i < keys.length; i++) {
|
|
137
|
+
const key = keys[i];
|
|
138
|
+
// Use base value if available, else create default
|
|
139
|
+
const base_child = base && has_own(base, key)
|
|
140
|
+
? base[key]
|
|
141
|
+
: normalize(schema[key], undefined);
|
|
142
|
+
|
|
143
|
+
if(has_own(value, key)) {
|
|
144
|
+
merged[key] = merge(schema[key], base_child, value[key], cache);
|
|
145
|
+
} else {
|
|
146
|
+
merged[key] = base_child;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return merged;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return normalize(schema, value, cache);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
has_own,
|
|
158
|
+
deep_clone,
|
|
159
|
+
normalize,
|
|
160
|
+
merge
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export default {
|
|
164
|
+
has_own,
|
|
165
|
+
deep_clone,
|
|
166
|
+
normalize,
|
|
167
|
+
merge
|
|
168
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const is_object = (value) => {
|
|
2
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
const is_not_object = (value) => {
|
|
6
|
+
return value === null || Array.isArray(value) || typeof value !== 'object';
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const is_nan = (value) => {
|
|
10
|
+
const numeric_value = Number(value);
|
|
11
|
+
return Number.isNaN(numeric_value);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const is_string = (value) => {
|
|
15
|
+
return typeof value === 'string';
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
is_object,
|
|
20
|
+
is_not_object,
|
|
21
|
+
is_nan,
|
|
22
|
+
is_string
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
is_object,
|
|
27
|
+
is_not_object,
|
|
28
|
+
is_nan,
|
|
29
|
+
is_string
|
|
30
|
+
};
|