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
@@ -0,0 +1,17 @@
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Expose the shared SQL builder and runner entry points.
4
+ */
5
+ import build_update_query from '#src/sql/write/build-update-query.js';
6
+ import build_insert_query from '#src/sql/write/build-insert-query.js';
7
+ import build_delete_query from '#src/sql/write/build-delete-query.js';
8
+ import run from '#src/sql/run.js';
9
+
10
+ const sql = {
11
+ build_delete_query,
12
+ build_insert_query,
13
+ build_update_query,
14
+ run
15
+ };
16
+
17
+ export default sql;
@@ -0,0 +1,153 @@
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Parse operator-style JSONB mutations and compile one SQL RHS expression.
4
+ */
5
+ import QueryError from '#src/errors/query-error.js';
6
+ import {bind_parameter} from '#src/sql/parameter-binder.js';
7
+ import {is_array} from '#src/utils/array.js';
8
+ import {build_path_literal, split_dot_path} from '#src/utils/object-path.js';
9
+ import {jsonb_stringify} from '#src/utils/json.js';
10
+ import {is_not_object, is_plain_object} from '#src/utils/value.js';
11
+
12
+ /**
13
+ * The canonical execution order for PostgreSQL JSONB mutations.
14
+ */
15
+ const core_update_operators = ['$replace_roots', '$unset', '$set'];
16
+
17
+ /**
18
+ * Utility for parsing JSONB mutations into a flat, ordered operation list.
19
+ * This acts as a Syntax Firewall: it knows HOW to write PG syntax,
20
+ * but knows NOTHING about SQL parameters.
21
+ */
22
+ function JsonbOps(target, operations) {
23
+ this.target = target;
24
+ this.operations = operations;
25
+ }
26
+
27
+ /**
28
+ * Compile one JsonbOps instance into a PostgreSQL JSONB RHS expression.
29
+ *
30
+ * @param {object} parameter_state
31
+ * @returns {string}
32
+ */
33
+ JsonbOps.prototype.compile = function (parameter_state) {
34
+ let expression = this.target;
35
+
36
+ for(const step of this.operations) {
37
+ if(step.op === '$replace_roots') {
38
+ const placeholder = bind_parameter(parameter_state, step.value);
39
+ expression = `${placeholder}::jsonb`;
40
+ }
41
+ else if(step.op === '#-') {
42
+ expression = `${expression} #- '${step.path}'`;
43
+ }
44
+ else if(step.op === 'jsonb_set') {
45
+ const placeholder = bind_parameter(parameter_state, step.value);
46
+ expression = `jsonb_set(${expression}, '${step.path}', ${placeholder}::jsonb, true)`;
47
+ }
48
+ }
49
+
50
+ return expression;
51
+ };
52
+
53
+ /**
54
+ * Transforms one operator-style update definition into a JsonbOps instance.
55
+ *
56
+ * The input contract here is `$replace_roots`, `$unset`, `$set`, plus implicit
57
+ * top-level `$set` keys. If the caller starts from a tracker delta shape
58
+ * (`replace_roots`, `set`, `unset`), the orchestrator must map that delta into
59
+ * operator-style keys before calling `.from(...)`.
60
+ *
61
+ * @param {object} update_definition - Operator-style update input for one JSONB mutation.
62
+ * @param {object} options
63
+ * @param {string} options.column_name - The target column (e.g. '"data"').
64
+ * @param {boolean} [options.coalesce=true] - Wrap base in COALESCE.
65
+ * @returns {JsonbOps}
66
+ */
67
+ JsonbOps.from = function (update_definition, options) {
68
+ if(is_not_object(update_definition)) {
69
+ throw new QueryError('JsonbOps requires an object definition');
70
+ }
71
+
72
+ const {column_name, coalesce = true} = options || {};
73
+
74
+ if(!column_name) {
75
+ throw new QueryError('JsonbOps requires options.column_name');
76
+ }
77
+
78
+ // Initialized with explicit types to avoid defensive assignment later
79
+ const buckets = {$replace_roots: {}, $unset: [], $set: {}};
80
+ let total_operations = 0;
81
+
82
+ // 1. Distribution & Auto-Wrapping
83
+ for(const [key, value] of Object.entries(update_definition)) {
84
+ if(key.startsWith('$')) {
85
+ if(!core_update_operators.includes(key)) {
86
+ throw new QueryError(`Unsupported JSONB operator: ${key}`);
87
+ }
88
+
89
+ if(key === '$unset') {
90
+ if(!is_array(value)) {
91
+ throw new QueryError('$unset expects array');
92
+ }
93
+
94
+ buckets.$unset.push(...value);
95
+ total_operations += value.length;
96
+
97
+ } else {
98
+ if(!is_plain_object(value)) {
99
+ throw new QueryError(`${key} expects plain object`);
100
+ }
101
+
102
+ Object.assign(buckets[key], value);
103
+ total_operations += Object.keys(value).length;
104
+ }
105
+
106
+ } else {
107
+ // Implicit wrapping of raw keys into $set
108
+ buckets.$set[key] = value;
109
+ total_operations += 1;
110
+ }
111
+ }
112
+
113
+ if(total_operations > 1024) {
114
+ throw new QueryError('JSONB mutation exceeds complexity limit (1024)');
115
+ }
116
+
117
+ // 2. Build the Linear Operation List
118
+ const operations = [];
119
+ let target = coalesce ? `COALESCE(${column_name}, '{}'::jsonb)` : column_name;
120
+
121
+ // A. Replace Roots (Redefines the starting target)
122
+ if(Object.keys(buckets.$replace_roots).length > 0) {
123
+ operations.push({
124
+ op: '$replace_roots',
125
+ value: jsonb_stringify(buckets.$replace_roots)
126
+ });
127
+ }
128
+
129
+ // B. Unsets
130
+ if(buckets.$unset.length > 0) {
131
+ for(const path of buckets.$unset) {
132
+ operations.push({
133
+ op: '#-',
134
+ path: build_path_literal(split_dot_path(path))
135
+ });
136
+ }
137
+ }
138
+
139
+ // C. Sets
140
+ if(Object.keys(buckets.$set).length > 0) {
141
+ for(const [path, value] of Object.entries(buckets.$set)) {
142
+ operations.push({
143
+ op: 'jsonb_set',
144
+ path: build_path_literal(split_dot_path(path)),
145
+ value: jsonb_stringify(value)
146
+ });
147
+ }
148
+ }
149
+
150
+ return new JsonbOps(target, operations);
151
+ };
152
+
153
+ export {JsonbOps};
@@ -1,43 +1,54 @@
1
- import {assert_path} from '#src/utils/assert.js';
2
- import {build_path_literal, split_dot_path} from '#src/utils/object-path.js';
3
-
4
- export function build_text_expression(column_reference, path_value) {
5
- const path_segments = split_dot_path(path_value);
6
-
7
- if(path_segments.length === 1) {
8
- return column_reference + " ->> '" + path_segments[0] + "'";
9
- }
10
-
11
- return column_reference + " #>> '" + build_path_literal(path_segments) + "'";
12
- }
13
-
14
- export function build_json_expression(column_reference, path_value) {
15
- const path_segments = split_dot_path(path_value);
16
-
17
- if(path_segments.length === 1) {
18
- return column_reference + " -> '" + path_segments[0] + "'";
19
- }
20
-
21
- return column_reference + " #> '" + build_path_literal(path_segments) + "'";
22
- }
23
-
24
- export function build_elem_text_expression(elem_alias, path_segments) {
25
- if(path_segments.length === 1) {
26
- return elem_alias + "->>'" + path_segments[0] + "'";
27
- }
28
-
29
- return elem_alias + " #>> '" + build_path_literal(path_segments) + "'";
30
- }
31
-
32
- export function parse_path(path_value) {
33
- assert_path(path_value, 'path');
34
-
35
- const path_segments = split_dot_path(path_value);
36
-
37
- return {
38
- path_segments: path_segments,
39
- root_path: path_segments[0],
40
- child_segments: path_segments.slice(1),
41
- is_nested: path_segments.length > 1
42
- };
43
- }
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Parse JSONB paths and build SQL path expressions for JSONB query helpers.
4
+ */
5
+ import {assert_path} from '#src/utils/assert.js';
6
+ import {build_path_literal, split_dot_path} from '#src/utils/object-path.js';
7
+
8
+ function build_text_expression(column_reference, path_value) {
9
+ const path_segments = split_dot_path(path_value);
10
+
11
+ if(path_segments.length === 1) {
12
+ return column_reference + " ->> '" + path_segments[0] + "'";
13
+ }
14
+
15
+ return column_reference + " #>> '" + build_path_literal(path_segments) + "'";
16
+ }
17
+
18
+ function build_json_expression(column_reference, path_value) {
19
+ const path_segments = split_dot_path(path_value);
20
+
21
+ if(path_segments.length === 1) {
22
+ return column_reference + " -> '" + path_segments[0] + "'";
23
+ }
24
+
25
+ return column_reference + " #> '" + build_path_literal(path_segments) + "'";
26
+ }
27
+
28
+ function build_elem_text_expression(elem_alias, path_segments) {
29
+ if(path_segments.length === 1) {
30
+ return elem_alias + "->>'" + path_segments[0] + "'";
31
+ }
32
+
33
+ return elem_alias + " #>> '" + build_path_literal(path_segments) + "'";
34
+ }
35
+
36
+ function parse_path(path_value) {
37
+ assert_path(path_value, 'path');
38
+
39
+ const path_segments = split_dot_path(path_value);
40
+
41
+ return {
42
+ path_segments: path_segments,
43
+ root_path: path_segments[0],
44
+ child_segments: path_segments.slice(1),
45
+ is_nested: path_segments.length > 1
46
+ };
47
+ }
48
+
49
+ export {
50
+ build_text_expression,
51
+ build_json_expression,
52
+ build_elem_text_expression,
53
+ parse_path
54
+ };
@@ -0,0 +1,133 @@
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Compile JSONB nested-array and $elem_match predicates for read queries.
4
+ */
5
+ import {build_elem_text_expression, build_json_expression} from '#src/sql/jsonb/path-parser.js';
6
+ import elem_match_operator from '#src/sql/jsonb/read/operators/elem-match.js';
7
+ import {eq_operator, regex_operator} from '#src/sql/read/where/operators/index.js';
8
+
9
+ import {has_operator_entries} from '#src/sql/read/where/context.js';
10
+ import {compile_operator_entry_clauses} from '#src/sql/read/where/operator-entries.js';
11
+ import {compile_text_operator} from '#src/sql/read/where/text-operators.js';
12
+
13
+ import {split_dot_path} from '#src/utils/object-path.js';
14
+ import {is_object} from '#src/utils/value.js';
15
+ import QueryError from '#src/errors/query-error.js';
16
+
17
+ const unsupported_elem_match_operator_message = 'Unsupported operator inside $elem_match';
18
+
19
+ function compile_nested_array_operator(operator_name, operator_value, regex_options, path_info, data_column_reference, parameter_state) {
20
+ const array_expression = build_json_expression(data_column_reference, path_info.root_path);
21
+ const elem_expression = build_elem_text_expression('elem', path_info.child_segments);
22
+ const predicate = compile_text_operator({
23
+ name: operator_name,
24
+ value: operator_value,
25
+ regex_options,
26
+ text_expression: elem_expression,
27
+ parameter_state,
28
+ error_message: unsupported_elem_match_operator_message
29
+ });
30
+
31
+ if(!predicate) {
32
+ throw new QueryError(unsupported_elem_match_operator_message + ': ' + operator_name, {
33
+ operator: operator_name
34
+ });
35
+ }
36
+
37
+ return elem_match_operator(array_expression, predicate);
38
+ }
39
+
40
+ function compile_elem_match_clause(path_value, elem_match_value, data_column_reference, parameter_state) {
41
+ const array_expression = build_json_expression(data_column_reference, path_value);
42
+ const predicate_list = [];
43
+
44
+ if(elem_match_value instanceof RegExp) {
45
+ predicate_list.push(regex_operator("elem #>> '{}'", elem_match_value.source, elem_match_value.flags, parameter_state));
46
+ return elem_match_operator(array_expression, predicate_list.join(' AND '));
47
+ }
48
+
49
+ if(!is_object(elem_match_value)) {
50
+ predicate_list.push(eq_operator("elem #>> '{}'", elem_match_value, parameter_state));
51
+ return elem_match_operator(array_expression, predicate_list.join(' AND '));
52
+ }
53
+
54
+ if(has_operator_entries(elem_match_value)) {
55
+ const option_value = elem_match_value.$options || '';
56
+ const compile_operator_predicate = (operator_name, operator_value) => {
57
+ const predicate = compile_text_operator({
58
+ name: operator_name,
59
+ value: operator_value,
60
+ regex_options: option_value,
61
+ text_expression: "elem #>> '{}'",
62
+ parameter_state,
63
+ error_message: unsupported_elem_match_operator_message
64
+ });
65
+
66
+ if(!predicate) {
67
+ throw new QueryError(unsupported_elem_match_operator_message + ': ' + operator_name, {
68
+ operator: operator_name
69
+ });
70
+ }
71
+
72
+ return predicate;
73
+ };
74
+ const operator_predicates = compile_operator_entry_clauses(elem_match_value, compile_operator_predicate);
75
+ predicate_list.push.apply(predicate_list, operator_predicates);
76
+
77
+ return elem_match_operator(array_expression, predicate_list.join(' AND '));
78
+ }
79
+
80
+ const elem_entries = Object.entries(elem_match_value);
81
+ let entry_index = 0;
82
+
83
+ while(entry_index < elem_entries.length) {
84
+ const entry_pair = elem_entries[entry_index];
85
+ const nested_path = entry_pair[0];
86
+ const nested_value = entry_pair[1];
87
+ const nested_segments = split_dot_path(nested_path);
88
+ const elem_expression = build_elem_text_expression('elem', nested_segments);
89
+
90
+ if(nested_value instanceof RegExp) {
91
+ predicate_list.push(regex_operator(elem_expression, nested_value.source, nested_value.flags, parameter_state));
92
+ entry_index += 1;
93
+ continue;
94
+ }
95
+
96
+ if(is_object(nested_value) && has_operator_entries(nested_value)) {
97
+ const option_value = nested_value.$options || '';
98
+ const compile_nested_predicate = (operator_name, operator_value) => {
99
+ const predicate = compile_text_operator({
100
+ name: operator_name,
101
+ value: operator_value,
102
+ regex_options: option_value,
103
+ text_expression: elem_expression,
104
+ parameter_state,
105
+ error_message: unsupported_elem_match_operator_message
106
+ });
107
+
108
+ if(!predicate) {
109
+ throw new QueryError(unsupported_elem_match_operator_message + ': ' + operator_name, {
110
+ operator: operator_name
111
+ });
112
+ }
113
+
114
+ return predicate;
115
+ };
116
+ const nested_predicates = compile_operator_entry_clauses(nested_value, compile_nested_predicate);
117
+ predicate_list.push.apply(predicate_list, nested_predicates);
118
+
119
+ entry_index += 1;
120
+ continue;
121
+ }
122
+
123
+ predicate_list.push(eq_operator(elem_expression, nested_value, parameter_state));
124
+ entry_index += 1;
125
+ }
126
+
127
+ return elem_match_operator(array_expression, predicate_list.join(' AND '));
128
+ }
129
+
130
+ export {
131
+ compile_elem_match_clause,
132
+ compile_nested_array_operator
133
+ };
@@ -1,7 +1,13 @@
1
- import {bind_parameter} from '#src/sql/parameter-binder.js';
2
- import {jsonb_stringify} from '#src/utils/json.js';
3
-
4
- export default function contains_operator(jsonb_expression, comparison_value, parameter_state) {
5
- const placeholder = bind_parameter(parameter_state, jsonb_stringify(comparison_value));
6
- return jsonb_expression + ' @> ' + placeholder + '::jsonb';
7
- }
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Compile the SQL fragment for the $contains read-query operator.
4
+ */
5
+ import {bind_parameter} from '#src/sql/parameter-binder.js';
6
+ import {jsonb_stringify} from '#src/utils/json.js';
7
+
8
+ function contains_operator(jsonb_expression, comparison_value, parameter_state) {
9
+ const placeholder = bind_parameter(parameter_state, jsonb_stringify(comparison_value));
10
+ return jsonb_expression + ' @> ' + placeholder + '::jsonb';
11
+ }
12
+
13
+ export default contains_operator;
@@ -0,0 +1,9 @@
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Compile the SQL fragment for the $elem-match read-query operator.
4
+ */
5
+ function elem_match_operator(array_expression, predicate_expression) {
6
+ return 'EXISTS (SELECT 1 FROM jsonb_array_elements(' + array_expression + ') AS elem WHERE ' + predicate_expression + ')';
7
+ }
8
+
9
+ export default elem_match_operator;
@@ -1,11 +1,17 @@
1
- import {bind_parameter} from '#src/sql/parameter-binder.js';
2
- import {to_array} from '#src/utils/array.js';
3
-
4
- export default function has_all_keys_operator(jsonb_expression, comparison_value, parameter_state) {
5
- const key_list = to_array(comparison_value).map(function map_key(key_value) {
6
- return String(key_value);
7
- });
8
-
9
- const placeholder = bind_parameter(parameter_state, key_list);
10
- return jsonb_expression + ' ?& ' + placeholder + '::text[]';
11
- }
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Compile the SQL fragment for the $has-all-keys read-query operator.
4
+ */
5
+ import {bind_parameter} from '#src/sql/parameter-binder.js';
6
+ import {to_array} from '#src/utils/array.js';
7
+
8
+ function has_all_keys_operator(jsonb_expression, comparison_value, parameter_state) {
9
+ const key_list = to_array(comparison_value).map(function map_key(key_value) {
10
+ return String(key_value);
11
+ });
12
+
13
+ const placeholder = bind_parameter(parameter_state, key_list);
14
+ return jsonb_expression + ' ?& ' + placeholder + '::text[]';
15
+ }
16
+
17
+ export default has_all_keys_operator;
@@ -1,11 +1,18 @@
1
- import {bind_parameter} from '#src/sql/parameter-binder.js';
2
- import {to_array} from '#src/utils/array.js';
3
-
4
- export default function has_any_keys_operator(jsonb_expression, comparison_value, parameter_state) {
5
- const key_list = to_array(comparison_value).map(function map_key(key_value) {
6
- return String(key_value);
7
- });
8
-
9
- const placeholder = bind_parameter(parameter_state, key_list);
10
- return jsonb_expression + ' ?| ' + placeholder + '::text[]';
11
- }
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Compile the SQL fragment for the $has-any-keys read-query operator.
4
+ */
5
+ import {bind_parameter} from '#src/sql/parameter-binder.js';
6
+ import {to_array} from '#src/utils/array.js';
7
+
8
+ function has_any_keys_operator(jsonb_expression, comparison_value, parameter_state) {
9
+ const key_list = to_array(comparison_value).map(function map_key(key_value) {
10
+ return String(key_value);
11
+ });
12
+
13
+ const placeholder = bind_parameter(parameter_state, key_list);
14
+
15
+ return jsonb_expression + ' ?| ' + placeholder + '::text[]';
16
+ }
17
+
18
+ export default has_any_keys_operator;
@@ -0,0 +1,12 @@
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Compile the SQL fragment for the $has-key read-query operator.
4
+ */
5
+ import {bind_parameter} from '#src/sql/parameter-binder.js';
6
+
7
+ function has_key_operator(jsonb_expression, comparison_value, parameter_state) {
8
+ const placeholder = bind_parameter(parameter_state, String(comparison_value));
9
+ return jsonb_expression + ' ? ' + placeholder;
10
+ }
11
+
12
+ export default has_key_operator;
@@ -1,15 +1,22 @@
1
- import QueryError from '#src/errors/query-error.js';
2
- import {bind_parameter} from '#src/sql/parameter-binder.js';
3
- import {is_string} from '#src/utils/value.js';
4
-
5
- export default function jsonpath_exists_operator(jsonb_expression, comparison_value, parameter_state) {
6
- if(!is_string(comparison_value) || comparison_value.trim() === '') {
7
- throw new QueryError('Invalid value for $json_path_exists operator', {
8
- operator: '$json_path_exists',
9
- value: comparison_value
10
- });
11
- }
12
-
13
- const placeholder = bind_parameter(parameter_state, comparison_value);
14
- return jsonb_expression + ' @? ' + placeholder + '::jsonpath';
15
- }
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Compile the SQL fragment for the $jsonpath-exists read-query operator.
4
+ */
5
+ import QueryError from '#src/errors/query-error.js';
6
+ import {bind_parameter} from '#src/sql/parameter-binder.js';
7
+ import {is_string} from '#src/utils/value.js';
8
+
9
+ function jsonpath_exists_operator(jsonb_expression, comparison_value, parameter_state) {
10
+ if(!is_string(comparison_value) || comparison_value.trim() === '') {
11
+ throw new QueryError('Invalid value for $json_path_exists operator', {
12
+ operator: '$json_path_exists',
13
+ value: comparison_value
14
+ });
15
+ }
16
+
17
+ const placeholder = bind_parameter(parameter_state, comparison_value);
18
+
19
+ return jsonb_expression + ' @? ' + placeholder + '::jsonpath';
20
+ }
21
+
22
+ export default jsonpath_exists_operator;
@@ -1,15 +1,22 @@
1
- import QueryError from '#src/errors/query-error.js';
2
- import {bind_parameter} from '#src/sql/parameter-binder.js';
3
- import {is_string} from '#src/utils/value.js';
4
-
5
- export default function jsonpath_match_operator(jsonb_expression, comparison_value, parameter_state) {
6
- if(!is_string(comparison_value) || comparison_value.trim() === '') {
7
- throw new QueryError('Invalid value for $json_path_match operator', {
8
- operator: '$json_path_match',
9
- value: comparison_value
10
- });
11
- }
12
-
13
- const placeholder = bind_parameter(parameter_state, comparison_value);
14
- return jsonb_expression + ' @@ ' + placeholder + '::jsonpath';
15
- }
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Compile the SQL fragment for the $jsonpath-match read-query operator.
4
+ */
5
+ import QueryError from '#src/errors/query-error.js';
6
+ import {bind_parameter} from '#src/sql/parameter-binder.js';
7
+ import {is_string} from '#src/utils/value.js';
8
+
9
+ function jsonpath_match_operator(jsonb_expression, comparison_value, parameter_state) {
10
+ if(!is_string(comparison_value) || comparison_value.trim() === '') {
11
+ throw new QueryError('Invalid value for $json_path_match operator', {
12
+ operator: '$json_path_match',
13
+ value: comparison_value
14
+ });
15
+ }
16
+
17
+ const placeholder = bind_parameter(parameter_state, comparison_value);
18
+
19
+ return jsonb_expression + ' @@ ' + placeholder + '::jsonpath';
20
+ }
21
+
22
+ export default jsonpath_match_operator;
@@ -1,16 +1,23 @@
1
- import QueryError from '#src/errors/query-error.js';
2
- import {bind_parameter} from '#src/sql/parameter-binder.js';
3
- import {is_nan} from '#src/utils/value.js';
4
-
5
- export default function size_operator(jsonb_expression, comparison_value, parameter_state) {
6
- if(is_nan(comparison_value)) {
7
- throw new QueryError('Invalid value for $size operator', {
8
- operator: '$size',
9
- value: comparison_value
10
- });
11
- }
12
-
13
- const numeric_value = Number(comparison_value);
14
- const placeholder = bind_parameter(parameter_state, numeric_value);
15
- return 'jsonb_array_length(' + jsonb_expression + ') = ' + placeholder;
16
- }
1
+ /*
2
+ * MODULE RESPONSIBILITY
3
+ * Compile the SQL fragment for the $size read-query operator.
4
+ */
5
+ import QueryError from '#src/errors/query-error.js';
6
+ import {bind_parameter} from '#src/sql/parameter-binder.js';
7
+ import {is_nan} from '#src/utils/value.js';
8
+
9
+ function size_operator(jsonb_expression, comparison_value, parameter_state) {
10
+ if(is_nan(comparison_value)) {
11
+ throw new QueryError('Invalid value for $size operator', {
12
+ operator: '$size',
13
+ value: comparison_value
14
+ });
15
+ }
16
+
17
+ const numeric_value = Number(comparison_value);
18
+ const placeholder = bind_parameter(parameter_state, numeric_value);
19
+
20
+ return 'jsonb_array_length(' + jsonb_expression + ') = ' + placeholder;
21
+ }
22
+
23
+ export default size_operator;
@@ -1,13 +1,18 @@
1
- export function create_parameter_state(start_index) {
2
- return {
3
- params: [],
4
- current_index: start_index || 1
5
- };
6
- }
7
-
8
- export function bind_parameter(parameter_state, value) {
9
- const placeholder = '$' + parameter_state.current_index;
10
- parameter_state.params.push(value);
11
- parameter_state.current_index += 1;
12
- return placeholder;
13
- }
1
+ function create_parameter_state(start_index) {
2
+ return {
3
+ params: [],
4
+ current_index: start_index || 1
5
+ };
6
+ }
7
+
8
+ function bind_parameter(parameter_state, value) {
9
+ const placeholder = '$' + parameter_state.current_index;
10
+ parameter_state.params.push(value);
11
+ parameter_state.current_index += 1;
12
+ return placeholder;
13
+ }
14
+
15
+ export {
16
+ create_parameter_state,
17
+ bind_parameter
18
+ };