proto.io 0.0.167 → 0.0.169
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/dist/adapters/file/database.d.ts +2 -2
- package/dist/adapters/file/database.js +1 -1
- package/dist/adapters/file/database.mjs +1 -1
- package/dist/adapters/file/filesystem.d.ts +2 -2
- package/dist/adapters/file/google-cloud-storage.d.ts +2 -2
- package/dist/adapters/storage/progres.d.ts +7 -2
- package/dist/adapters/storage/progres.js +324 -353
- package/dist/adapters/storage/progres.js.map +1 -1
- package/dist/adapters/storage/progres.mjs +324 -353
- package/dist/adapters/storage/progres.mjs.map +1 -1
- package/dist/client.d.ts +3 -3
- package/dist/client.js +1 -1
- package/dist/client.mjs +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/index.mjs +4 -4
- package/dist/internals/{index-BejQNqvC.mjs → index-B1wqSio6.mjs} +1 -2
- package/dist/internals/index-B1wqSio6.mjs.map +1 -0
- package/dist/internals/{index-rkqvel7o.d.ts → index-B5u7VXjz.d.ts} +2 -2
- package/dist/internals/index-B5u7VXjz.d.ts.map +1 -0
- package/dist/internals/{index-y8EePsDY.d.ts → index-BB2vDnq0.d.ts} +2 -2
- package/dist/internals/index-BB2vDnq0.d.ts.map +1 -0
- package/dist/internals/{index-CyzpkgJB.js → index-BJP46VGq.js} +2 -2
- package/dist/internals/index-BJP46VGq.js.map +1 -0
- package/dist/internals/{index-CSNRyhjB.js → index-CzfsyXvb.js} +1 -2
- package/dist/internals/index-CzfsyXvb.js.map +1 -0
- package/dist/internals/{index-Dyfia5Om.mjs → index-D0hHgn2P.mjs} +2 -2
- package/dist/internals/index-D0hHgn2P.mjs.map +1 -0
- package/dist/internals/{index-BQggoDNX.d.ts → index-D_GYwO8X.d.ts} +2 -2
- package/dist/internals/index-D_GYwO8X.d.ts.map +1 -0
- package/dist/internals/{random-DrURPPxr.mjs → random-BCpwYpyw.mjs} +2 -2
- package/dist/internals/{random-DrURPPxr.mjs.map → random-BCpwYpyw.mjs.map} +1 -1
- package/dist/internals/{random-q0PeamQE.js → random-Dytum6Nh.js} +2 -2
- package/dist/internals/{random-q0PeamQE.js.map → random-Dytum6Nh.js.map} +1 -1
- package/package.json +1 -1
- package/dist/internals/index-BQggoDNX.d.ts.map +0 -1
- package/dist/internals/index-BejQNqvC.mjs.map +0 -1
- package/dist/internals/index-CSNRyhjB.js.map +0 -1
- package/dist/internals/index-CyzpkgJB.js.map +0 -1
- package/dist/internals/index-Dyfia5Om.mjs.map +0 -1
- package/dist/internals/index-rkqvel7o.d.ts.map +0 -1
- package/dist/internals/index-y8EePsDY.d.ts.map +0 -1
|
@@ -9,9 +9,9 @@ var QueryStream = require('pg-query-stream');
|
|
|
9
9
|
var utilsJs = require('@o2ter/utils-js');
|
|
10
10
|
var Decimal = require('decimal.js');
|
|
11
11
|
var utils = require('pg/lib/utils');
|
|
12
|
-
var index$1 = require('../../internals/index-
|
|
12
|
+
var index$1 = require('../../internals/index-CzfsyXvb.js');
|
|
13
13
|
require('@o2ter/crypto-js');
|
|
14
|
-
var random$1 = require('../../internals/random-
|
|
14
|
+
var random$1 = require('../../internals/random-Dytum6Nh.js');
|
|
15
15
|
var _private = require('../../internals/private-CSB1Ep4g.js');
|
|
16
16
|
|
|
17
17
|
//
|
|
@@ -291,7 +291,7 @@ class QueryCompiler {
|
|
|
291
291
|
const _stages = _.mapValues(context.populates, (populate) => this.dialect.encodePopulate(this, populate));
|
|
292
292
|
const stages = _.fromPairs(_.flatMap(_.values(_stages), (p) => _.toPairs(p)));
|
|
293
293
|
const fetchName = `_fetch_$${query.className.toLowerCase()}`;
|
|
294
|
-
const parent = { className: query.className, name: fetchName };
|
|
294
|
+
const parent = { className: query.className, name: fetchName, populates: context.populates };
|
|
295
295
|
const baseFilter = this._encodeFilter(parent, query.filter);
|
|
296
296
|
const populates = this._selectPopulateMap(context, query.className, fetchName);
|
|
297
297
|
const joins = _.compact(_.map(populates, ({ join }) => join));
|
|
@@ -799,36 +799,8 @@ class SqlStorage {
|
|
|
799
799
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
800
800
|
// THE SOFTWARE.
|
|
801
801
|
//
|
|
802
|
-
const foreignFieldType = (schema, className, path) => {
|
|
803
|
-
let fields = schema[className].fields;
|
|
804
|
-
let last;
|
|
805
|
-
let result = false;
|
|
806
|
-
for (const key of _.toPath(path)) {
|
|
807
|
-
const dataType = fields[key];
|
|
808
|
-
if (_.isNil(dataType))
|
|
809
|
-
return;
|
|
810
|
-
if (index.isPrimitive(dataType) || index.isVector(dataType))
|
|
811
|
-
return;
|
|
812
|
-
if (index.isShape(dataType)) {
|
|
813
|
-
fields = dataType.shape;
|
|
814
|
-
continue;
|
|
815
|
-
}
|
|
816
|
-
if (_.isNil(schema[dataType.target]))
|
|
817
|
-
return;
|
|
818
|
-
if (dataType.type === 'relation')
|
|
819
|
-
result = true;
|
|
820
|
-
fields = schema[dataType.target].fields;
|
|
821
|
-
last = dataType;
|
|
822
|
-
}
|
|
823
|
-
if (!last)
|
|
824
|
-
return;
|
|
825
|
-
return {
|
|
826
|
-
target: last.target,
|
|
827
|
-
type: result ? 'relation' : last.type,
|
|
828
|
-
};
|
|
829
|
-
};
|
|
830
802
|
const _fetchElement = (parent, colname, subpath, dataType) => {
|
|
831
|
-
const element = sql `${{ identifier: parent.name }}.${{ identifier: parent.name.startsWith('
|
|
803
|
+
const element = sql `${{ identifier: parent.name }}.${{ identifier: parent.name.startsWith('_doller_expr_$') ? '$' : colname }}`;
|
|
832
804
|
if (!parent.className) {
|
|
833
805
|
if (colname !== '$') {
|
|
834
806
|
return {
|
|
@@ -858,7 +830,7 @@ const _fetchElement = (parent, colname, subpath, dataType) => {
|
|
|
858
830
|
};
|
|
859
831
|
}
|
|
860
832
|
}
|
|
861
|
-
if (parent.name.startsWith('
|
|
833
|
+
if (parent.name.startsWith('_doller_expr_$') && colname !== '$') {
|
|
862
834
|
return {
|
|
863
835
|
element: sql `jsonb_extract_path(${element}, ${{ quote: colname.startsWith('$') ? `$${colname}` : colname }})`,
|
|
864
836
|
json: true,
|
|
@@ -890,36 +862,34 @@ const resolvePaths = (compiler, className, paths) => {
|
|
|
890
862
|
}
|
|
891
863
|
return { dataType, colname, subpath };
|
|
892
864
|
};
|
|
865
|
+
const _resolvePopulate = (path, populates) => {
|
|
866
|
+
let [colname, ...subpath] = path;
|
|
867
|
+
while (populates && !_.isEmpty(subpath)) {
|
|
868
|
+
const populate = populates[colname];
|
|
869
|
+
if (populate)
|
|
870
|
+
return _resolvePopulate(subpath, populate.populates);
|
|
871
|
+
const [key, ...remain] = subpath;
|
|
872
|
+
colname = `${colname}.${key}`;
|
|
873
|
+
subpath = remain;
|
|
874
|
+
}
|
|
875
|
+
return populates?.[colname];
|
|
876
|
+
};
|
|
893
877
|
const fetchElement = (compiler, parent, field) => {
|
|
894
878
|
if (parent.className) {
|
|
895
879
|
const { dataType, colname, subpath } = resolvePaths(compiler, parent.className, _.toPath(field));
|
|
896
880
|
const { element, json } = _fetchElement(parent, colname, subpath, dataType);
|
|
897
|
-
if (!_.isEmpty(subpath)) {
|
|
898
|
-
const foreignField = foreignFieldType(compiler.schema, parent.className, field);
|
|
899
|
-
if (foreignField) {
|
|
900
|
-
return {
|
|
901
|
-
element,
|
|
902
|
-
dataType: foreignField,
|
|
903
|
-
relation: {
|
|
904
|
-
target: foreignField.target,
|
|
905
|
-
sql: (callback) => sql `SELECT
|
|
906
|
-
${callback(sql `UNNEST`)}
|
|
907
|
-
FROM UNNEST(${{ identifier: parent.name }}.${{ identifier: colname }})`,
|
|
908
|
-
},
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
881
|
if (index.isPointer(dataType))
|
|
913
882
|
return { element: sql `${{ identifier: parent.name }}.${{ identifier: `${colname}._id` }}`, dataType };
|
|
883
|
+
const populate = index.isRelation(dataType) && _resolvePopulate(_.toPath(colname), parent.populates);
|
|
884
|
+
if (!populate)
|
|
885
|
+
return { element, dataType: json ? null : dataType };
|
|
914
886
|
return {
|
|
915
887
|
element,
|
|
916
888
|
dataType: json ? null : dataType,
|
|
917
|
-
relation:
|
|
889
|
+
relation: {
|
|
918
890
|
target: dataType.target,
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
FROM ${json ? sql `jsonb_array_elements(${element})` : sql `UNNEST(${element})`}`,
|
|
922
|
-
} : null,
|
|
891
|
+
populate,
|
|
892
|
+
},
|
|
923
893
|
};
|
|
924
894
|
}
|
|
925
895
|
const [colname, ...subpath] = _.toPath(field);
|
|
@@ -1878,6 +1848,231 @@ const encodeQueryExpression = (compiler, parent, expr) => {
|
|
|
1878
1848
|
return encodeBooleanExpression(compiler, parent, expr);
|
|
1879
1849
|
};
|
|
1880
1850
|
|
|
1851
|
+
//
|
|
1852
|
+
// populate.ts
|
|
1853
|
+
//
|
|
1854
|
+
// The MIT License
|
|
1855
|
+
// Copyright (c) 2021 - 2024 O2ter Limited. All rights reserved.
|
|
1856
|
+
//
|
|
1857
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1858
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
1859
|
+
// in the Software without restriction, including without limitation the rights
|
|
1860
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1861
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
1862
|
+
// furnished to do so, subject to the following conditions:
|
|
1863
|
+
//
|
|
1864
|
+
// The above copyright notice and this permission notice shall be included in
|
|
1865
|
+
// all copies or substantial portions of the Software.
|
|
1866
|
+
//
|
|
1867
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1868
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1869
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1870
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1871
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1872
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
1873
|
+
// THE SOFTWARE.
|
|
1874
|
+
//
|
|
1875
|
+
const resolveSubpaths = (compiler, populate) => {
|
|
1876
|
+
const subpaths = [];
|
|
1877
|
+
for (const [name, type] of _.toPairs(populate.includes)) {
|
|
1878
|
+
if (index.isPointer(type)) {
|
|
1879
|
+
subpaths.push(..._.map(resolveSubpaths(compiler, populate.populates[name]), ({ path, type }) => ({
|
|
1880
|
+
path: `${name}.${path}`,
|
|
1881
|
+
type,
|
|
1882
|
+
})));
|
|
1883
|
+
}
|
|
1884
|
+
else {
|
|
1885
|
+
subpaths.push({
|
|
1886
|
+
path: name,
|
|
1887
|
+
type,
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
return subpaths;
|
|
1892
|
+
};
|
|
1893
|
+
const _isPointer = (schema, className, path) => {
|
|
1894
|
+
let fields = schema[className].fields;
|
|
1895
|
+
let last;
|
|
1896
|
+
for (const key of _.toPath(path)) {
|
|
1897
|
+
const dataType = fields[key];
|
|
1898
|
+
if (_.isNil(dataType))
|
|
1899
|
+
throw Error(`Invalid path: ${path}`);
|
|
1900
|
+
if (index.isPrimitive(dataType) || index.isVector(dataType))
|
|
1901
|
+
throw Error(`Invalid path: ${path}`);
|
|
1902
|
+
if (index.isShape(dataType)) {
|
|
1903
|
+
fields = dataType.shape;
|
|
1904
|
+
continue;
|
|
1905
|
+
}
|
|
1906
|
+
if (dataType.type !== 'pointer')
|
|
1907
|
+
return false;
|
|
1908
|
+
if (_.isNil(schema[dataType.target]))
|
|
1909
|
+
throw Error(`Invalid path: ${path}`);
|
|
1910
|
+
fields = schema[dataType.target].fields;
|
|
1911
|
+
last = dataType;
|
|
1912
|
+
}
|
|
1913
|
+
return last?.type === 'pointer';
|
|
1914
|
+
};
|
|
1915
|
+
const _selectRelationPopulate = (compiler, parent, populate, field, encode) => {
|
|
1916
|
+
const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
|
|
1917
|
+
const _foreign = (field) => sql `${{ identifier: populate.name }}.${{ identifier: field }}`;
|
|
1918
|
+
const subpaths = resolveSubpaths(compiler, populate);
|
|
1919
|
+
let cond;
|
|
1920
|
+
if (_.isNil(populate.foreignField)) {
|
|
1921
|
+
cond = sql `${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ANY(${_local(field)})`;
|
|
1922
|
+
}
|
|
1923
|
+
else if (_isPointer(compiler.schema, populate.className, populate.foreignField)) {
|
|
1924
|
+
cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(populate.colname)}`;
|
|
1925
|
+
}
|
|
1926
|
+
else {
|
|
1927
|
+
cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(populate.colname)})`;
|
|
1928
|
+
}
|
|
1929
|
+
return sql `
|
|
1930
|
+
SELECT ${_.compact(_.flatMap(subpaths, ({ path, type }) => [
|
|
1931
|
+
encode && _encodePopulateInclude(populate.name, path, type),
|
|
1932
|
+
!encode && sql `${{ identifier: populate.name }}.${{ identifier: path }}`,
|
|
1933
|
+
!encode && index.isRelation(type) && sql `${{ identifier: populate.name }}.${{ identifier: `$${path}` }}`,
|
|
1934
|
+
]))}
|
|
1935
|
+
FROM ${{ identifier: populate.name }} WHERE ${cond}
|
|
1936
|
+
${!_.isEmpty(populate.sort) ? sql `ORDER BY ${compiler._encodeSort(populate.sort, { className: populate.className, name: populate.name })}` : sql ``}
|
|
1937
|
+
${populate.limit ? sql `LIMIT ${{ literal: `${populate.limit}` }}` : sql ``}
|
|
1938
|
+
${populate.skip ? sql `OFFSET ${{ literal: `${populate.skip}` }}` : sql ``}
|
|
1939
|
+
${compiler.selectLock ? compiler.isUpdate ? sql `FOR UPDATE NOWAIT` : sql `FOR SHARE NOWAIT` : sql ``}
|
|
1940
|
+
`;
|
|
1941
|
+
};
|
|
1942
|
+
const selectPopulate = (compiler, parent, populate, field) => {
|
|
1943
|
+
if (populate.type === 'relation') {
|
|
1944
|
+
return {
|
|
1945
|
+
columns: [
|
|
1946
|
+
sql `
|
|
1947
|
+
ARRAY(
|
|
1948
|
+
SELECT to_jsonb(${{ identifier: populate.name }}) FROM (
|
|
1949
|
+
${_selectRelationPopulate(compiler, parent, populate, field, true)}
|
|
1950
|
+
) ${{ identifier: populate.name }}
|
|
1951
|
+
) AS ${{ identifier: field }}
|
|
1952
|
+
`,
|
|
1953
|
+
sql `${{ identifier: parent.name }}.${{ identifier: field }} AS ${{ identifier: `$${field}` }}`
|
|
1954
|
+
],
|
|
1955
|
+
};
|
|
1956
|
+
}
|
|
1957
|
+
const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
|
|
1958
|
+
const _foreign = (field) => sql `${{ identifier: populate.name }}.${{ identifier: field }}`;
|
|
1959
|
+
const subpaths = resolveSubpaths(compiler, populate);
|
|
1960
|
+
return {
|
|
1961
|
+
columns: _.compact(_.flatMap(subpaths, ({ path, type }) => [
|
|
1962
|
+
sql `${{ identifier: populate.name }}.${{ identifier: path }} AS ${{ identifier: `${field}.${path}` }}`,
|
|
1963
|
+
index.isRelation(type) && sql `${{ identifier: populate.name }}.${{ identifier: `$${path}` }} AS ${{ identifier: `$${field}.${path}` }}`,
|
|
1964
|
+
])),
|
|
1965
|
+
join: sql `
|
|
1966
|
+
LEFT JOIN ${{ identifier: populate.name }}
|
|
1967
|
+
ON ${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ${_local(field)}
|
|
1968
|
+
`,
|
|
1969
|
+
};
|
|
1970
|
+
};
|
|
1971
|
+
const encodeRemix = (parent, remix) => sql `${remix?.className === parent.className ? sql `
|
|
1972
|
+
(SELECT * FROM ${{ identifier: remix.name }} UNION SELECT * FROM ${{ identifier: parent.className }})
|
|
1973
|
+
` : { identifier: parent.className }}`;
|
|
1974
|
+
const encodeForeignField = (compiler, parent, foreignField, remix) => {
|
|
1975
|
+
const { paths: [colname, ...subpath], dataType } = random$1.resolveColumn(compiler.schema, parent.className, foreignField);
|
|
1976
|
+
const tempName = `_populate_$${compiler.nextIdx()}`;
|
|
1977
|
+
const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
|
|
1978
|
+
const _foreign = (field) => sql `${{ identifier: tempName }}.${{ identifier: field }}`;
|
|
1979
|
+
if (_.isEmpty(subpath) && index.isRelation(dataType) && dataType.foreignField) {
|
|
1980
|
+
const { joins, field, rows, array } = encodeForeignField(compiler, { className: dataType.target, name: tempName }, dataType.foreignField, remix);
|
|
1981
|
+
return {
|
|
1982
|
+
joins: [],
|
|
1983
|
+
field: sql `(
|
|
1984
|
+
SELECT ${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`}
|
|
1985
|
+
FROM ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
|
|
1986
|
+
${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
|
|
1987
|
+
WHERE ${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${array || rows ? sql `ANY(${field})` : field}
|
|
1988
|
+
)`,
|
|
1989
|
+
array: false,
|
|
1990
|
+
rows: true,
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1993
|
+
if (_.isEmpty(subpath)) {
|
|
1994
|
+
return {
|
|
1995
|
+
joins: [],
|
|
1996
|
+
field: sql `${{ identifier: parent.name }}.${{ identifier: foreignField }}`,
|
|
1997
|
+
array: index.isRelation(dataType),
|
|
1998
|
+
rows: false,
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
if (!index.isPointer(dataType) && !index.isRelation(dataType))
|
|
2002
|
+
throw Error(`Invalid path: ${foreignField}`);
|
|
2003
|
+
const { joins, field, rows, array } = encodeForeignField(compiler, { className: dataType.target, name: tempName }, subpath.join('.'), remix);
|
|
2004
|
+
const cond = [];
|
|
2005
|
+
if (compiler.extraFilter) {
|
|
2006
|
+
const filter = compiler.extraFilter(dataType.target);
|
|
2007
|
+
cond.push(compiler._encodeFilter({ className: dataType.target, name: tempName }, filter));
|
|
2008
|
+
}
|
|
2009
|
+
if (index.isPointer(dataType)) {
|
|
2010
|
+
cond.push(sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ${_local(colname)}`);
|
|
2011
|
+
return {
|
|
2012
|
+
joins: [sql `
|
|
2013
|
+
LEFT JOIN ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
|
|
2014
|
+
ON ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
|
|
2015
|
+
`, ...joins],
|
|
2016
|
+
field,
|
|
2017
|
+
array,
|
|
2018
|
+
rows,
|
|
2019
|
+
};
|
|
2020
|
+
}
|
|
2021
|
+
if (_.isNil(dataType.foreignField)) {
|
|
2022
|
+
cond.push(sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ANY(${_local(colname)})`);
|
|
2023
|
+
}
|
|
2024
|
+
else if (_isPointer(compiler.schema, dataType.target, dataType.foreignField)) {
|
|
2025
|
+
cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(dataType.foreignField)}`);
|
|
2026
|
+
}
|
|
2027
|
+
else {
|
|
2028
|
+
cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(dataType.foreignField)})`);
|
|
2029
|
+
}
|
|
2030
|
+
return {
|
|
2031
|
+
joins: [],
|
|
2032
|
+
field: sql `(
|
|
2033
|
+
SELECT ${array ? sql `UNNEST(${field})` : field}
|
|
2034
|
+
FROM ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
|
|
2035
|
+
${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
|
|
2036
|
+
WHERE ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
|
|
2037
|
+
)`,
|
|
2038
|
+
array: false,
|
|
2039
|
+
rows: true,
|
|
2040
|
+
};
|
|
2041
|
+
};
|
|
2042
|
+
const encodePopulate = (compiler, parent, remix) => {
|
|
2043
|
+
const _filter = _.compact([
|
|
2044
|
+
parent.filter && compiler._encodeFilter(parent, parent.filter),
|
|
2045
|
+
compiler.extraFilter && compiler._encodeFilter(parent, compiler.extraFilter(parent.className)),
|
|
2046
|
+
]);
|
|
2047
|
+
const _populates = _.map(parent.populates, (populate, field) => selectPopulate(compiler, parent, populate, field));
|
|
2048
|
+
const _joins = _.compact(_.map(_populates, ({ join }) => join));
|
|
2049
|
+
const _includes = _.pickBy(parent.includes, v => index.isPrimitive(v));
|
|
2050
|
+
const { joins: _joins2 = [], field: _foreignField = undefined, rows = false, } = parent.foreignField ? encodeForeignField(compiler, {
|
|
2051
|
+
className: parent.className,
|
|
2052
|
+
name: parent.name,
|
|
2053
|
+
}, parent.foreignField, remix) : {};
|
|
2054
|
+
return _.reduce(parent.populates, (acc, populate) => ({
|
|
2055
|
+
...encodePopulate(compiler, populate, remix),
|
|
2056
|
+
...acc,
|
|
2057
|
+
}), {
|
|
2058
|
+
[parent.name]: sql `
|
|
2059
|
+
SELECT * FROM (
|
|
2060
|
+
SELECT
|
|
2061
|
+
${{
|
|
2062
|
+
literal: [
|
|
2063
|
+
..._.map(_.keys(_includes), colname => sql `${{ identifier: parent.name }}.${{ identifier: colname }}`),
|
|
2064
|
+
..._.flatMap(_populates, ({ columns: column }) => column),
|
|
2065
|
+
..._foreignField ? [sql `${rows ? sql `ARRAY(${_foreignField})` : _foreignField} AS ${{ identifier: parent.colname }}`] : [],
|
|
2066
|
+
], separator: ',\n'
|
|
2067
|
+
}}
|
|
2068
|
+
FROM ${encodeRemix(parent, remix)} AS ${{ identifier: parent.name }}
|
|
2069
|
+
${!_.isEmpty(_joins) || !_.isEmpty(_joins2) ? { literal: [..._joins, ..._joins2], separator: '\n' } : sql ``}
|
|
2070
|
+
) AS ${{ identifier: parent.name }}
|
|
2071
|
+
${!_.isEmpty(_filter) ? sql `WHERE ${{ literal: _.map(_.compact(_filter), x => sql `(${x})`), separator: ' AND ' }}` : sql ``}
|
|
2072
|
+
`,
|
|
2073
|
+
});
|
|
2074
|
+
};
|
|
2075
|
+
|
|
1881
2076
|
//
|
|
1882
2077
|
// selectors.ts
|
|
1883
2078
|
//
|
|
@@ -1934,12 +2129,12 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
1934
2129
|
case '$lt':
|
|
1935
2130
|
case '$lte':
|
|
1936
2131
|
{
|
|
1937
|
-
const
|
|
2132
|
+
const op = {
|
|
1938
2133
|
'$gt': '>',
|
|
1939
2134
|
'$gte': '>=',
|
|
1940
2135
|
'$lt': '<',
|
|
1941
2136
|
'$lte': '<=',
|
|
1942
|
-
};
|
|
2137
|
+
}[expr.type];
|
|
1943
2138
|
if (_.isRegExp(expr.value) || expr.value instanceof index$1.QuerySelector || expr.value instanceof index$1.FieldSelectorExpression)
|
|
1944
2139
|
break;
|
|
1945
2140
|
if (dataType && index.isPrimitive(dataType)) {
|
|
@@ -1947,46 +2142,47 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
1947
2142
|
case 'boolean':
|
|
1948
2143
|
if (!_.isBoolean(expr.value))
|
|
1949
2144
|
break;
|
|
1950
|
-
return sql `${element} ${{ literal:
|
|
2145
|
+
return sql `${element} ${{ literal: op }} ${encodeValue(expr.value)}`;
|
|
1951
2146
|
case 'number':
|
|
1952
2147
|
case 'decimal':
|
|
1953
2148
|
if (!(expr.value instanceof Decimal) && !_.isNumber(expr.value))
|
|
1954
2149
|
break;
|
|
1955
|
-
return sql `${element} ${{ literal:
|
|
2150
|
+
return sql `${element} ${{ literal: op }} ${encodeValue(expr.value)}`;
|
|
1956
2151
|
case 'string':
|
|
1957
2152
|
if (!_.isString(expr.value))
|
|
1958
2153
|
break;
|
|
1959
|
-
return sql `${element} ${{ literal:
|
|
2154
|
+
return sql `${element} ${{ literal: op }} ${encodeValue(expr.value)}`;
|
|
1960
2155
|
case 'date':
|
|
1961
2156
|
if (!_.isDate(expr.value))
|
|
1962
2157
|
break;
|
|
1963
|
-
return sql `${element} ${{ literal:
|
|
2158
|
+
return sql `${element} ${{ literal: op }} ${encodeValue(expr.value)}`;
|
|
1964
2159
|
}
|
|
1965
2160
|
}
|
|
1966
2161
|
else if (!_.isString(dataType) && dataType?.type === 'pointer' && expr.value instanceof index.TObject && expr.value.objectId) {
|
|
1967
|
-
return sql `${element} ${{ literal:
|
|
2162
|
+
return sql `${element} ${{ literal: op }} ${{ value: expr.value.objectId }}`;
|
|
1968
2163
|
}
|
|
1969
2164
|
else if (!dataType) {
|
|
1970
2165
|
if (expr.value instanceof Decimal || _.isNumber(expr.value)) {
|
|
1971
2166
|
return sql `(
|
|
1972
2167
|
jsonb_typeof(${element}) ${nullSafeEqual()} 'number'
|
|
1973
|
-
AND ${element}::NUMERIC ${{ literal:
|
|
2168
|
+
AND ${element}::NUMERIC ${{ literal: op }} ${{ value: expr.value instanceof Decimal ? expr.value.toNumber() : expr.value }}
|
|
1974
2169
|
) OR (
|
|
1975
2170
|
jsonb_typeof(${element} -> '$decimal') ${nullSafeEqual()} 'string'
|
|
1976
|
-
AND (${element} ->> '$decimal')::DECIMAL ${{ literal:
|
|
2171
|
+
AND (${element} ->> '$decimal')::DECIMAL ${{ literal: op }} ${{ value: expr.value instanceof Decimal ? expr.value.toString() : expr.value }}::DECIMAL
|
|
1977
2172
|
)`;
|
|
1978
2173
|
}
|
|
1979
2174
|
else if (_.isDate(expr.value)) {
|
|
1980
2175
|
return sql `(
|
|
1981
2176
|
jsonb_typeof(${element} -> '$date') ${nullSafeEqual()} 'string'
|
|
1982
|
-
AND ${element} ${{ literal:
|
|
2177
|
+
AND ${element} ${{ literal: op }} ${encodeValue(expr.value)}
|
|
1983
2178
|
)`;
|
|
1984
2179
|
}
|
|
1985
2180
|
else {
|
|
1986
|
-
return sql `${element} ${{ literal:
|
|
2181
|
+
return sql `${element} ${{ literal: op }} ${encodeValue(expr.value)}`;
|
|
1987
2182
|
}
|
|
1988
2183
|
}
|
|
1989
2184
|
}
|
|
2185
|
+
break;
|
|
1990
2186
|
case '$in':
|
|
1991
2187
|
{
|
|
1992
2188
|
if (!_.isArray(expr.value))
|
|
@@ -2022,6 +2218,7 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2022
2218
|
return sql `${element} IN (${_.map(values, x => encodeValue(x))})`;
|
|
2023
2219
|
}
|
|
2024
2220
|
}
|
|
2221
|
+
break;
|
|
2025
2222
|
case '$nin':
|
|
2026
2223
|
{
|
|
2027
2224
|
if (!_.isArray(expr.value))
|
|
@@ -2057,76 +2254,34 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2057
2254
|
return sql `${element} NOT IN (${_.map(values, x => encodeValue(x))})`;
|
|
2058
2255
|
}
|
|
2059
2256
|
}
|
|
2257
|
+
break;
|
|
2060
2258
|
case '$subset':
|
|
2061
|
-
{
|
|
2062
|
-
if (!_.isArray(expr.value))
|
|
2063
|
-
break;
|
|
2064
|
-
if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
|
|
2065
|
-
return sql `${element} <@ ${{ value: index._encodeValue(expr.value) }}`;
|
|
2066
|
-
}
|
|
2067
|
-
else if (relation) {
|
|
2068
|
-
if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
|
|
2069
|
-
break;
|
|
2070
|
-
return sql `ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) <@ ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
|
|
2071
|
-
}
|
|
2072
|
-
else if (!dataType) {
|
|
2073
|
-
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} <@ ${_encodeJsonValue(index._encodeValue(expr.value))}`;
|
|
2074
|
-
}
|
|
2075
|
-
}
|
|
2076
2259
|
case '$superset':
|
|
2077
|
-
{
|
|
2078
|
-
if (!_.isArray(expr.value))
|
|
2079
|
-
break;
|
|
2080
|
-
if (_.isEmpty(expr.value))
|
|
2081
|
-
return sql `true`;
|
|
2082
|
-
if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
|
|
2083
|
-
return sql `${element} @> ${{ value: index._encodeValue(expr.value) }}`;
|
|
2084
|
-
}
|
|
2085
|
-
else if (relation) {
|
|
2086
|
-
if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
|
|
2087
|
-
break;
|
|
2088
|
-
return sql `ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) @> ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
|
|
2089
|
-
}
|
|
2090
|
-
else if (!dataType) {
|
|
2091
|
-
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} @> ${_encodeJsonValue(index._encodeValue(expr.value))}`;
|
|
2092
|
-
}
|
|
2093
|
-
}
|
|
2094
|
-
case '$disjoint':
|
|
2095
|
-
{
|
|
2096
|
-
if (!_.isArray(expr.value))
|
|
2097
|
-
break;
|
|
2098
|
-
if (_.isEmpty(expr.value))
|
|
2099
|
-
return sql `true`;
|
|
2100
|
-
if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
|
|
2101
|
-
return sql `NOT ${element} && ${{ value: index._encodeValue(expr.value) }}`;
|
|
2102
|
-
}
|
|
2103
|
-
else if (relation) {
|
|
2104
|
-
if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
|
|
2105
|
-
break;
|
|
2106
|
-
return sql `NOT ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
|
|
2107
|
-
}
|
|
2108
|
-
else if (!dataType) {
|
|
2109
|
-
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND NOT ${element} && ${_encodeJsonValue(index._encodeValue(expr.value))}`;
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
2260
|
case '$intersect':
|
|
2113
2261
|
{
|
|
2262
|
+
const op = {
|
|
2263
|
+
'$subset': '<@',
|
|
2264
|
+
'$superset': '@>',
|
|
2265
|
+
'$intersect': '&&',
|
|
2266
|
+
}[expr.type];
|
|
2114
2267
|
if (!_.isArray(expr.value))
|
|
2115
2268
|
break;
|
|
2116
2269
|
if (_.isEmpty(expr.value))
|
|
2117
|
-
return sql `
|
|
2270
|
+
return sql `true`;
|
|
2118
2271
|
if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
|
|
2119
|
-
return sql `${element}
|
|
2272
|
+
return sql `${element} ${{ literal: op }} ${{ value: index._encodeValue(expr.value) }}`;
|
|
2120
2273
|
}
|
|
2121
|
-
|
|
2274
|
+
if (relation && parent.className) {
|
|
2122
2275
|
if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
|
|
2123
2276
|
break;
|
|
2124
|
-
|
|
2277
|
+
const populate = _selectRelationPopulate(compiler, { className: parent.className, name: parent.name }, relation.populate, `$${field}`, false);
|
|
2278
|
+
return sql `ARRAY(SELECT ${{ identifier: '_id' }} FROM (${populate})) ${{ literal: op }} ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
|
|
2125
2279
|
}
|
|
2126
|
-
|
|
2127
|
-
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element}
|
|
2280
|
+
if (!dataType) {
|
|
2281
|
+
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} ${{ literal: op }} ${_encodeJsonValue(index._encodeValue(expr.value))}`;
|
|
2128
2282
|
}
|
|
2129
2283
|
}
|
|
2284
|
+
break;
|
|
2130
2285
|
case '$not':
|
|
2131
2286
|
{
|
|
2132
2287
|
if (!(expr.value instanceof index$1.FieldSelectorExpression))
|
|
@@ -2139,7 +2294,7 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2139
2294
|
if (_.isString(expr.value)) {
|
|
2140
2295
|
return sql `${element} LIKE ${{ value: `%${expr.value.replace(/([\\_%])/g, '\\$1')}%` }}`;
|
|
2141
2296
|
}
|
|
2142
|
-
|
|
2297
|
+
if (_.isRegExp(expr.value)) {
|
|
2143
2298
|
if (expr.value.ignoreCase)
|
|
2144
2299
|
return sql `${element} ~* ${{ value: expr.value.source }}`;
|
|
2145
2300
|
return sql `${element} ~ ${{ value: expr.value.source }}`;
|
|
@@ -2149,13 +2304,14 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2149
2304
|
if (_.isString(expr.value)) {
|
|
2150
2305
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'string' AND (${element} #>> '{}') LIKE ${{ value: `%${expr.value.replace(/([\\_%])/g, '\\$1')}%` }}`;
|
|
2151
2306
|
}
|
|
2152
|
-
|
|
2307
|
+
if (_.isRegExp(expr.value)) {
|
|
2153
2308
|
if (expr.value.ignoreCase)
|
|
2154
2309
|
return sql `${element} ~* ${{ value: expr.value.source }}`;
|
|
2155
2310
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'string' AND (${element} #>> '{}') ~ ${{ value: expr.value.source }}`;
|
|
2156
2311
|
}
|
|
2157
2312
|
}
|
|
2158
2313
|
}
|
|
2314
|
+
break;
|
|
2159
2315
|
case '$starts':
|
|
2160
2316
|
{
|
|
2161
2317
|
if (!_.isString(expr.value))
|
|
@@ -2163,10 +2319,11 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2163
2319
|
if (dataType === 'string' || (!_.isString(dataType) && dataType?.type === 'string')) {
|
|
2164
2320
|
return sql `${element} LIKE ${{ value: `${expr.value.replace(/([\\_%])/g, '\\$1')}%` }}`;
|
|
2165
2321
|
}
|
|
2166
|
-
|
|
2322
|
+
if (!dataType) {
|
|
2167
2323
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'string' AND (${element} #>> '{}') LIKE ${{ value: `${expr.value.replace(/([\\_%])/g, '\\$1')}%` }}`;
|
|
2168
2324
|
}
|
|
2169
2325
|
}
|
|
2326
|
+
break;
|
|
2170
2327
|
case '$ends':
|
|
2171
2328
|
{
|
|
2172
2329
|
if (!_.isString(expr.value))
|
|
@@ -2174,10 +2331,11 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2174
2331
|
if (dataType === 'string' || (!_.isString(dataType) && dataType?.type === 'string')) {
|
|
2175
2332
|
return sql `${element} LIKE ${{ value: `%${expr.value.replace(/([\\_%])/g, '\\$1')}` }}`;
|
|
2176
2333
|
}
|
|
2177
|
-
|
|
2334
|
+
if (!dataType) {
|
|
2178
2335
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'string' AND (${element} #>> '{}') LIKE ${{ value: `%${expr.value.replace(/([\\_%])/g, '\\$1')}` }}`;
|
|
2179
2336
|
}
|
|
2180
2337
|
}
|
|
2338
|
+
break;
|
|
2181
2339
|
case '$size':
|
|
2182
2340
|
{
|
|
2183
2341
|
if (!_.isNumber(expr.value) || !_.isSafeInteger(expr.value))
|
|
@@ -2185,10 +2343,10 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2185
2343
|
if (dataType === 'string' || (!_.isString(dataType) && dataType?.type === 'string')) {
|
|
2186
2344
|
return sql `COALESCE(length(${element}), 0) = ${{ value: expr.value }}`;
|
|
2187
2345
|
}
|
|
2188
|
-
|
|
2346
|
+
if (dataType === 'array' || (!_.isString(dataType) && (dataType?.type === 'array' || dataType?.type === 'vector' || dataType?.type === 'relation'))) {
|
|
2189
2347
|
return sql `COALESCE(array_length(${element}, 1), 0) = ${{ value: expr.value }}`;
|
|
2190
2348
|
}
|
|
2191
|
-
|
|
2349
|
+
if (!dataType) {
|
|
2192
2350
|
return sql `(
|
|
2193
2351
|
CASE jsonb_typeof(${element})
|
|
2194
2352
|
WHEN 'array' THEN jsonb_array_length(${element}) = ${{ value: expr.value }}
|
|
@@ -2198,6 +2356,7 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2198
2356
|
)`;
|
|
2199
2357
|
}
|
|
2200
2358
|
}
|
|
2359
|
+
break;
|
|
2201
2360
|
case '$empty':
|
|
2202
2361
|
{
|
|
2203
2362
|
if (!_.isBoolean(expr.value))
|
|
@@ -2205,10 +2364,10 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2205
2364
|
if (dataType === 'string' || (!_.isString(dataType) && dataType?.type === 'string')) {
|
|
2206
2365
|
return sql `COALESCE(length(${element}), 0) ${{ literal: expr.value ? '=' : '<>' }} 0`;
|
|
2207
2366
|
}
|
|
2208
|
-
|
|
2367
|
+
if (dataType === 'array' || (!_.isString(dataType) && (dataType?.type === 'array' || dataType?.type === 'vector' || dataType?.type === 'relation'))) {
|
|
2209
2368
|
return sql `COALESCE(array_length(${element}, 1), 0) ${{ literal: expr.value ? '=' : '<>' }} 0`;
|
|
2210
2369
|
}
|
|
2211
|
-
|
|
2370
|
+
if (!dataType) {
|
|
2212
2371
|
return sql `(
|
|
2213
2372
|
CASE jsonb_typeof(${element})
|
|
2214
2373
|
WHEN 'array' THEN jsonb_array_length(${element}) ${{ literal: expr.value ? '=' : '<>' }} 0
|
|
@@ -2218,273 +2377,85 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2218
2377
|
)`;
|
|
2219
2378
|
}
|
|
2220
2379
|
}
|
|
2380
|
+
break;
|
|
2221
2381
|
case '$every':
|
|
2222
2382
|
{
|
|
2223
2383
|
if (!(expr.value instanceof index$1.QuerySelector))
|
|
2224
2384
|
break;
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2385
|
+
if (relation && parent.className) {
|
|
2386
|
+
const tempName = `_populate_expr_$${compiler.nextIdx()}`;
|
|
2387
|
+
const filter = compiler._encodeFilter({
|
|
2388
|
+
name: tempName,
|
|
2389
|
+
className: relation.target,
|
|
2390
|
+
populates: relation.populate.populates,
|
|
2391
|
+
}, expr.value);
|
|
2392
|
+
if (!filter)
|
|
2393
|
+
break;
|
|
2394
|
+
const populate = _selectRelationPopulate(compiler, { className: parent.className, name: parent.name }, relation.populate, `$${field}`, false);
|
|
2230
2395
|
return sql `NOT EXISTS(
|
|
2231
|
-
SELECT * FROM (${
|
|
2396
|
+
SELECT * FROM (${populate}) AS ${{ identifier: tempName }}
|
|
2232
2397
|
WHERE NOT (${filter})
|
|
2233
2398
|
)`;
|
|
2234
2399
|
}
|
|
2235
|
-
|
|
2400
|
+
const tempName = `_doller_expr_$${compiler.nextIdx()}`;
|
|
2401
|
+
const filter = compiler._encodeFilter({ name: tempName, className: relation?.target }, expr.value);
|
|
2402
|
+
if (!filter)
|
|
2403
|
+
break;
|
|
2404
|
+
if (dataType === 'array' || (!_.isString(dataType) && (dataType?.type === 'array' || dataType?.type === 'vector'))) {
|
|
2236
2405
|
return sql `NOT EXISTS(
|
|
2237
2406
|
SELECT * FROM (SELECT UNNEST AS "$" FROM UNNEST(${element})) AS ${{ identifier: tempName }}
|
|
2238
2407
|
WHERE NOT (${filter})
|
|
2239
2408
|
)`;
|
|
2240
2409
|
}
|
|
2241
|
-
|
|
2410
|
+
if (!dataType) {
|
|
2242
2411
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND NOT EXISTS(
|
|
2243
2412
|
SELECT * FROM (SELECT value AS "$" FROM jsonb_array_elements(${element})) AS ${{ identifier: tempName }}
|
|
2244
2413
|
WHERE NOT (${filter})
|
|
2245
2414
|
)`;
|
|
2246
2415
|
}
|
|
2247
2416
|
}
|
|
2417
|
+
break;
|
|
2248
2418
|
case '$some':
|
|
2249
2419
|
{
|
|
2250
2420
|
if (!(expr.value instanceof index$1.QuerySelector))
|
|
2251
2421
|
break;
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2422
|
+
if (relation && parent.className) {
|
|
2423
|
+
const tempName = `_populate_expr_$${compiler.nextIdx()}`;
|
|
2424
|
+
const filter = compiler._encodeFilter({
|
|
2425
|
+
name: tempName,
|
|
2426
|
+
className: relation.target,
|
|
2427
|
+
populates: relation.populate.populates,
|
|
2428
|
+
}, expr.value);
|
|
2429
|
+
if (!filter)
|
|
2430
|
+
break;
|
|
2431
|
+
const populate = _selectRelationPopulate(compiler, { className: parent.className, name: parent.name }, relation.populate, `$${field}`, false);
|
|
2257
2432
|
return sql `EXISTS(
|
|
2258
|
-
SELECT * FROM (${
|
|
2433
|
+
SELECT * FROM (${populate}) AS ${{ identifier: tempName }}
|
|
2259
2434
|
WHERE ${filter}
|
|
2260
2435
|
)`;
|
|
2261
2436
|
}
|
|
2262
|
-
|
|
2437
|
+
const tempName = `_doller_expr_$${compiler.nextIdx()}`;
|
|
2438
|
+
const filter = compiler._encodeFilter({ name: tempName, className: relation?.target }, expr.value);
|
|
2439
|
+
if (!filter)
|
|
2440
|
+
break;
|
|
2441
|
+
if (dataType === 'array' || (!_.isString(dataType) && (dataType?.type === 'array' || dataType?.type === 'vector'))) {
|
|
2263
2442
|
return sql `EXISTS(
|
|
2264
2443
|
SELECT * FROM (SELECT UNNEST AS "$" FROM UNNEST(${element})) AS ${{ identifier: tempName }}
|
|
2265
2444
|
WHERE ${filter}
|
|
2266
2445
|
)`;
|
|
2267
2446
|
}
|
|
2268
|
-
|
|
2447
|
+
if (!dataType) {
|
|
2269
2448
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND EXISTS(
|
|
2270
2449
|
SELECT * FROM (SELECT value AS "$" FROM jsonb_array_elements(${element})) AS ${{ identifier: tempName }}
|
|
2271
2450
|
WHERE ${filter}
|
|
2272
2451
|
)`;
|
|
2273
2452
|
}
|
|
2274
2453
|
}
|
|
2454
|
+
break;
|
|
2275
2455
|
}
|
|
2276
2456
|
throw Error('Invalid expression');
|
|
2277
2457
|
};
|
|
2278
2458
|
|
|
2279
|
-
//
|
|
2280
|
-
// populate.ts
|
|
2281
|
-
//
|
|
2282
|
-
// The MIT License
|
|
2283
|
-
// Copyright (c) 2021 - 2024 O2ter Limited. All rights reserved.
|
|
2284
|
-
//
|
|
2285
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2286
|
-
// of this software and associated documentation files (the "Software"), to deal
|
|
2287
|
-
// in the Software without restriction, including without limitation the rights
|
|
2288
|
-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
2289
|
-
// copies of the Software, and to permit persons to whom the Software is
|
|
2290
|
-
// furnished to do so, subject to the following conditions:
|
|
2291
|
-
//
|
|
2292
|
-
// The above copyright notice and this permission notice shall be included in
|
|
2293
|
-
// all copies or substantial portions of the Software.
|
|
2294
|
-
//
|
|
2295
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2296
|
-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2297
|
-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2298
|
-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
2299
|
-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
2300
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
2301
|
-
// THE SOFTWARE.
|
|
2302
|
-
//
|
|
2303
|
-
const resolveSubpaths = (compiler, populate) => {
|
|
2304
|
-
const subpaths = [];
|
|
2305
|
-
for (const [name, type] of _.toPairs(populate.includes)) {
|
|
2306
|
-
if (index.isPointer(type)) {
|
|
2307
|
-
subpaths.push(..._.map(resolveSubpaths(compiler, populate.populates[name]), ({ path, type }) => ({
|
|
2308
|
-
path: `${name}.${path}`,
|
|
2309
|
-
type,
|
|
2310
|
-
})));
|
|
2311
|
-
}
|
|
2312
|
-
else {
|
|
2313
|
-
subpaths.push({
|
|
2314
|
-
path: name,
|
|
2315
|
-
type,
|
|
2316
|
-
});
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
return subpaths;
|
|
2320
|
-
};
|
|
2321
|
-
const _isPointer = (schema, className, path) => {
|
|
2322
|
-
let fields = schema[className].fields;
|
|
2323
|
-
let last;
|
|
2324
|
-
for (const key of _.toPath(path)) {
|
|
2325
|
-
const dataType = fields[key];
|
|
2326
|
-
if (_.isNil(dataType))
|
|
2327
|
-
throw Error(`Invalid path: ${path}`);
|
|
2328
|
-
if (index.isPrimitive(dataType) || index.isVector(dataType))
|
|
2329
|
-
throw Error(`Invalid path: ${path}`);
|
|
2330
|
-
if (index.isShape(dataType)) {
|
|
2331
|
-
fields = dataType.shape;
|
|
2332
|
-
continue;
|
|
2333
|
-
}
|
|
2334
|
-
if (dataType.type !== 'pointer')
|
|
2335
|
-
return false;
|
|
2336
|
-
if (_.isNil(schema[dataType.target]))
|
|
2337
|
-
throw Error(`Invalid path: ${path}`);
|
|
2338
|
-
fields = schema[dataType.target].fields;
|
|
2339
|
-
last = dataType;
|
|
2340
|
-
}
|
|
2341
|
-
return last?.type === 'pointer';
|
|
2342
|
-
};
|
|
2343
|
-
const selectPopulate = (compiler, parent, populate, field) => {
|
|
2344
|
-
const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
|
|
2345
|
-
const _foreign = (field) => sql `${{ identifier: populate.name }}.${{ identifier: field }}`;
|
|
2346
|
-
const subpaths = resolveSubpaths(compiler, populate);
|
|
2347
|
-
const cond = [];
|
|
2348
|
-
if (compiler.extraFilter) {
|
|
2349
|
-
const filter = compiler.extraFilter(populate.className);
|
|
2350
|
-
cond.push(compiler._encodeFilter(populate, filter));
|
|
2351
|
-
}
|
|
2352
|
-
if (populate.type === 'pointer') {
|
|
2353
|
-
cond.push(sql `${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ${_local(field)}`);
|
|
2354
|
-
return {
|
|
2355
|
-
columns: _.map(subpaths, ({ path }) => sql `${{ identifier: populate.name }}.${{ identifier: path }} AS ${{ identifier: `${field}.${path}` }}`),
|
|
2356
|
-
join: sql `
|
|
2357
|
-
LEFT JOIN ${{ identifier: populate.name }}
|
|
2358
|
-
ON ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
|
|
2359
|
-
`,
|
|
2360
|
-
};
|
|
2361
|
-
}
|
|
2362
|
-
if (_.isNil(populate.foreignField)) {
|
|
2363
|
-
cond.push(sql `${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ANY(${_local(field)})`);
|
|
2364
|
-
}
|
|
2365
|
-
else if (_isPointer(compiler.schema, populate.className, populate.foreignField)) {
|
|
2366
|
-
cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(populate.colname)}`);
|
|
2367
|
-
}
|
|
2368
|
-
else {
|
|
2369
|
-
cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(populate.colname)})`);
|
|
2370
|
-
}
|
|
2371
|
-
return {
|
|
2372
|
-
columns: [sql `
|
|
2373
|
-
ARRAY(
|
|
2374
|
-
SELECT to_jsonb(${{ identifier: populate.name }}) FROM (
|
|
2375
|
-
SELECT ${_.map(subpaths, ({ path, type }) => _encodePopulateInclude(populate.name, path, type))}
|
|
2376
|
-
FROM ${{ identifier: populate.name }} WHERE ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
|
|
2377
|
-
${!_.isEmpty(populate.sort) ? sql `ORDER BY ${compiler._encodeSort(populate.sort, { className: populate.className, name: populate.name })}` : sql ``}
|
|
2378
|
-
${populate.limit ? sql `LIMIT ${{ literal: `${populate.limit}` }}` : sql ``}
|
|
2379
|
-
${populate.skip ? sql `OFFSET ${{ literal: `${populate.skip}` }}` : sql ``}
|
|
2380
|
-
${compiler.selectLock ? compiler.isUpdate ? sql `FOR UPDATE NOWAIT` : sql `FOR SHARE NOWAIT` : sql ``}
|
|
2381
|
-
) ${{ identifier: populate.name }}
|
|
2382
|
-
) AS ${{ identifier: field }}
|
|
2383
|
-
`],
|
|
2384
|
-
};
|
|
2385
|
-
};
|
|
2386
|
-
const encodeRemix = (parent, remix) => sql `${remix?.className === parent.className ? sql `
|
|
2387
|
-
(SELECT * FROM ${{ identifier: remix.name }} UNION SELECT * FROM ${{ identifier: parent.className }})
|
|
2388
|
-
` : { identifier: parent.className }}`;
|
|
2389
|
-
const encodeForeignField = (compiler, parent, foreignField, remix) => {
|
|
2390
|
-
const { paths: [colname, ...subpath], dataType } = random$1.resolveColumn(compiler.schema, parent.className, foreignField);
|
|
2391
|
-
const tempName = `_populate_$${compiler.nextIdx()}`;
|
|
2392
|
-
const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
|
|
2393
|
-
const _foreign = (field) => sql `${{ identifier: tempName }}.${{ identifier: field }}`;
|
|
2394
|
-
if (_.isEmpty(subpath) && index.isRelation(dataType) && dataType.foreignField) {
|
|
2395
|
-
const { joins, field, rows, array } = encodeForeignField(compiler, { className: dataType.target, name: tempName }, dataType.foreignField, remix);
|
|
2396
|
-
return {
|
|
2397
|
-
joins: [],
|
|
2398
|
-
field: sql `(
|
|
2399
|
-
SELECT ${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`}
|
|
2400
|
-
FROM ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
|
|
2401
|
-
${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
|
|
2402
|
-
WHERE ${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${array || rows ? sql `ANY(${field})` : field}
|
|
2403
|
-
)`,
|
|
2404
|
-
array: false,
|
|
2405
|
-
rows: true,
|
|
2406
|
-
};
|
|
2407
|
-
}
|
|
2408
|
-
if (_.isEmpty(subpath)) {
|
|
2409
|
-
return {
|
|
2410
|
-
joins: [],
|
|
2411
|
-
field: sql `${{ identifier: parent.name }}.${{ identifier: foreignField }}`,
|
|
2412
|
-
array: index.isRelation(dataType),
|
|
2413
|
-
rows: false,
|
|
2414
|
-
};
|
|
2415
|
-
}
|
|
2416
|
-
if (!index.isPointer(dataType) && !index.isRelation(dataType))
|
|
2417
|
-
throw Error(`Invalid path: ${foreignField}`);
|
|
2418
|
-
const { joins, field, rows, array } = encodeForeignField(compiler, { className: dataType.target, name: tempName }, subpath.join('.'), remix);
|
|
2419
|
-
const cond = [];
|
|
2420
|
-
if (compiler.extraFilter) {
|
|
2421
|
-
const filter = compiler.extraFilter(dataType.target);
|
|
2422
|
-
cond.push(compiler._encodeFilter({ className: dataType.target, name: tempName }, filter));
|
|
2423
|
-
}
|
|
2424
|
-
if (index.isPointer(dataType)) {
|
|
2425
|
-
cond.push(sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ${_local(colname)}`);
|
|
2426
|
-
return {
|
|
2427
|
-
joins: [sql `
|
|
2428
|
-
LEFT JOIN ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
|
|
2429
|
-
ON ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
|
|
2430
|
-
`, ...joins],
|
|
2431
|
-
field,
|
|
2432
|
-
array,
|
|
2433
|
-
rows,
|
|
2434
|
-
};
|
|
2435
|
-
}
|
|
2436
|
-
if (_.isNil(dataType.foreignField)) {
|
|
2437
|
-
cond.push(sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ANY(${_local(colname)})`);
|
|
2438
|
-
}
|
|
2439
|
-
else if (_isPointer(compiler.schema, dataType.target, dataType.foreignField)) {
|
|
2440
|
-
cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(dataType.foreignField)}`);
|
|
2441
|
-
}
|
|
2442
|
-
else {
|
|
2443
|
-
cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(dataType.foreignField)})`);
|
|
2444
|
-
}
|
|
2445
|
-
return {
|
|
2446
|
-
joins: [],
|
|
2447
|
-
field: sql `(
|
|
2448
|
-
SELECT ${array ? sql `UNNEST(${field})` : field}
|
|
2449
|
-
FROM ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
|
|
2450
|
-
${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
|
|
2451
|
-
WHERE ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
|
|
2452
|
-
)`,
|
|
2453
|
-
array: false,
|
|
2454
|
-
rows: true,
|
|
2455
|
-
};
|
|
2456
|
-
};
|
|
2457
|
-
const encodePopulate = (compiler, parent, remix) => {
|
|
2458
|
-
const _filter = parent.filter && compiler._encodeFilter(parent, parent.filter);
|
|
2459
|
-
const _populates = _.map(parent.populates, (populate, field) => selectPopulate(compiler, parent, populate, field));
|
|
2460
|
-
const _joins = _.compact(_.map(_populates, ({ join }) => join));
|
|
2461
|
-
const _includes = _.pickBy(parent.includes, v => index.isPrimitive(v));
|
|
2462
|
-
const { joins: _joins2 = [], field: _foreignField = undefined, rows = false, } = parent.foreignField ? encodeForeignField(compiler, {
|
|
2463
|
-
className: parent.className,
|
|
2464
|
-
name: parent.name,
|
|
2465
|
-
}, parent.foreignField, remix) : {};
|
|
2466
|
-
return _.reduce(parent.populates, (acc, populate) => ({
|
|
2467
|
-
...encodePopulate(compiler, populate, remix),
|
|
2468
|
-
...acc,
|
|
2469
|
-
}), {
|
|
2470
|
-
[parent.name]: sql `
|
|
2471
|
-
SELECT * FROM (
|
|
2472
|
-
SELECT
|
|
2473
|
-
${{
|
|
2474
|
-
literal: [
|
|
2475
|
-
..._.map(_.keys(_includes), colname => sql `${{ identifier: parent.name }}.${{ identifier: colname }}`),
|
|
2476
|
-
..._.flatMap(_populates, ({ columns: column }) => column),
|
|
2477
|
-
..._foreignField ? [sql `${rows ? sql `ARRAY(${_foreignField})` : _foreignField} AS ${{ identifier: parent.colname }}`] : [],
|
|
2478
|
-
], separator: ',\n'
|
|
2479
|
-
}}
|
|
2480
|
-
FROM ${encodeRemix(parent, remix)} AS ${{ identifier: parent.name }}
|
|
2481
|
-
${!_.isEmpty(_joins) || !_.isEmpty(_joins2) ? { literal: [..._joins, ..._joins2], separator: '\n' } : sql ``}
|
|
2482
|
-
) AS ${{ identifier: parent.name }}
|
|
2483
|
-
${_filter ? sql `WHERE ${_filter}` : sql ``}
|
|
2484
|
-
`,
|
|
2485
|
-
});
|
|
2486
|
-
};
|
|
2487
|
-
|
|
2488
2459
|
//
|
|
2489
2460
|
// relation.ts
|
|
2490
2461
|
//
|