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.
- package/README.md +36 -18
- package/docs/api/connection.md +144 -0
- package/docs/api/delta-tracker.md +106 -0
- package/docs/api/document.md +77 -0
- package/docs/api/field-types.md +329 -0
- package/docs/api/index.md +35 -0
- package/docs/api/model.md +392 -0
- package/docs/api/query-builder.md +81 -0
- package/docs/api/schema.md +204 -0
- package/docs/architecture-flow.md +397 -0
- package/docs/examples.md +495 -218
- package/docs/jsonb-ops.md +171 -0
- package/docs/lifecycle/model-compilation.md +111 -0
- package/docs/lifecycle.md +146 -0
- package/docs/query-translation.md +11 -10
- package/package.json +10 -3
- package/src/connection/connect.js +12 -17
- package/src/connection/connection.js +128 -0
- package/src/connection/server-capabilities.js +60 -59
- package/src/constants/defaults.js +32 -19
- package/src/constants/{id-strategies.js → id-strategy.js} +28 -29
- package/src/constants/intake-mode.js +8 -0
- package/src/debug/debug-logger.js +17 -15
- package/src/errors/model-overwrite-error.js +25 -0
- package/src/errors/query-error.js +25 -23
- package/src/errors/validation-error.js +25 -23
- package/src/field-types/base-field-type.js +137 -140
- package/src/field-types/builtins/advanced.js +365 -365
- package/src/field-types/builtins/index.js +579 -585
- package/src/field-types/field-type-namespace.js +9 -0
- package/src/field-types/registry.js +149 -122
- package/src/index.js +26 -36
- package/src/migration/ensure-index.js +157 -154
- package/src/migration/ensure-schema.js +27 -15
- package/src/migration/ensure-table.js +44 -31
- package/src/migration/schema-indexes-resolver.js +8 -6
- package/src/model/document-instance.js +29 -540
- package/src/model/document.js +60 -0
- package/src/model/factory/constants.js +36 -0
- package/src/model/factory/index.js +58 -0
- package/src/model/model.js +875 -0
- package/src/model/operations/delete-one.js +39 -0
- package/src/model/operations/insert-one.js +35 -0
- package/src/model/operations/query-builder.js +132 -0
- package/src/model/operations/update-one.js +333 -0
- package/src/model/state.js +34 -0
- package/src/schema/field-definition-parser.js +213 -218
- package/src/schema/path-introspection.js +87 -82
- package/src/schema/schema-compiler.js +126 -212
- package/src/schema/schema.js +621 -138
- package/src/sql/index.js +17 -0
- package/src/sql/jsonb/ops.js +153 -0
- package/src/{query → sql/jsonb}/path-parser.js +54 -43
- package/src/sql/jsonb/read/elem-match.js +133 -0
- package/src/{query → sql/jsonb/read}/operators/contains.js +13 -7
- package/src/sql/jsonb/read/operators/elem-match.js +9 -0
- package/src/{query → sql/jsonb/read}/operators/has-all-keys.js +17 -11
- package/src/{query → sql/jsonb/read}/operators/has-any-keys.js +18 -11
- package/src/sql/jsonb/read/operators/has-key.js +12 -0
- package/src/{query → sql/jsonb/read}/operators/jsonpath-exists.js +22 -15
- package/src/{query → sql/jsonb/read}/operators/jsonpath-match.js +22 -15
- package/src/{query → sql/jsonb/read}/operators/size.js +23 -16
- package/src/sql/parameter-binder.js +18 -13
- package/src/sql/read/build-count-query.js +12 -0
- package/src/sql/read/build-find-query.js +25 -0
- package/src/sql/read/limit-skip.js +21 -0
- package/src/sql/read/sort.js +85 -0
- package/src/sql/read/where/base-fields.js +310 -0
- package/src/sql/read/where/casting.js +90 -0
- package/src/sql/read/where/context.js +79 -0
- package/src/sql/read/where/field-clause.js +58 -0
- package/src/sql/read/where/index.js +38 -0
- package/src/sql/read/where/operator-entries.js +29 -0
- package/src/{query → sql/read/where}/operators/all.js +16 -10
- package/src/sql/read/where/operators/eq.js +12 -0
- package/src/{query → sql/read/where}/operators/gt.js +23 -16
- package/src/{query → sql/read/where}/operators/gte.js +23 -16
- package/src/{query → sql/read/where}/operators/in.js +18 -12
- package/src/sql/read/where/operators/index.js +40 -0
- package/src/{query → sql/read/where}/operators/lt.js +23 -16
- package/src/{query → sql/read/where}/operators/lte.js +23 -16
- package/src/sql/read/where/operators/ne.js +12 -0
- package/src/{query → sql/read/where}/operators/nin.js +18 -12
- package/src/{query → sql/read/where}/operators/regex.js +14 -8
- package/src/sql/read/where/operators.js +126 -0
- package/src/sql/read/where/text-operators.js +83 -0
- package/src/sql/run.js +46 -0
- package/src/sql/write/build-delete-query.js +33 -0
- package/src/sql/write/build-insert-query.js +42 -0
- package/src/sql/write/build-update-query.js +65 -0
- package/src/utils/assert.js +34 -27
- package/src/utils/delta-tracker/.archive/1 tracker-redesign-codex-v2.md +250 -0
- package/src/utils/delta-tracker/.archive/1 tracker-redesign-gemini.md +101 -0
- package/src/utils/delta-tracker/.archive/2 evaluation by gemini.txt +65 -0
- package/src/utils/delta-tracker/.archive/2 evaluation by grok.txt +39 -0
- package/src/utils/delta-tracker/.archive/3 gemini evaluate grok.txt +37 -0
- package/src/utils/delta-tracker/.archive/3 grok evaluate gemini.txt +63 -0
- package/src/utils/delta-tracker/.archive/4 gemini veredict.txt +16 -0
- package/src/utils/delta-tracker/.archive/index.1.js +587 -0
- package/src/utils/delta-tracker/.archive/index.2.js +612 -0
- package/src/utils/delta-tracker/index.js +592 -0
- package/src/utils/dirty-tracker/inline.js +335 -0
- package/src/utils/dirty-tracker/instance.js +414 -0
- package/src/utils/dirty-tracker/static.js +343 -0
- package/src/utils/json-safe.js +13 -9
- package/src/utils/object-path.js +227 -33
- package/src/utils/object.js +408 -168
- package/src/utils/string.js +55 -0
- package/src/utils/value.js +169 -30
- package/docs/api.md +0 -152
- package/src/connection/disconnect.js +0 -16
- package/src/connection/pool-store.js +0 -46
- package/src/model/model-factory.js +0 -555
- package/src/query/limit-skip-compiler.js +0 -31
- package/src/query/operators/elem-match.js +0 -3
- package/src/query/operators/eq.js +0 -6
- package/src/query/operators/has-key.js +0 -6
- package/src/query/operators/index.js +0 -60
- package/src/query/operators/ne.js +0 -6
- package/src/query/query-builder.js +0 -93
- package/src/query/sort-compiler.js +0 -30
- package/src/query/where-compiler.js +0 -477
- package/src/sql/sql-runner.js +0 -31
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import limit_skip_compiler from '#src/query/limit-skip-compiler.js';
|
|
2
|
-
import sort_compiler from '#src/query/sort-compiler.js';
|
|
3
|
-
import where_compiler from '#src/query/where-compiler.js';
|
|
4
|
-
|
|
5
|
-
import sql_runner from '#src/sql/sql-runner.js';
|
|
6
|
-
|
|
7
|
-
import {quote_identifier} from '#src/utils/assert.js';
|
|
8
|
-
|
|
9
|
-
export default function QueryBuilder(model_constructor, operation_name, query_filter, projection_value) {
|
|
10
|
-
this.model_constructor = model_constructor;
|
|
11
|
-
this.operation_name = operation_name;
|
|
12
|
-
this.base_filter = query_filter || {};
|
|
13
|
-
this.where_filter = {};
|
|
14
|
-
this.sort_definition = null;
|
|
15
|
-
this.limit_count = null;
|
|
16
|
-
this.skip_count = null;
|
|
17
|
-
this.projection_value = projection_value || null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
QueryBuilder.prototype.where = function (extra_filter) {
|
|
21
|
-
this.where_filter = Object.assign({}, this.where_filter, extra_filter || {});
|
|
22
|
-
return this;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
QueryBuilder.prototype.sort = function (sort_definition) {
|
|
26
|
-
this.sort_definition = sort_definition || null;
|
|
27
|
-
return this;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
QueryBuilder.prototype.limit = function (limit_value) {
|
|
31
|
-
this.limit_count = limit_value;
|
|
32
|
-
return this;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
QueryBuilder.prototype.skip = function (skip_value) {
|
|
36
|
-
this.skip_count = skip_value;
|
|
37
|
-
return this;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
QueryBuilder.prototype.exec = async function () {
|
|
41
|
-
const schema_instance = this.model_constructor.schema_instance;
|
|
42
|
-
const model_options = this.model_constructor.model_options;
|
|
43
|
-
const table_name = model_options.table_name;
|
|
44
|
-
const data_column = model_options.data_column;
|
|
45
|
-
const table_identifier = quote_identifier(table_name);
|
|
46
|
-
const data_identifier = quote_identifier(data_column);
|
|
47
|
-
const merged_filter = Object.assign({}, this.base_filter, this.where_filter);
|
|
48
|
-
const where_result = where_compiler(merged_filter, {
|
|
49
|
-
data_column: data_column,
|
|
50
|
-
schema: schema_instance
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if(this.operation_name === 'count_documents') {
|
|
55
|
-
const count_sql = 'SELECT COUNT(*)::int AS total_count FROM ' + table_identifier + ' WHERE ' + where_result.sql;
|
|
56
|
-
const count_result = await sql_runner(count_sql, where_result.params);
|
|
57
|
-
|
|
58
|
-
if(count_result.rows.length === 0) {
|
|
59
|
-
return 0;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return Number(count_result.rows[0].total_count);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
let sql_text = 'SELECT ' + data_identifier + ' AS data FROM ' + table_identifier + ' WHERE ' + where_result.sql;
|
|
66
|
-
const sort_sql = sort_compiler(this.sort_definition, {
|
|
67
|
-
data_column: data_column
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
sql_text += sort_sql;
|
|
71
|
-
|
|
72
|
-
if(this.operation_name === 'find_one') {
|
|
73
|
-
if(this.limit_count === null || this.limit_count === undefined) {
|
|
74
|
-
this.limit_count = 1;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
sql_text += limit_skip_compiler(this.limit_count, this.skip_count);
|
|
79
|
-
|
|
80
|
-
const query_result = await sql_runner(sql_text, where_result.params);
|
|
81
|
-
|
|
82
|
-
if(this.operation_name === 'find_one') {
|
|
83
|
-
if(query_result.rows.length === 0) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return query_result.rows[0].data;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return query_result.rows.map(function map_row(row_value) {
|
|
91
|
-
return row_value.data;
|
|
92
|
-
});
|
|
93
|
-
};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import {quote_identifier} from '#src/utils/assert.js';
|
|
2
|
-
import {build_text_expression} from '#src/query/path-parser.js';
|
|
3
|
-
|
|
4
|
-
export default function sort_compiler(sort_definition, compile_options) {
|
|
5
|
-
if(!sort_definition || typeof sort_definition !== 'object') {
|
|
6
|
-
return '';
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const data_column_name = compile_options?.data_column ?? 'data';
|
|
10
|
-
const data_column_reference = quote_identifier(data_column_name);
|
|
11
|
-
const sort_entries = Object.entries(sort_definition);
|
|
12
|
-
const sort_clauses = [];
|
|
13
|
-
let entry_index = 0;
|
|
14
|
-
|
|
15
|
-
while(entry_index < sort_entries.length) {
|
|
16
|
-
const sort_entry = sort_entries[entry_index];
|
|
17
|
-
const path_value = sort_entry[0];
|
|
18
|
-
const direction_value = Number(sort_entry[1]) === -1 ? 'DESC' : 'ASC';
|
|
19
|
-
const text_expression = build_text_expression(data_column_reference, path_value);
|
|
20
|
-
|
|
21
|
-
sort_clauses.push(text_expression + ' ' + direction_value);
|
|
22
|
-
entry_index += 1;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if(sort_clauses.length === 0) {
|
|
26
|
-
return '';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return ' ORDER BY ' + sort_clauses.join(', ');
|
|
30
|
-
}
|
|
@@ -1,477 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
all_operator,
|
|
3
|
-
contains_operator,
|
|
4
|
-
elem_match_operator,
|
|
5
|
-
eq_operator,
|
|
6
|
-
gt_operator,
|
|
7
|
-
gte_operator,
|
|
8
|
-
has_all_keys_operator,
|
|
9
|
-
has_any_keys_operator,
|
|
10
|
-
has_key_operator,
|
|
11
|
-
in_operator,
|
|
12
|
-
jsonpath_exists_operator,
|
|
13
|
-
jsonpath_match_operator,
|
|
14
|
-
lt_operator,
|
|
15
|
-
lte_operator,
|
|
16
|
-
ne_operator,
|
|
17
|
-
nin_operator,
|
|
18
|
-
regex_operator,
|
|
19
|
-
size_operator
|
|
20
|
-
} from '#src/query/operators/index.js';
|
|
21
|
-
|
|
22
|
-
import {build_elem_text_expression, build_json_expression, build_text_expression, parse_path} from '#src/query/path-parser.js';
|
|
23
|
-
|
|
24
|
-
import {create_parameter_state} from '#src/sql/parameter-binder.js';
|
|
25
|
-
|
|
26
|
-
import {quote_identifier} from '#src/utils/assert.js';
|
|
27
|
-
import {build_nested_object, split_dot_path} from '#src/utils/object-path.js';
|
|
28
|
-
import {is_object} from '#src/utils/value.js';
|
|
29
|
-
|
|
30
|
-
// TODO: might as well split into multiple files within the same directory
|
|
31
|
-
|
|
32
|
-
function where_compiler(query_filter, compile_options, start_index) {
|
|
33
|
-
const filter_object = query_filter ?? {};
|
|
34
|
-
const options = compile_options ?? {};
|
|
35
|
-
const parameter_state = create_parameter_state(start_index);
|
|
36
|
-
const clause_list = [];
|
|
37
|
-
const filter_entries = Object.entries(filter_object);
|
|
38
|
-
let entry_index = 0;
|
|
39
|
-
|
|
40
|
-
while(entry_index < filter_entries.length) {
|
|
41
|
-
const entry_pair = filter_entries[entry_index];
|
|
42
|
-
const path_value = entry_pair[0];
|
|
43
|
-
const comparison_value = entry_pair[1];
|
|
44
|
-
const clause = compile_field_clause(path_value, comparison_value, options, parameter_state);
|
|
45
|
-
|
|
46
|
-
if(clause) {
|
|
47
|
-
clause_list.push(clause);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
entry_index += 1;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
sql: clause_list.length > 0 ? clause_list.join(' AND ') : 'TRUE',
|
|
55
|
-
params: parameter_state.params,
|
|
56
|
-
next_index: parameter_state.current_index
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function compile_field_clause(path_value, comparison_value, compile_options, parameter_state) {
|
|
61
|
-
const data_column_name = compile_options?.data_column ?? 'data';
|
|
62
|
-
const data_column_reference = quote_identifier(data_column_name);
|
|
63
|
-
const schema_instance = compile_options?.schema ?? null;
|
|
64
|
-
const is_array_path = should_use_array_contains(path_value, comparison_value, schema_instance);
|
|
65
|
-
|
|
66
|
-
if(comparison_value instanceof RegExp) {
|
|
67
|
-
const text_expression = build_text_expression(data_column_reference, path_value);
|
|
68
|
-
return regex_operator(text_expression, comparison_value.source, comparison_value.flags, parameter_state);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if(is_object(comparison_value)) {
|
|
72
|
-
if(comparison_value.$elem_match !== undefined) {
|
|
73
|
-
return compile_elem_match_clause(path_value, comparison_value.$elem_match, data_column_reference, parameter_state);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if(has_operator_entries(comparison_value)) {
|
|
77
|
-
return compile_operator_object(path_value, comparison_value, data_column_reference, schema_instance, parameter_state);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const nested_object = build_nested_object(path_value, comparison_value);
|
|
81
|
-
return contains_operator(data_column_reference, nested_object, parameter_state);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if(is_array_path) {
|
|
85
|
-
const casted_array_value = cast_array_contains_value(path_value, comparison_value, schema_instance);
|
|
86
|
-
const nested_object = build_nested_object(path_value, [casted_array_value]);
|
|
87
|
-
return contains_operator(data_column_reference, nested_object, parameter_state);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const text_expression = build_text_expression(data_column_reference, path_value);
|
|
91
|
-
const casted_comparison_value = cast_query_value(path_value, comparison_value, schema_instance);
|
|
92
|
-
return eq_operator(text_expression, casted_comparison_value, parameter_state);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function compile_operator_object(path_value, operator_definition, data_column_reference, schema_instance, parameter_state) {
|
|
96
|
-
const clause_list = [];
|
|
97
|
-
const operator_entries = Object.entries(operator_definition);
|
|
98
|
-
const path_info = parse_path(path_value);
|
|
99
|
-
const regex_options = operator_definition.$options || '';
|
|
100
|
-
const has_array_root = is_array_root(schema_instance, path_info.root_path) && path_info.child_segments.length > 0;
|
|
101
|
-
let entry_index = 0;
|
|
102
|
-
|
|
103
|
-
while(entry_index < operator_entries.length) {
|
|
104
|
-
const operator_entry = operator_entries[entry_index];
|
|
105
|
-
const operator_name = operator_entry[0];
|
|
106
|
-
const operator_value = operator_entry[1];
|
|
107
|
-
|
|
108
|
-
if(operator_name === '$options') {
|
|
109
|
-
entry_index += 1;
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if(has_array_root) {
|
|
114
|
-
clause_list.push(
|
|
115
|
-
compile_nested_array_operator(
|
|
116
|
-
operator_name,
|
|
117
|
-
operator_value,
|
|
118
|
-
regex_options,
|
|
119
|
-
path_info,
|
|
120
|
-
data_column_reference,
|
|
121
|
-
parameter_state
|
|
122
|
-
)
|
|
123
|
-
);
|
|
124
|
-
entry_index += 1;
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
clause_list.push(
|
|
129
|
-
compile_standard_operator(
|
|
130
|
-
operator_name,
|
|
131
|
-
operator_value,
|
|
132
|
-
regex_options,
|
|
133
|
-
path_value,
|
|
134
|
-
data_column_reference,
|
|
135
|
-
schema_instance,
|
|
136
|
-
parameter_state
|
|
137
|
-
)
|
|
138
|
-
);
|
|
139
|
-
entry_index += 1;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return clause_list.join(' AND ');
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function compile_standard_operator(operator_name, operator_value, regex_options, path_value, data_column_reference, schema_instance, parameter_state) {
|
|
146
|
-
const text_expression = build_text_expression(data_column_reference, path_value);
|
|
147
|
-
const json_expression = build_json_expression(data_column_reference, path_value);
|
|
148
|
-
const casted_operator_value = cast_operator_value(path_value, operator_name, operator_value, schema_instance);
|
|
149
|
-
|
|
150
|
-
if(operator_name === '$eq') {
|
|
151
|
-
return eq_operator(text_expression, casted_operator_value, parameter_state);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if(operator_name === '$ne') {
|
|
155
|
-
return ne_operator(text_expression, casted_operator_value, parameter_state);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if(operator_name === '$gt') {
|
|
159
|
-
return gt_operator(text_expression, casted_operator_value, parameter_state);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if(operator_name === '$gte') {
|
|
163
|
-
return gte_operator(text_expression, casted_operator_value, parameter_state);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if(operator_name === '$lt') {
|
|
167
|
-
return lt_operator(text_expression, casted_operator_value, parameter_state);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if(operator_name === '$lte') {
|
|
171
|
-
return lte_operator(text_expression, casted_operator_value, parameter_state);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if(operator_name === '$in') {
|
|
175
|
-
return in_operator(text_expression, casted_operator_value, parameter_state);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if(operator_name === '$nin') {
|
|
179
|
-
return nin_operator(text_expression, casted_operator_value, parameter_state);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if(operator_name === '$regex') {
|
|
183
|
-
return regex_operator(text_expression, operator_value, regex_options, parameter_state);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if(operator_name === '$contains') {
|
|
187
|
-
const nested_object = build_nested_object(path_value, operator_value);
|
|
188
|
-
return contains_operator(data_column_reference, nested_object, parameter_state);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if(operator_name === '$has_key') {
|
|
192
|
-
return has_key_operator(json_expression, operator_value, parameter_state);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if(operator_name === '$has_any_keys') {
|
|
196
|
-
return has_any_keys_operator(json_expression, operator_value, parameter_state);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if(operator_name === '$has_all_keys') {
|
|
200
|
-
return has_all_keys_operator(json_expression, operator_value, parameter_state);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if(operator_name === '$json_path_exists') {
|
|
204
|
-
return jsonpath_exists_operator(json_expression, operator_value, parameter_state);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if(operator_name === '$json_path_match') {
|
|
208
|
-
return jsonpath_match_operator(json_expression, operator_value, parameter_state);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if(operator_name === '$all') {
|
|
212
|
-
return all_operator(json_expression, casted_operator_value, parameter_state);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if(operator_name === '$size') {
|
|
216
|
-
return size_operator(json_expression, operator_value, parameter_state);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
throw new Error('Unsupported operator: ' + operator_name);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function compile_nested_array_operator(operator_name, operator_value, regex_options, path_info, data_column_reference, parameter_state) {
|
|
223
|
-
const array_expression = build_json_expression(data_column_reference, path_info.root_path);
|
|
224
|
-
const elem_expression = build_elem_text_expression('elem', path_info.child_segments);
|
|
225
|
-
const predicate = compile_scalar_operator(operator_name, operator_value, regex_options, elem_expression, parameter_state);
|
|
226
|
-
|
|
227
|
-
return elem_match_operator(array_expression, predicate);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function compile_elem_match_clause(path_value, elem_match_value, data_column_reference, parameter_state) {
|
|
231
|
-
const array_expression = build_json_expression(data_column_reference, path_value);
|
|
232
|
-
const predicate_list = [];
|
|
233
|
-
|
|
234
|
-
if(elem_match_value instanceof RegExp) {
|
|
235
|
-
predicate_list.push(regex_operator("elem #>> '{}'", elem_match_value.source, elem_match_value.flags, parameter_state));
|
|
236
|
-
return elem_match_operator(array_expression, predicate_list.join(' AND '));
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if(!is_object(elem_match_value)) {
|
|
240
|
-
predicate_list.push(eq_operator("elem #>> '{}'", elem_match_value, parameter_state));
|
|
241
|
-
return elem_match_operator(array_expression, predicate_list.join(' AND '));
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if(has_operator_entries(elem_match_value)) {
|
|
245
|
-
const operator_entries = Object.entries(elem_match_value);
|
|
246
|
-
const option_value = elem_match_value.$options || '';
|
|
247
|
-
let operator_index = 0;
|
|
248
|
-
|
|
249
|
-
while(operator_index < operator_entries.length) {
|
|
250
|
-
const operator_entry = operator_entries[operator_index];
|
|
251
|
-
const operator_name = operator_entry[0];
|
|
252
|
-
const operator_value = operator_entry[1];
|
|
253
|
-
|
|
254
|
-
if(operator_name === '$options') {
|
|
255
|
-
operator_index += 1;
|
|
256
|
-
continue;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
predicate_list.push(
|
|
260
|
-
compile_scalar_operator(operator_name, operator_value, option_value, "elem #>> '{}'", parameter_state)
|
|
261
|
-
);
|
|
262
|
-
operator_index += 1;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return elem_match_operator(array_expression, predicate_list.join(' AND '));
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const elem_entries = Object.entries(elem_match_value);
|
|
269
|
-
let entry_index = 0;
|
|
270
|
-
|
|
271
|
-
while(entry_index < elem_entries.length) {
|
|
272
|
-
const entry_pair = elem_entries[entry_index];
|
|
273
|
-
const nested_path = entry_pair[0];
|
|
274
|
-
const nested_value = entry_pair[1];
|
|
275
|
-
const nested_segments = split_dot_path(nested_path);
|
|
276
|
-
const elem_expression = build_elem_text_expression('elem', nested_segments);
|
|
277
|
-
|
|
278
|
-
if(nested_value instanceof RegExp) {
|
|
279
|
-
predicate_list.push(regex_operator(elem_expression, nested_value.source, nested_value.flags, parameter_state));
|
|
280
|
-
entry_index += 1;
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if(is_object(nested_value) && has_operator_entries(nested_value)) {
|
|
285
|
-
const nested_operator_entries = Object.entries(nested_value);
|
|
286
|
-
const option_value = nested_value.$options || '';
|
|
287
|
-
let operator_index = 0;
|
|
288
|
-
|
|
289
|
-
while(operator_index < nested_operator_entries.length) {
|
|
290
|
-
const operator_entry = nested_operator_entries[operator_index];
|
|
291
|
-
const operator_name = operator_entry[0];
|
|
292
|
-
const operator_value = operator_entry[1];
|
|
293
|
-
|
|
294
|
-
if(operator_name === '$options') {
|
|
295
|
-
operator_index += 1;
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
predicate_list.push(
|
|
300
|
-
compile_scalar_operator(operator_name, operator_value, option_value, elem_expression, parameter_state)
|
|
301
|
-
);
|
|
302
|
-
operator_index += 1;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
entry_index += 1;
|
|
306
|
-
continue;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
predicate_list.push(eq_operator(elem_expression, nested_value, parameter_state));
|
|
310
|
-
entry_index += 1;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return elem_match_operator(array_expression, predicate_list.join(' AND '));
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function compile_scalar_operator(operator_name, operator_value, regex_options, elem_expression, parameter_state) {
|
|
317
|
-
if(operator_name === '$eq') {
|
|
318
|
-
return eq_operator(elem_expression, operator_value, parameter_state);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if(operator_name === '$ne') {
|
|
322
|
-
return ne_operator(elem_expression, operator_value, parameter_state);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if(operator_name === '$gt') {
|
|
326
|
-
return gt_operator(elem_expression, operator_value, parameter_state);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if(operator_name === '$gte') {
|
|
330
|
-
return gte_operator(elem_expression, operator_value, parameter_state);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if(operator_name === '$lt') {
|
|
334
|
-
return lt_operator(elem_expression, operator_value, parameter_state);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if(operator_name === '$lte') {
|
|
338
|
-
return lte_operator(elem_expression, operator_value, parameter_state);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if(operator_name === '$in') {
|
|
342
|
-
return in_operator(elem_expression, operator_value, parameter_state);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
if(operator_name === '$nin') {
|
|
346
|
-
return nin_operator(elem_expression, operator_value, parameter_state);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if(operator_name === '$regex') {
|
|
350
|
-
return regex_operator(elem_expression, operator_value, regex_options, parameter_state);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
throw new Error('Unsupported operator inside $elem_match: ' + operator_name);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
function cast_operator_value(path_value, operator_name, operator_value, schema_instance) {
|
|
357
|
-
if(
|
|
358
|
-
operator_name === '$eq' ||
|
|
359
|
-
operator_name === '$ne' ||
|
|
360
|
-
operator_name === '$gt' ||
|
|
361
|
-
operator_name === '$gte' ||
|
|
362
|
-
operator_name === '$lt' ||
|
|
363
|
-
operator_name === '$lte'
|
|
364
|
-
) {
|
|
365
|
-
return cast_query_value(path_value, operator_value, schema_instance);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if(operator_name === '$in' || operator_name === '$nin') {
|
|
369
|
-
if(!Array.isArray(operator_value)) {
|
|
370
|
-
return [cast_query_value(path_value, operator_value, schema_instance)];
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const casted_values = [];
|
|
374
|
-
let value_index = 0;
|
|
375
|
-
|
|
376
|
-
while(value_index < operator_value.length) {
|
|
377
|
-
casted_values.push(cast_query_value(path_value, operator_value[value_index], schema_instance));
|
|
378
|
-
value_index += 1;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return casted_values;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if(operator_name === '$all') {
|
|
385
|
-
if(!Array.isArray(operator_value)) {
|
|
386
|
-
return operator_value;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const casted_values = [];
|
|
390
|
-
let value_index = 0;
|
|
391
|
-
|
|
392
|
-
while(value_index < operator_value.length) {
|
|
393
|
-
casted_values.push(cast_array_contains_value(path_value, operator_value[value_index], schema_instance));
|
|
394
|
-
value_index += 1;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
return casted_values;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
return operator_value;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
function cast_query_value(path_value, comparison_value, schema_instance) {
|
|
404
|
-
if(comparison_value === undefined || comparison_value === null) {
|
|
405
|
-
return comparison_value;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
const field_type = resolve_query_field_type(schema_instance, path_value);
|
|
409
|
-
|
|
410
|
-
if(!field_type || typeof field_type.cast !== 'function') {
|
|
411
|
-
return comparison_value;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
return field_type.cast(comparison_value, {
|
|
415
|
-
path: path_value,
|
|
416
|
-
mode: 'query'
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function cast_array_contains_value(path_value, comparison_value, schema_instance) {
|
|
421
|
-
const field_type = resolve_query_field_type(schema_instance, path_value);
|
|
422
|
-
|
|
423
|
-
if(!field_type || field_type.instance !== 'Array' || !field_type.of_field_type || typeof field_type.of_field_type.cast !== 'function') {
|
|
424
|
-
return comparison_value;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
return field_type.of_field_type.cast(comparison_value, {
|
|
428
|
-
path: path_value,
|
|
429
|
-
mode: 'query'
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
function resolve_query_field_type(schema_instance, path_value) {
|
|
434
|
-
if(!schema_instance || typeof schema_instance.path !== 'function') {
|
|
435
|
-
return null;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
return schema_instance.path(path_value);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
function should_use_array_contains(path_value, comparison_value, schema_instance) {
|
|
442
|
-
if(!schema_instance || typeof schema_instance.is_array_root !== 'function') {
|
|
443
|
-
return false;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
if(is_object(comparison_value) || comparison_value instanceof RegExp) {
|
|
447
|
-
return false;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
return schema_instance.is_array_root(path_value);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
function is_array_root(schema_instance, root_path) {
|
|
454
|
-
if(!schema_instance || typeof schema_instance.is_array_root !== 'function') {
|
|
455
|
-
return false;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
return schema_instance.is_array_root(root_path);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
function has_operator_entries(object_value) {
|
|
462
|
-
const keys = Object.keys(object_value);
|
|
463
|
-
let key_index = 0;
|
|
464
|
-
|
|
465
|
-
while(key_index < keys.length) {
|
|
466
|
-
if(keys[key_index][0] === '$') {
|
|
467
|
-
return true;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
key_index += 1;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
return false;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
export default where_compiler;
|
|
477
|
-
|
package/src/sql/sql-runner.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import debug_logger from '#src/debug/debug-logger.js';
|
|
2
|
-
import QueryError from '#src/errors/query-error.js';
|
|
3
|
-
import {get_debug_mode, get_pool} from '#src/connection/pool-store.js';
|
|
4
|
-
|
|
5
|
-
export default async function sql_runner(sql_text, sql_params) {
|
|
6
|
-
const params = sql_params || [];
|
|
7
|
-
const debug_mode = get_debug_mode();
|
|
8
|
-
const pool_instance = get_pool();
|
|
9
|
-
|
|
10
|
-
debug_logger(debug_mode, 'sql_query', {
|
|
11
|
-
sql_text: sql_text,
|
|
12
|
-
params: params
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
return await pool_instance.query(sql_text, params);
|
|
17
|
-
} catch(error) {
|
|
18
|
-
debug_logger(debug_mode, 'sql_error', {
|
|
19
|
-
sql_text: sql_text,
|
|
20
|
-
params: params,
|
|
21
|
-
message: error.message
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
throw new QueryError('SQL execution failed', {
|
|
25
|
-
sql_text: sql_text,
|
|
26
|
-
params: params,
|
|
27
|
-
cause: error.message
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|