jsonbadger 0.5.0 → 0.6.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.
Files changed (123) hide show
  1. package/README.md +36 -18
  2. package/docs/api/connection.md +144 -0
  3. package/docs/api/delta-tracker.md +106 -0
  4. package/docs/api/document.md +77 -0
  5. package/docs/api/field-types.md +329 -0
  6. package/docs/api/index.md +35 -0
  7. package/docs/api/model.md +392 -0
  8. package/docs/api/query-builder.md +81 -0
  9. package/docs/api/schema.md +204 -0
  10. package/docs/architecture-flow.md +397 -0
  11. package/docs/examples.md +495 -218
  12. package/docs/jsonb-ops.md +171 -0
  13. package/docs/lifecycle/model-compilation.md +111 -0
  14. package/docs/lifecycle.md +146 -0
  15. package/docs/query-translation.md +11 -10
  16. package/package.json +10 -3
  17. package/src/connection/connect.js +12 -17
  18. package/src/connection/connection.js +128 -0
  19. package/src/connection/server-capabilities.js +60 -59
  20. package/src/constants/defaults.js +32 -19
  21. package/src/constants/{id-strategies.js → id-strategy.js} +28 -29
  22. package/src/constants/intake-mode.js +8 -0
  23. package/src/debug/debug-logger.js +17 -15
  24. package/src/errors/model-overwrite-error.js +25 -0
  25. package/src/errors/query-error.js +25 -23
  26. package/src/errors/validation-error.js +25 -23
  27. package/src/field-types/base-field-type.js +137 -140
  28. package/src/field-types/builtins/advanced.js +365 -365
  29. package/src/field-types/builtins/index.js +579 -585
  30. package/src/field-types/field-type-namespace.js +9 -0
  31. package/src/field-types/registry.js +149 -122
  32. package/src/index.js +26 -36
  33. package/src/migration/ensure-index.js +157 -154
  34. package/src/migration/ensure-schema.js +27 -15
  35. package/src/migration/ensure-table.js +44 -31
  36. package/src/migration/schema-indexes-resolver.js +8 -6
  37. package/src/model/document-instance.js +29 -540
  38. package/src/model/document.js +60 -0
  39. package/src/model/factory/constants.js +36 -0
  40. package/src/model/factory/index.js +58 -0
  41. package/src/model/model.js +875 -0
  42. package/src/model/operations/delete-one.js +39 -0
  43. package/src/model/operations/insert-one.js +35 -0
  44. package/src/model/operations/query-builder.js +132 -0
  45. package/src/model/operations/update-one.js +333 -0
  46. package/src/model/state.js +34 -0
  47. package/src/schema/field-definition-parser.js +213 -218
  48. package/src/schema/path-introspection.js +87 -82
  49. package/src/schema/schema-compiler.js +126 -212
  50. package/src/schema/schema.js +621 -138
  51. package/src/sql/index.js +17 -0
  52. package/src/sql/jsonb/ops.js +153 -0
  53. package/src/{query → sql/jsonb}/path-parser.js +54 -43
  54. package/src/sql/jsonb/read/elem-match.js +133 -0
  55. package/src/{query → sql/jsonb/read}/operators/contains.js +13 -7
  56. package/src/sql/jsonb/read/operators/elem-match.js +9 -0
  57. package/src/{query → sql/jsonb/read}/operators/has-all-keys.js +17 -11
  58. package/src/{query → sql/jsonb/read}/operators/has-any-keys.js +18 -11
  59. package/src/sql/jsonb/read/operators/has-key.js +12 -0
  60. package/src/{query → sql/jsonb/read}/operators/jsonpath-exists.js +22 -15
  61. package/src/{query → sql/jsonb/read}/operators/jsonpath-match.js +22 -15
  62. package/src/{query → sql/jsonb/read}/operators/size.js +23 -16
  63. package/src/sql/parameter-binder.js +18 -13
  64. package/src/sql/read/build-count-query.js +12 -0
  65. package/src/sql/read/build-find-query.js +25 -0
  66. package/src/sql/read/limit-skip.js +21 -0
  67. package/src/sql/read/sort.js +85 -0
  68. package/src/sql/read/where/base-fields.js +310 -0
  69. package/src/sql/read/where/casting.js +90 -0
  70. package/src/sql/read/where/context.js +79 -0
  71. package/src/sql/read/where/field-clause.js +58 -0
  72. package/src/sql/read/where/index.js +38 -0
  73. package/src/sql/read/where/operator-entries.js +29 -0
  74. package/src/{query → sql/read/where}/operators/all.js +16 -10
  75. package/src/sql/read/where/operators/eq.js +12 -0
  76. package/src/{query → sql/read/where}/operators/gt.js +23 -16
  77. package/src/{query → sql/read/where}/operators/gte.js +23 -16
  78. package/src/{query → sql/read/where}/operators/in.js +18 -12
  79. package/src/sql/read/where/operators/index.js +40 -0
  80. package/src/{query → sql/read/where}/operators/lt.js +23 -16
  81. package/src/{query → sql/read/where}/operators/lte.js +23 -16
  82. package/src/sql/read/where/operators/ne.js +12 -0
  83. package/src/{query → sql/read/where}/operators/nin.js +18 -12
  84. package/src/{query → sql/read/where}/operators/regex.js +14 -8
  85. package/src/sql/read/where/operators.js +126 -0
  86. package/src/sql/read/where/text-operators.js +83 -0
  87. package/src/sql/run.js +46 -0
  88. package/src/sql/write/build-delete-query.js +33 -0
  89. package/src/sql/write/build-insert-query.js +42 -0
  90. package/src/sql/write/build-update-query.js +65 -0
  91. package/src/utils/assert.js +34 -27
  92. package/src/utils/delta-tracker/.archive/1 tracker-redesign-codex-v2.md +250 -0
  93. package/src/utils/delta-tracker/.archive/1 tracker-redesign-gemini.md +101 -0
  94. package/src/utils/delta-tracker/.archive/2 evaluation by gemini.txt +65 -0
  95. package/src/utils/delta-tracker/.archive/2 evaluation by grok.txt +39 -0
  96. package/src/utils/delta-tracker/.archive/3 gemini evaluate grok.txt +37 -0
  97. package/src/utils/delta-tracker/.archive/3 grok evaluate gemini.txt +63 -0
  98. package/src/utils/delta-tracker/.archive/4 gemini veredict.txt +16 -0
  99. package/src/utils/delta-tracker/.archive/index.1.js +587 -0
  100. package/src/utils/delta-tracker/.archive/index.2.js +612 -0
  101. package/src/utils/delta-tracker/index.js +592 -0
  102. package/src/utils/dirty-tracker/inline.js +335 -0
  103. package/src/utils/dirty-tracker/instance.js +414 -0
  104. package/src/utils/dirty-tracker/static.js +343 -0
  105. package/src/utils/json-safe.js +13 -9
  106. package/src/utils/object-path.js +227 -33
  107. package/src/utils/object.js +408 -168
  108. package/src/utils/string.js +55 -0
  109. package/src/utils/value.js +169 -30
  110. package/docs/api.md +0 -152
  111. package/src/connection/disconnect.js +0 -16
  112. package/src/connection/pool-store.js +0 -46
  113. package/src/model/model-factory.js +0 -555
  114. package/src/query/limit-skip-compiler.js +0 -31
  115. package/src/query/operators/elem-match.js +0 -3
  116. package/src/query/operators/eq.js +0 -6
  117. package/src/query/operators/has-key.js +0 -6
  118. package/src/query/operators/index.js +0 -60
  119. package/src/query/operators/ne.js +0 -6
  120. package/src/query/query-builder.js +0 -93
  121. package/src/query/sort-compiler.js +0 -30
  122. package/src/query/where-compiler.js +0 -477
  123. package/src/sql/sql-runner.js +0 -31
@@ -1,212 +1,126 @@
1
- /*
2
- Assumptions and trade-offs:
3
- - Validation/casting is FieldType-driven and unknown payload keys are preserved.
4
- - Error aggregation mirrors abortEarly=false behavior with deterministic per-path detail records.
5
- */
6
- import field_definition_parser from '#src/schema/field-definition-parser.js';
7
- import {
8
- create_path_introspection,
9
- get_path_field_type,
10
- get_path_type as resolve_path_type,
11
- is_array_root as resolve_is_array_root
12
- } from '#src/schema/path-introspection.js';
13
- import {has_own} from '#src/utils/object.js';
14
- export default function schema_compiler(schema_definition) {
15
- const parsed_schema = field_definition_parser(schema_definition || {});
16
- const path_introspection = create_path_introspection(parsed_schema);
17
- const field_types = path_introspection.field_types;
18
- const sorted_paths = Object.keys(field_types).sort(sort_paths_by_depth);
19
-
20
- return {
21
- validate: function (payload) {
22
- return validate_payload(payload, sorted_paths, field_types);
23
- },
24
- path: function (path_name) {
25
- return get_path_field_type(path_introspection, path_name);
26
- },
27
- get_path_type: function (path_name) {
28
- return resolve_path_type(path_introspection, path_name);
29
- },
30
- is_array_root: function (path_name) {
31
- return resolve_is_array_root(path_introspection, path_name);
32
- },
33
- describe: function () {
34
- return {
35
- paths: Object.keys(field_types),
36
- objects: Array.from(path_introspection.object_paths)
37
- };
38
- }
39
- };
40
- }
41
-
42
- function validate_payload(payload, sorted_paths, field_types) {
43
- if(payload === null || typeof payload !== 'object' || Array.isArray(payload)) {
44
- return {
45
- value: payload,
46
- error: {
47
- details: [{
48
- path: '',
49
- code: 'validation_error',
50
- message: 'Schema validation failed',
51
- type: 'object'
52
- }]
53
- }
54
- };
55
- }
56
-
57
- const result_payload = clone_value(payload);
58
- const detail_list = [];
59
- let path_index = 0;
60
-
61
- while(path_index < sorted_paths.length) {
62
- const path_name = sorted_paths[path_index];
63
- const field_type = field_types[path_name];
64
- const path_segments = path_name.split('.');
65
- const current_path_state = read_path(result_payload, path_segments);
66
- const current_value = current_path_state.exists ? current_path_state.value : undefined;
67
- let normalized_value = undefined;
68
-
69
- try {
70
- normalized_value = field_type.normalize(current_value, {path: path_name});
71
- } catch(error) {
72
- detail_list.push(format_field_error(path_name, error));
73
- path_index += 1;
74
- continue;
75
- }
76
-
77
- if(normalized_value === undefined) {
78
- path_index += 1;
79
- continue;
80
- }
81
-
82
- write_path(result_payload, path_segments, normalized_value);
83
- path_index += 1;
84
- }
85
-
86
- if(detail_list.length > 0) {
87
- return {
88
- value: result_payload,
89
- error: {
90
- details: detail_list
91
- }
92
- };
93
- }
94
-
95
- return {
96
- value: result_payload,
97
- error: null
98
- };
99
- }
100
-
101
- function sort_paths_by_depth(left_path, right_path) {
102
- const left_depth = left_path.split('.').length;
103
- const right_depth = right_path.split('.').length;
104
-
105
- if(left_depth !== right_depth) {
106
- return left_depth - right_depth;
107
- }
108
-
109
- return left_path.localeCompare(right_path);
110
- }
111
-
112
- function format_field_error(path_name, error) {
113
- const error_message = error && error.message ? error.message : 'Schema validation failed';
114
- const error_code = error && error.code ? error.code : 'validation_error';
115
-
116
- return {
117
- path: path_name,
118
- code: error_code,
119
- message: error_message,
120
- type: error_code
121
- };
122
- }
123
-
124
- function read_path(root_object, path_segments) {
125
- let current_value = root_object;
126
- let segment_index = 0;
127
-
128
- while(segment_index < path_segments.length) {
129
- const segment_value = path_segments[segment_index];
130
-
131
- if(current_value === null || typeof current_value !== 'object' || !has_own(current_value, segment_value)) {
132
- return {
133
- exists: false,
134
- value: undefined
135
- };
136
- }
137
-
138
- current_value = current_value[segment_value];
139
- segment_index += 1;
140
- }
141
-
142
- return {
143
- exists: true,
144
- value: current_value
145
- };
146
- }
147
-
148
- function write_path(root_object, path_segments, next_value) {
149
- let current_value = root_object;
150
- let segment_index = 0;
151
-
152
- while(segment_index < path_segments.length) {
153
- const segment_value = path_segments[segment_index];
154
- const is_leaf = segment_index === path_segments.length - 1;
155
-
156
- if(is_leaf) {
157
- current_value[segment_value] = next_value;
158
- return;
159
- }
160
-
161
- // TODO: implement a code review agent that catches these
162
- if(
163
- !has_own(current_value, segment_value) ||
164
- current_value[segment_value] === null ||
165
- typeof current_value[segment_value] !== 'object' ||
166
- Array.isArray(current_value[segment_value])
167
- ) {
168
- current_value[segment_value] = {};
169
- }
170
-
171
- current_value = current_value[segment_value];
172
- segment_index += 1;
173
- }
174
- }
175
-
176
- function clone_value(value) {
177
- if(Array.isArray(value)) {
178
- const cloned_array = [];
179
- let value_index = 0;
180
-
181
- while(value_index < value.length) {
182
- cloned_array.push(clone_value(value[value_index]));
183
- value_index += 1;
184
- }
185
-
186
- return cloned_array;
187
- }
188
-
189
- if(value instanceof Date) {
190
- return new Date(value.getTime());
191
- }
192
-
193
- if(Buffer.isBuffer(value)) {
194
- return Buffer.from(value);
195
- }
196
-
197
- if(value && typeof value === 'object') {
198
- const cloned_object = {};
199
- const object_entries = Object.entries(value);
200
- let entry_index = 0;
201
-
202
- while(entry_index < object_entries.length) {
203
- const object_entry = object_entries[entry_index];
204
- cloned_object[object_entry[0]] = clone_value(object_entry[1]);
205
- entry_index += 1;
206
- }
207
-
208
- return cloned_object;
209
- }
210
-
211
- return value;
212
- }
1
+ import field_definition_parser from '#src/schema/field-definition-parser.js';
2
+ import {create_path_introspection} from '#src/schema/path-introspection.js';
3
+
4
+ import {is_array} from '#src/utils/array.js';
5
+ import {has_own} from '#src/utils/object.js';
6
+ import {is_function, is_not_object} from '#src/utils/value.js';
7
+
8
+ const schema_validation_error_message = 'Schema validation failed';
9
+ const schema_validation_error_code = 'validation_error';
10
+
11
+ // --- PUBLIC API ---
12
+
13
+ function prepare_schema_state(schema_definition = {}) {
14
+ const parsed_schema = field_definition_parser(schema_definition);
15
+ const path_introspection = create_path_introspection(parsed_schema);
16
+ const field_types = path_introspection.field_types;
17
+ const sorted_paths = Object.keys(field_types).sort(sort_paths_by_depth);
18
+
19
+ return {
20
+ path_introspection,
21
+ field_types,
22
+ sorted_paths
23
+ };
24
+ }
25
+
26
+ /**
27
+ * Build one reusable validator from a prepared field-type path map.
28
+ *
29
+ * @param {object} field_types
30
+ * @returns {Function}
31
+ */
32
+ function create_path_validator(field_types = {}) {
33
+ const sorted_paths = Object.keys(field_types).sort(sort_paths_by_depth);
34
+
35
+ return (payload) => {
36
+ return validate_payload(payload, sorted_paths, field_types);
37
+ };
38
+ }
39
+
40
+ function validate_payload(payload, sorted_paths, field_types) {
41
+ if(is_not_object(payload) || is_array(payload)) {
42
+ return {
43
+ valid: false,
44
+ errors: [{
45
+ path: '',
46
+ code: schema_validation_error_code,
47
+ message: schema_validation_error_message,
48
+ type: 'object'
49
+ }]
50
+ };
51
+ }
52
+
53
+ const error_list = [];
54
+
55
+ for(const path_name of sorted_paths) {
56
+ const field_type = field_types[path_name];
57
+ const path_segments = path_name.split('.');
58
+ const current_path_state = read_path(payload, path_segments);
59
+ const current_value = current_path_state.exists ? current_path_state.value : undefined;
60
+
61
+ if(is_function(field_type.validate)) {
62
+ try {
63
+ field_type.validate(current_value, {path: path_name, exists: current_path_state.exists});
64
+ } catch(error) {
65
+ error_list.push(format_field_error(path_name, error));
66
+ }
67
+ }
68
+ }
69
+
70
+ return {
71
+ valid: error_list.length === 0,
72
+ errors: error_list.length > 0 ? error_list : null
73
+ };
74
+ }
75
+
76
+ function sort_paths_by_depth(left_path, right_path) {
77
+ const left_depth = left_path.split('.').length;
78
+ const right_depth = right_path.split('.').length;
79
+
80
+ if(left_depth !== right_depth) {
81
+ return left_depth - right_depth;
82
+ }
83
+
84
+ return left_path.localeCompare(right_path);
85
+ }
86
+
87
+ // --- LOCAL HELPER FUNCTIONS ---
88
+
89
+ function format_field_error(path_name, error) {
90
+ const error_message = error && error.message ? error.message : schema_validation_error_message;
91
+ const error_code = error && error.code ? error.code : schema_validation_error_code;
92
+
93
+ return {
94
+ path: path_name,
95
+ code: error_code,
96
+ message: error_message,
97
+ type: error_code
98
+ };
99
+ }
100
+
101
+ function read_path(root_object, path_segments) {
102
+ let current_value = root_object;
103
+
104
+ for(const segment_value of path_segments) {
105
+ if(current_value === null || typeof current_value !== 'object' || !has_own(current_value, segment_value)) {
106
+ return {
107
+ exists: false,
108
+ value: undefined
109
+ };
110
+ }
111
+
112
+ current_value = current_value[segment_value];
113
+ }
114
+
115
+ return {
116
+ exists: true,
117
+ value: current_value
118
+ };
119
+ }
120
+
121
+ export {
122
+ create_path_validator,
123
+ prepare_schema_state,
124
+ validate_payload,
125
+ sort_paths_by_depth
126
+ };