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
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile one read-query filter object into SQL and bound params.
|
|
4
|
+
*/
|
|
5
|
+
import {create_parameter_state} from '#src/sql/parameter-binder.js';
|
|
6
|
+
|
|
7
|
+
import {create_compile_context} from '#src/sql/read/where/context.js';
|
|
8
|
+
import {compile_field_clause} from '#src/sql/read/where/field-clause.js';
|
|
9
|
+
|
|
10
|
+
function where_compiler(query_filter, compile_options, start_index) {
|
|
11
|
+
const filter_object = query_filter ?? {};
|
|
12
|
+
const compile_context = create_compile_context(compile_options);
|
|
13
|
+
const parameter_state = create_parameter_state(start_index);
|
|
14
|
+
const filter_entries = Object.entries(filter_object);
|
|
15
|
+
const clause_list = [];
|
|
16
|
+
let entry_index = 0;
|
|
17
|
+
|
|
18
|
+
while(entry_index < filter_entries.length) {
|
|
19
|
+
const entry_pair = filter_entries[entry_index];
|
|
20
|
+
const path_value = entry_pair[0];
|
|
21
|
+
const comparison_value = entry_pair[1];
|
|
22
|
+
const clause = compile_field_clause(path_value, comparison_value, compile_context, parameter_state);
|
|
23
|
+
|
|
24
|
+
if(clause) {
|
|
25
|
+
clause_list.push(clause);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
entry_index += 1;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
sql: clause_list.length > 0 ? clause_list.join(' AND ') : 'TRUE',
|
|
33
|
+
params: parameter_state.params,
|
|
34
|
+
next_index: parameter_state.current_index
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default where_compiler;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Iterate operator entries and compile their clause fragments.
|
|
4
|
+
*/
|
|
5
|
+
function compile_operator_entry_clauses(operator_definition, compile_operator_clause) {
|
|
6
|
+
const clause_list = [];
|
|
7
|
+
const operator_entries = Object.entries(operator_definition);
|
|
8
|
+
let entry_index = 0;
|
|
9
|
+
|
|
10
|
+
while(entry_index < operator_entries.length) {
|
|
11
|
+
const operator_entry = operator_entries[entry_index];
|
|
12
|
+
const operator_name = operator_entry[0];
|
|
13
|
+
const operator_value = operator_entry[1];
|
|
14
|
+
|
|
15
|
+
if(operator_name === '$options') {
|
|
16
|
+
entry_index += 1;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
clause_list.push(compile_operator_clause(operator_name, operator_value));
|
|
21
|
+
entry_index += 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return clause_list;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
compile_operator_entry_clauses
|
|
29
|
+
};
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile the SQL fragment for the $all read-query operator.
|
|
4
|
+
*/
|
|
5
|
+
import {bind_parameter} from '#src/sql/parameter-binder.js';
|
|
6
|
+
import {jsonb_stringify} from '#src/utils/json.js';
|
|
7
|
+
import {to_array} from '#src/utils/array.js';
|
|
8
|
+
|
|
9
|
+
function all_operator(jsonb_expression, comparison_value, parameter_state) {
|
|
10
|
+
const value_list = to_array(comparison_value);
|
|
11
|
+
const placeholder = bind_parameter(parameter_state, jsonb_stringify(value_list));
|
|
12
|
+
|
|
13
|
+
return jsonb_expression + ' @> ' + placeholder + '::jsonb';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default all_operator;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile the SQL fragment for the $eq read-query operator.
|
|
4
|
+
*/
|
|
5
|
+
import {bind_parameter} from '#src/sql/parameter-binder.js';
|
|
6
|
+
|
|
7
|
+
function eq_operator(sql_expression, comparison_value, parameter_state) {
|
|
8
|
+
const placeholder = bind_parameter(parameter_state, String(comparison_value));
|
|
9
|
+
return sql_expression + ' = ' + placeholder;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default eq_operator;
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile the SQL fragment for the $gt 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 gt_operator(sql_expression, comparison_value, parameter_state) {
|
|
10
|
+
if(is_nan(comparison_value)) {
|
|
11
|
+
throw new QueryError('Invalid value for $gt operator', {
|
|
12
|
+
operator: '$gt',
|
|
13
|
+
value: comparison_value
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const numeric_value = typeof comparison_value === 'bigint' ? comparison_value.toString() : Number(comparison_value);
|
|
18
|
+
const placeholder = bind_parameter(parameter_state, numeric_value);
|
|
19
|
+
|
|
20
|
+
return '(' + sql_expression + ')::numeric > ' + placeholder;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default gt_operator;
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile the SQL fragment for the $gte 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 gte_operator(sql_expression, comparison_value, parameter_state) {
|
|
10
|
+
if(is_nan(comparison_value)) {
|
|
11
|
+
throw new QueryError('Invalid value for $gte operator', {
|
|
12
|
+
operator: '$gte',
|
|
13
|
+
value: comparison_value
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const numeric_value = typeof comparison_value === 'bigint' ? comparison_value.toString() : Number(comparison_value);
|
|
18
|
+
const placeholder = bind_parameter(parameter_state, numeric_value);
|
|
19
|
+
|
|
20
|
+
return '(' + sql_expression + ')::numeric >= ' + placeholder;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default gte_operator;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile the SQL fragment for the $in 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 in_operator(sql_expression, comparison_value, parameter_state) {
|
|
9
|
+
const value_list = to_array(comparison_value);
|
|
10
|
+
const normalized_values = value_list.map(function map_value(current_value) {
|
|
11
|
+
return String(current_value);
|
|
12
|
+
});
|
|
13
|
+
const placeholder = bind_parameter(parameter_state, normalized_values);
|
|
14
|
+
|
|
15
|
+
return sql_expression + ' = ANY(' + placeholder + '::text[])';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default in_operator;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Expose the read-query operator fragment registry.
|
|
4
|
+
*/
|
|
5
|
+
import all_operator from './all.js';
|
|
6
|
+
import eq_operator from './eq.js';
|
|
7
|
+
import gt_operator from './gt.js';
|
|
8
|
+
import gte_operator from './gte.js';
|
|
9
|
+
import in_operator from './in.js';
|
|
10
|
+
import lt_operator from './lt.js';
|
|
11
|
+
import lte_operator from './lte.js';
|
|
12
|
+
import ne_operator from './ne.js';
|
|
13
|
+
import nin_operator from './nin.js';
|
|
14
|
+
import regex_operator from './regex.js';
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
all_operator,
|
|
18
|
+
eq_operator,
|
|
19
|
+
gt_operator,
|
|
20
|
+
gte_operator,
|
|
21
|
+
in_operator,
|
|
22
|
+
lt_operator,
|
|
23
|
+
lte_operator,
|
|
24
|
+
ne_operator,
|
|
25
|
+
nin_operator,
|
|
26
|
+
regex_operator
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
all_operator,
|
|
31
|
+
eq_operator,
|
|
32
|
+
gt_operator,
|
|
33
|
+
gte_operator,
|
|
34
|
+
in_operator,
|
|
35
|
+
lt_operator,
|
|
36
|
+
lte_operator,
|
|
37
|
+
ne_operator,
|
|
38
|
+
nin_operator,
|
|
39
|
+
regex_operator
|
|
40
|
+
};
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile the SQL fragment for the $lt 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 lt_operator(sql_expression, comparison_value, parameter_state) {
|
|
10
|
+
if(is_nan(comparison_value)) {
|
|
11
|
+
throw new QueryError('Invalid value for $lt operator', {
|
|
12
|
+
operator: '$lt',
|
|
13
|
+
value: comparison_value
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const numeric_value = typeof comparison_value === 'bigint' ? comparison_value.toString() : Number(comparison_value);
|
|
18
|
+
const placeholder = bind_parameter(parameter_state, numeric_value);
|
|
19
|
+
|
|
20
|
+
return '(' + sql_expression + ')::numeric < ' + placeholder;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default lt_operator;
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile the SQL fragment for the $lte 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 lte_operator(sql_expression, comparison_value, parameter_state) {
|
|
10
|
+
if(is_nan(comparison_value)) {
|
|
11
|
+
throw new QueryError('Invalid value for $lte operator', {
|
|
12
|
+
operator: '$lte',
|
|
13
|
+
value: comparison_value
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const numeric_value = typeof comparison_value === 'bigint' ? comparison_value.toString() : Number(comparison_value);
|
|
18
|
+
const placeholder = bind_parameter(parameter_state, numeric_value);
|
|
19
|
+
|
|
20
|
+
return '(' + sql_expression + ')::numeric <= ' + placeholder;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default lte_operator;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile the SQL fragment for the $ne read-query operator.
|
|
4
|
+
*/
|
|
5
|
+
import {bind_parameter} from '#src/sql/parameter-binder.js';
|
|
6
|
+
|
|
7
|
+
function ne_operator(sql_expression, comparison_value, parameter_state) {
|
|
8
|
+
const placeholder = bind_parameter(parameter_state, String(comparison_value));
|
|
9
|
+
return sql_expression + ' != ' + placeholder;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default ne_operator;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile the SQL fragment for the $nin 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 nin_operator(sql_expression, comparison_value, parameter_state) {
|
|
9
|
+
const value_list = to_array(comparison_value);
|
|
10
|
+
const normalized_values = value_list.map(function map_value(current_value) {
|
|
11
|
+
return String(current_value);
|
|
12
|
+
});
|
|
13
|
+
const placeholder = bind_parameter(parameter_state, normalized_values);
|
|
14
|
+
|
|
15
|
+
return 'NOT (' + sql_expression + ' = ANY(' + placeholder + '::text[]))';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default nin_operator;
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile the SQL fragment for the $regex read-query operator.
|
|
4
|
+
*/
|
|
5
|
+
import {bind_parameter} from '#src/sql/parameter-binder.js';
|
|
6
|
+
|
|
7
|
+
function regex_operator(sql_expression, pattern_value, option_value, parameter_state) {
|
|
8
|
+
const regex_operator_value = option_value && option_value.indexOf('i') >= 0 ? '~*' : '~';
|
|
9
|
+
const placeholder = bind_parameter(parameter_state, String(pattern_value));
|
|
10
|
+
|
|
11
|
+
return sql_expression + ' ' + regex_operator_value + ' ' + placeholder;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default regex_operator;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile operator-style read-query objects into SQL predicates.
|
|
4
|
+
*/
|
|
5
|
+
import {
|
|
6
|
+
all_operator
|
|
7
|
+
} from '#src/sql/read/where/operators/index.js';
|
|
8
|
+
import contains_operator from '#src/sql/jsonb/read/operators/contains.js';
|
|
9
|
+
import has_all_keys_operator from '#src/sql/jsonb/read/operators/has-all-keys.js';
|
|
10
|
+
import has_any_keys_operator from '#src/sql/jsonb/read/operators/has-any-keys.js';
|
|
11
|
+
import has_key_operator from '#src/sql/jsonb/read/operators/has-key.js';
|
|
12
|
+
import jsonpath_exists_operator from '#src/sql/jsonb/read/operators/jsonpath-exists.js';
|
|
13
|
+
import jsonpath_match_operator from '#src/sql/jsonb/read/operators/jsonpath-match.js';
|
|
14
|
+
import size_operator from '#src/sql/jsonb/read/operators/size.js';
|
|
15
|
+
import {build_json_expression, build_text_expression, parse_path} from '#src/sql/jsonb/path-parser.js';
|
|
16
|
+
|
|
17
|
+
import QueryError from '#src/errors/query-error.js';
|
|
18
|
+
|
|
19
|
+
import {cast_operator_value} from '#src/sql/read/where/casting.js';
|
|
20
|
+
import {is_array_root} from '#src/sql/read/where/context.js';
|
|
21
|
+
import {compile_nested_array_operator} from '#src/sql/jsonb/read/elem-match.js';
|
|
22
|
+
import {compile_operator_entry_clauses} from '#src/sql/read/where/operator-entries.js';
|
|
23
|
+
import {compile_text_operator} from '#src/sql/read/where/text-operators.js';
|
|
24
|
+
|
|
25
|
+
import {build_nested_object} from '#src/utils/object-path.js';
|
|
26
|
+
|
|
27
|
+
function compile_operator_object(path_value, operator_definition, compile_context, parameter_state) {
|
|
28
|
+
const path_info = parse_path(path_value);
|
|
29
|
+
const regex_options = operator_definition.$options || '';
|
|
30
|
+
const has_array_path = is_array_root(compile_context, path_info.root_path) && path_info.child_segments.length > 0;
|
|
31
|
+
|
|
32
|
+
const clause_list = compile_operator_entry_clauses(operator_definition, function (operator_name, operator_value) {
|
|
33
|
+
if(has_array_path) {
|
|
34
|
+
return compile_nested_array_operator(
|
|
35
|
+
operator_name,
|
|
36
|
+
operator_value,
|
|
37
|
+
regex_options,
|
|
38
|
+
path_info,
|
|
39
|
+
compile_context.data_column_reference,
|
|
40
|
+
parameter_state
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return compile_standard_operator({
|
|
45
|
+
name: operator_name,
|
|
46
|
+
value: operator_value,
|
|
47
|
+
regex_options,
|
|
48
|
+
path_value,
|
|
49
|
+
compile_context,
|
|
50
|
+
parameter_state
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return clause_list.join(' AND ');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function compile_standard_operator(context) {
|
|
58
|
+
const {
|
|
59
|
+
name,
|
|
60
|
+
value,
|
|
61
|
+
regex_options,
|
|
62
|
+
path_value,
|
|
63
|
+
compile_context,
|
|
64
|
+
parameter_state
|
|
65
|
+
} = context;
|
|
66
|
+
|
|
67
|
+
const data_column_reference = compile_context.data_column_reference;
|
|
68
|
+
const text_expression = build_text_expression(data_column_reference, path_value);
|
|
69
|
+
const json_expression = build_json_expression(data_column_reference, path_value);
|
|
70
|
+
const casted_value = cast_operator_value(path_value, name, value, compile_context);
|
|
71
|
+
const text_operator_clause = compile_text_operator({
|
|
72
|
+
name,
|
|
73
|
+
value,
|
|
74
|
+
casted_value,
|
|
75
|
+
regex_options,
|
|
76
|
+
text_expression,
|
|
77
|
+
parameter_state,
|
|
78
|
+
error_message: 'Unsupported operator'
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if(text_operator_clause) {
|
|
82
|
+
return text_operator_clause;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if(name === '$contains') {
|
|
86
|
+
const nested_object = build_nested_object(path_value, value);
|
|
87
|
+
return contains_operator(data_column_reference, nested_object, parameter_state);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if(name === '$has_key') {
|
|
91
|
+
return has_key_operator(json_expression, value, parameter_state);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if(name === '$has_any_keys') {
|
|
95
|
+
return has_any_keys_operator(json_expression, value, parameter_state);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if(name === '$has_all_keys') {
|
|
99
|
+
return has_all_keys_operator(json_expression, value, parameter_state);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if(name === '$json_path_exists') {
|
|
103
|
+
return jsonpath_exists_operator(json_expression, value, parameter_state);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if(name === '$json_path_match') {
|
|
107
|
+
return jsonpath_match_operator(json_expression, value, parameter_state);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if(name === '$all') {
|
|
111
|
+
return all_operator(json_expression, casted_value, parameter_state);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if(name === '$size') {
|
|
115
|
+
return size_operator(json_expression, value, parameter_state);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
throw new QueryError('Unsupported operator: ' + name, {
|
|
119
|
+
operator: name,
|
|
120
|
+
path: path_value
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export {
|
|
125
|
+
compile_operator_object
|
|
126
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MODULE RESPONSIBILITY
|
|
3
|
+
* Compile scalar and text read-query operators into SQL predicates.
|
|
4
|
+
*/
|
|
5
|
+
import {
|
|
6
|
+
eq_operator,
|
|
7
|
+
gt_operator,
|
|
8
|
+
gte_operator,
|
|
9
|
+
in_operator,
|
|
10
|
+
lt_operator,
|
|
11
|
+
lte_operator,
|
|
12
|
+
ne_operator,
|
|
13
|
+
nin_operator,
|
|
14
|
+
regex_operator
|
|
15
|
+
} from '#src/sql/read/where/operators/index.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Compile one scalar comparison operator into a SQL predicate.
|
|
19
|
+
*
|
|
20
|
+
* @param {object} operator_context
|
|
21
|
+
* @param {string} operator_context.name
|
|
22
|
+
* @param {*} operator_context.value
|
|
23
|
+
* @param {*} [operator_context.casted_value]
|
|
24
|
+
* @param {*} operator_context.regex_options
|
|
25
|
+
* @param {string} operator_context.text_expression
|
|
26
|
+
* @param {object} operator_context.parameter_state
|
|
27
|
+
* @param {string} operator_context.error_message
|
|
28
|
+
* @returns {string|null}
|
|
29
|
+
* @throws {QueryError}
|
|
30
|
+
*/
|
|
31
|
+
function compile_text_operator(operator_context) {
|
|
32
|
+
const {
|
|
33
|
+
name,
|
|
34
|
+
value,
|
|
35
|
+
casted_value = value,
|
|
36
|
+
regex_options,
|
|
37
|
+
text_expression,
|
|
38
|
+
parameter_state,
|
|
39
|
+
error_message
|
|
40
|
+
} = operator_context;
|
|
41
|
+
|
|
42
|
+
if(name === '$eq') {
|
|
43
|
+
return eq_operator(text_expression, casted_value, parameter_state);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if(name === '$ne') {
|
|
47
|
+
return ne_operator(text_expression, casted_value, parameter_state);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if(name === '$gt') {
|
|
51
|
+
return gt_operator(text_expression, casted_value, parameter_state);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if(name === '$gte') {
|
|
55
|
+
return gte_operator(text_expression, casted_value, parameter_state);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if(name === '$lt') {
|
|
59
|
+
return lt_operator(text_expression, casted_value, parameter_state);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if(name === '$lte') {
|
|
63
|
+
return lte_operator(text_expression, casted_value, parameter_state);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if(name === '$in') {
|
|
67
|
+
return in_operator(text_expression, casted_value, parameter_state);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if(name === '$nin') {
|
|
71
|
+
return nin_operator(text_expression, casted_value, parameter_state);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if(name === '$regex') {
|
|
75
|
+
return regex_operator(text_expression, value, regex_options, parameter_state);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
compile_text_operator
|
|
83
|
+
};
|