proto.io 0.0.167 → 0.0.168
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.
|
@@ -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,37 @@ 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
|
-
|
|
891
|
+
populate,
|
|
892
|
+
mapElem: (callback) => sql `SELECT
|
|
920
893
|
${callback(sql `${json ? sql `VALUE` : sql `UNNEST`}`)}
|
|
921
894
|
FROM ${json ? sql `jsonb_array_elements(${element})` : sql `UNNEST(${element})`}`,
|
|
922
|
-
}
|
|
895
|
+
},
|
|
923
896
|
};
|
|
924
897
|
}
|
|
925
898
|
const [colname, ...subpath] = _.toPath(field);
|
|
@@ -1878,6 +1851,231 @@ const encodeQueryExpression = (compiler, parent, expr) => {
|
|
|
1878
1851
|
return encodeBooleanExpression(compiler, parent, expr);
|
|
1879
1852
|
};
|
|
1880
1853
|
|
|
1854
|
+
//
|
|
1855
|
+
// populate.ts
|
|
1856
|
+
//
|
|
1857
|
+
// The MIT License
|
|
1858
|
+
// Copyright (c) 2021 - 2024 O2ter Limited. All rights reserved.
|
|
1859
|
+
//
|
|
1860
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1861
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
1862
|
+
// in the Software without restriction, including without limitation the rights
|
|
1863
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1864
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
1865
|
+
// furnished to do so, subject to the following conditions:
|
|
1866
|
+
//
|
|
1867
|
+
// The above copyright notice and this permission notice shall be included in
|
|
1868
|
+
// all copies or substantial portions of the Software.
|
|
1869
|
+
//
|
|
1870
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1871
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1872
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1873
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1874
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1875
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
1876
|
+
// THE SOFTWARE.
|
|
1877
|
+
//
|
|
1878
|
+
const resolveSubpaths = (compiler, populate) => {
|
|
1879
|
+
const subpaths = [];
|
|
1880
|
+
for (const [name, type] of _.toPairs(populate.includes)) {
|
|
1881
|
+
if (index.isPointer(type)) {
|
|
1882
|
+
subpaths.push(..._.map(resolveSubpaths(compiler, populate.populates[name]), ({ path, type }) => ({
|
|
1883
|
+
path: `${name}.${path}`,
|
|
1884
|
+
type,
|
|
1885
|
+
})));
|
|
1886
|
+
}
|
|
1887
|
+
else {
|
|
1888
|
+
subpaths.push({
|
|
1889
|
+
path: name,
|
|
1890
|
+
type,
|
|
1891
|
+
});
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
return subpaths;
|
|
1895
|
+
};
|
|
1896
|
+
const _isPointer = (schema, className, path) => {
|
|
1897
|
+
let fields = schema[className].fields;
|
|
1898
|
+
let last;
|
|
1899
|
+
for (const key of _.toPath(path)) {
|
|
1900
|
+
const dataType = fields[key];
|
|
1901
|
+
if (_.isNil(dataType))
|
|
1902
|
+
throw Error(`Invalid path: ${path}`);
|
|
1903
|
+
if (index.isPrimitive(dataType) || index.isVector(dataType))
|
|
1904
|
+
throw Error(`Invalid path: ${path}`);
|
|
1905
|
+
if (index.isShape(dataType)) {
|
|
1906
|
+
fields = dataType.shape;
|
|
1907
|
+
continue;
|
|
1908
|
+
}
|
|
1909
|
+
if (dataType.type !== 'pointer')
|
|
1910
|
+
return false;
|
|
1911
|
+
if (_.isNil(schema[dataType.target]))
|
|
1912
|
+
throw Error(`Invalid path: ${path}`);
|
|
1913
|
+
fields = schema[dataType.target].fields;
|
|
1914
|
+
last = dataType;
|
|
1915
|
+
}
|
|
1916
|
+
return last?.type === 'pointer';
|
|
1917
|
+
};
|
|
1918
|
+
const _selectRelationPopulate = (compiler, parent, populate, field, encode) => {
|
|
1919
|
+
const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
|
|
1920
|
+
const _foreign = (field) => sql `${{ identifier: populate.name }}.${{ identifier: field }}`;
|
|
1921
|
+
const subpaths = resolveSubpaths(compiler, populate);
|
|
1922
|
+
let cond;
|
|
1923
|
+
if (_.isNil(populate.foreignField)) {
|
|
1924
|
+
cond = sql `${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ANY(${_local(field)})`;
|
|
1925
|
+
}
|
|
1926
|
+
else if (_isPointer(compiler.schema, populate.className, populate.foreignField)) {
|
|
1927
|
+
cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(populate.colname)}`;
|
|
1928
|
+
}
|
|
1929
|
+
else {
|
|
1930
|
+
cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(populate.colname)})`;
|
|
1931
|
+
}
|
|
1932
|
+
return sql `
|
|
1933
|
+
SELECT ${_.compact(_.flatMap(subpaths, ({ path, type }) => [
|
|
1934
|
+
encode && _encodePopulateInclude(populate.name, path, type),
|
|
1935
|
+
!encode && sql `${{ identifier: populate.name }}.${{ identifier: path }}`,
|
|
1936
|
+
!encode && index.isRelation(type) && sql `${{ identifier: populate.name }}.${{ identifier: `$${path}` }}`,
|
|
1937
|
+
]))}
|
|
1938
|
+
FROM ${{ identifier: populate.name }} WHERE ${cond}
|
|
1939
|
+
${!_.isEmpty(populate.sort) ? sql `ORDER BY ${compiler._encodeSort(populate.sort, { className: populate.className, name: populate.name })}` : sql ``}
|
|
1940
|
+
${populate.limit ? sql `LIMIT ${{ literal: `${populate.limit}` }}` : sql ``}
|
|
1941
|
+
${populate.skip ? sql `OFFSET ${{ literal: `${populate.skip}` }}` : sql ``}
|
|
1942
|
+
${compiler.selectLock ? compiler.isUpdate ? sql `FOR UPDATE NOWAIT` : sql `FOR SHARE NOWAIT` : sql ``}
|
|
1943
|
+
`;
|
|
1944
|
+
};
|
|
1945
|
+
const selectPopulate = (compiler, parent, populate, field) => {
|
|
1946
|
+
if (populate.type === 'relation') {
|
|
1947
|
+
return {
|
|
1948
|
+
columns: [
|
|
1949
|
+
sql `
|
|
1950
|
+
ARRAY(
|
|
1951
|
+
SELECT to_jsonb(${{ identifier: populate.name }}) FROM (
|
|
1952
|
+
${_selectRelationPopulate(compiler, parent, populate, field, true)}
|
|
1953
|
+
) ${{ identifier: populate.name }}
|
|
1954
|
+
) AS ${{ identifier: field }}
|
|
1955
|
+
`,
|
|
1956
|
+
sql `${{ identifier: parent.name }}.${{ identifier: field }} AS ${{ identifier: `$${field}` }}`
|
|
1957
|
+
],
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1960
|
+
const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
|
|
1961
|
+
const _foreign = (field) => sql `${{ identifier: populate.name }}.${{ identifier: field }}`;
|
|
1962
|
+
const subpaths = resolveSubpaths(compiler, populate);
|
|
1963
|
+
return {
|
|
1964
|
+
columns: _.compact(_.flatMap(subpaths, ({ path, type }) => [
|
|
1965
|
+
sql `${{ identifier: populate.name }}.${{ identifier: path }} AS ${{ identifier: `${field}.${path}` }}`,
|
|
1966
|
+
index.isRelation(type) && sql `${{ identifier: populate.name }}.${{ identifier: `$${path}` }} AS ${{ identifier: `$${field}.${path}` }}`,
|
|
1967
|
+
])),
|
|
1968
|
+
join: sql `
|
|
1969
|
+
LEFT JOIN ${{ identifier: populate.name }}
|
|
1970
|
+
ON ${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ${_local(field)}
|
|
1971
|
+
`,
|
|
1972
|
+
};
|
|
1973
|
+
};
|
|
1974
|
+
const encodeRemix = (parent, remix) => sql `${remix?.className === parent.className ? sql `
|
|
1975
|
+
(SELECT * FROM ${{ identifier: remix.name }} UNION SELECT * FROM ${{ identifier: parent.className }})
|
|
1976
|
+
` : { identifier: parent.className }}`;
|
|
1977
|
+
const encodeForeignField = (compiler, parent, foreignField, remix) => {
|
|
1978
|
+
const { paths: [colname, ...subpath], dataType } = random$1.resolveColumn(compiler.schema, parent.className, foreignField);
|
|
1979
|
+
const tempName = `_populate_$${compiler.nextIdx()}`;
|
|
1980
|
+
const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
|
|
1981
|
+
const _foreign = (field) => sql `${{ identifier: tempName }}.${{ identifier: field }}`;
|
|
1982
|
+
if (_.isEmpty(subpath) && index.isRelation(dataType) && dataType.foreignField) {
|
|
1983
|
+
const { joins, field, rows, array } = encodeForeignField(compiler, { className: dataType.target, name: tempName }, dataType.foreignField, remix);
|
|
1984
|
+
return {
|
|
1985
|
+
joins: [],
|
|
1986
|
+
field: sql `(
|
|
1987
|
+
SELECT ${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`}
|
|
1988
|
+
FROM ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
|
|
1989
|
+
${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
|
|
1990
|
+
WHERE ${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${array || rows ? sql `ANY(${field})` : field}
|
|
1991
|
+
)`,
|
|
1992
|
+
array: false,
|
|
1993
|
+
rows: true,
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1996
|
+
if (_.isEmpty(subpath)) {
|
|
1997
|
+
return {
|
|
1998
|
+
joins: [],
|
|
1999
|
+
field: sql `${{ identifier: parent.name }}.${{ identifier: foreignField }}`,
|
|
2000
|
+
array: index.isRelation(dataType),
|
|
2001
|
+
rows: false,
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
if (!index.isPointer(dataType) && !index.isRelation(dataType))
|
|
2005
|
+
throw Error(`Invalid path: ${foreignField}`);
|
|
2006
|
+
const { joins, field, rows, array } = encodeForeignField(compiler, { className: dataType.target, name: tempName }, subpath.join('.'), remix);
|
|
2007
|
+
const cond = [];
|
|
2008
|
+
if (compiler.extraFilter) {
|
|
2009
|
+
const filter = compiler.extraFilter(dataType.target);
|
|
2010
|
+
cond.push(compiler._encodeFilter({ className: dataType.target, name: tempName }, filter));
|
|
2011
|
+
}
|
|
2012
|
+
if (index.isPointer(dataType)) {
|
|
2013
|
+
cond.push(sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ${_local(colname)}`);
|
|
2014
|
+
return {
|
|
2015
|
+
joins: [sql `
|
|
2016
|
+
LEFT JOIN ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
|
|
2017
|
+
ON ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
|
|
2018
|
+
`, ...joins],
|
|
2019
|
+
field,
|
|
2020
|
+
array,
|
|
2021
|
+
rows,
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
if (_.isNil(dataType.foreignField)) {
|
|
2025
|
+
cond.push(sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ANY(${_local(colname)})`);
|
|
2026
|
+
}
|
|
2027
|
+
else if (_isPointer(compiler.schema, dataType.target, dataType.foreignField)) {
|
|
2028
|
+
cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(dataType.foreignField)}`);
|
|
2029
|
+
}
|
|
2030
|
+
else {
|
|
2031
|
+
cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(dataType.foreignField)})`);
|
|
2032
|
+
}
|
|
2033
|
+
return {
|
|
2034
|
+
joins: [],
|
|
2035
|
+
field: sql `(
|
|
2036
|
+
SELECT ${array ? sql `UNNEST(${field})` : field}
|
|
2037
|
+
FROM ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
|
|
2038
|
+
${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
|
|
2039
|
+
WHERE ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
|
|
2040
|
+
)`,
|
|
2041
|
+
array: false,
|
|
2042
|
+
rows: true,
|
|
2043
|
+
};
|
|
2044
|
+
};
|
|
2045
|
+
const encodePopulate = (compiler, parent, remix) => {
|
|
2046
|
+
const _filter = _.compact([
|
|
2047
|
+
parent.filter && compiler._encodeFilter(parent, parent.filter),
|
|
2048
|
+
compiler.extraFilter && compiler._encodeFilter(parent, compiler.extraFilter(parent.className)),
|
|
2049
|
+
]);
|
|
2050
|
+
const _populates = _.map(parent.populates, (populate, field) => selectPopulate(compiler, parent, populate, field));
|
|
2051
|
+
const _joins = _.compact(_.map(_populates, ({ join }) => join));
|
|
2052
|
+
const _includes = _.pickBy(parent.includes, v => index.isPrimitive(v));
|
|
2053
|
+
const { joins: _joins2 = [], field: _foreignField = undefined, rows = false, } = parent.foreignField ? encodeForeignField(compiler, {
|
|
2054
|
+
className: parent.className,
|
|
2055
|
+
name: parent.name,
|
|
2056
|
+
}, parent.foreignField, remix) : {};
|
|
2057
|
+
return _.reduce(parent.populates, (acc, populate) => ({
|
|
2058
|
+
...encodePopulate(compiler, populate, remix),
|
|
2059
|
+
...acc,
|
|
2060
|
+
}), {
|
|
2061
|
+
[parent.name]: sql `
|
|
2062
|
+
SELECT * FROM (
|
|
2063
|
+
SELECT
|
|
2064
|
+
${{
|
|
2065
|
+
literal: [
|
|
2066
|
+
..._.map(_.keys(_includes), colname => sql `${{ identifier: parent.name }}.${{ identifier: colname }}`),
|
|
2067
|
+
..._.flatMap(_populates, ({ columns: column }) => column),
|
|
2068
|
+
..._foreignField ? [sql `${rows ? sql `ARRAY(${_foreignField})` : _foreignField} AS ${{ identifier: parent.colname }}`] : [],
|
|
2069
|
+
], separator: ',\n'
|
|
2070
|
+
}}
|
|
2071
|
+
FROM ${encodeRemix(parent, remix)} AS ${{ identifier: parent.name }}
|
|
2072
|
+
${!_.isEmpty(_joins) || !_.isEmpty(_joins2) ? { literal: [..._joins, ..._joins2], separator: '\n' } : sql ``}
|
|
2073
|
+
) AS ${{ identifier: parent.name }}
|
|
2074
|
+
${!_.isEmpty(_filter) ? sql `WHERE ${{ literal: _.map(_.compact(_filter), x => sql `(${x})`), separator: ' AND ' }}` : sql ``}
|
|
2075
|
+
`,
|
|
2076
|
+
});
|
|
2077
|
+
};
|
|
2078
|
+
|
|
1881
2079
|
//
|
|
1882
2080
|
// selectors.ts
|
|
1883
2081
|
//
|
|
@@ -2064,12 +2262,12 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2064
2262
|
if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
|
|
2065
2263
|
return sql `${element} <@ ${{ value: index._encodeValue(expr.value) }}`;
|
|
2066
2264
|
}
|
|
2067
|
-
|
|
2265
|
+
if (relation) {
|
|
2068
2266
|
if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
|
|
2069
2267
|
break;
|
|
2070
|
-
return sql `ARRAY(${relation.
|
|
2268
|
+
return sql `ARRAY(${relation.mapElem((v) => sql `${v} ->> '_id'`)}) <@ ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
|
|
2071
2269
|
}
|
|
2072
|
-
|
|
2270
|
+
if (!dataType) {
|
|
2073
2271
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} <@ ${_encodeJsonValue(index._encodeValue(expr.value))}`;
|
|
2074
2272
|
}
|
|
2075
2273
|
}
|
|
@@ -2082,12 +2280,12 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2082
2280
|
if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
|
|
2083
2281
|
return sql `${element} @> ${{ value: index._encodeValue(expr.value) }}`;
|
|
2084
2282
|
}
|
|
2085
|
-
|
|
2283
|
+
if (relation) {
|
|
2086
2284
|
if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
|
|
2087
2285
|
break;
|
|
2088
|
-
return sql `ARRAY(${relation.
|
|
2286
|
+
return sql `ARRAY(${relation.mapElem((v) => sql `${v} ->> '_id'`)}) @> ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
|
|
2089
2287
|
}
|
|
2090
|
-
|
|
2288
|
+
if (!dataType) {
|
|
2091
2289
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} @> ${_encodeJsonValue(index._encodeValue(expr.value))}`;
|
|
2092
2290
|
}
|
|
2093
2291
|
}
|
|
@@ -2100,12 +2298,12 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2100
2298
|
if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
|
|
2101
2299
|
return sql `NOT ${element} && ${{ value: index._encodeValue(expr.value) }}`;
|
|
2102
2300
|
}
|
|
2103
|
-
|
|
2301
|
+
if (relation) {
|
|
2104
2302
|
if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
|
|
2105
2303
|
break;
|
|
2106
|
-
return sql `NOT ARRAY(${relation.
|
|
2304
|
+
return sql `NOT ARRAY(${relation.mapElem((v) => sql `${v} ->> '_id'`)}) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
|
|
2107
2305
|
}
|
|
2108
|
-
|
|
2306
|
+
if (!dataType) {
|
|
2109
2307
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND NOT ${element} && ${_encodeJsonValue(index._encodeValue(expr.value))}`;
|
|
2110
2308
|
}
|
|
2111
2309
|
}
|
|
@@ -2118,12 +2316,12 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2118
2316
|
if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
|
|
2119
2317
|
return sql `${element} && ${{ value: index._encodeValue(expr.value) }}`;
|
|
2120
2318
|
}
|
|
2121
|
-
|
|
2319
|
+
if (relation) {
|
|
2122
2320
|
if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
|
|
2123
2321
|
break;
|
|
2124
|
-
return sql `ARRAY(${relation.
|
|
2322
|
+
return sql `ARRAY(${relation.mapElem((v) => sql `${v} ->> '_id'`)}) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
|
|
2125
2323
|
}
|
|
2126
|
-
|
|
2324
|
+
if (!dataType) {
|
|
2127
2325
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} && ${_encodeJsonValue(index._encodeValue(expr.value))}`;
|
|
2128
2326
|
}
|
|
2129
2327
|
}
|
|
@@ -2139,7 +2337,7 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2139
2337
|
if (_.isString(expr.value)) {
|
|
2140
2338
|
return sql `${element} LIKE ${{ value: `%${expr.value.replace(/([\\_%])/g, '\\$1')}%` }}`;
|
|
2141
2339
|
}
|
|
2142
|
-
|
|
2340
|
+
if (_.isRegExp(expr.value)) {
|
|
2143
2341
|
if (expr.value.ignoreCase)
|
|
2144
2342
|
return sql `${element} ~* ${{ value: expr.value.source }}`;
|
|
2145
2343
|
return sql `${element} ~ ${{ value: expr.value.source }}`;
|
|
@@ -2149,7 +2347,7 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2149
2347
|
if (_.isString(expr.value)) {
|
|
2150
2348
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'string' AND (${element} #>> '{}') LIKE ${{ value: `%${expr.value.replace(/([\\_%])/g, '\\$1')}%` }}`;
|
|
2151
2349
|
}
|
|
2152
|
-
|
|
2350
|
+
if (_.isRegExp(expr.value)) {
|
|
2153
2351
|
if (expr.value.ignoreCase)
|
|
2154
2352
|
return sql `${element} ~* ${{ value: expr.value.source }}`;
|
|
2155
2353
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'string' AND (${element} #>> '{}') ~ ${{ value: expr.value.source }}`;
|
|
@@ -2163,7 +2361,7 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2163
2361
|
if (dataType === 'string' || (!_.isString(dataType) && dataType?.type === 'string')) {
|
|
2164
2362
|
return sql `${element} LIKE ${{ value: `${expr.value.replace(/([\\_%])/g, '\\$1')}%` }}`;
|
|
2165
2363
|
}
|
|
2166
|
-
|
|
2364
|
+
if (!dataType) {
|
|
2167
2365
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'string' AND (${element} #>> '{}') LIKE ${{ value: `${expr.value.replace(/([\\_%])/g, '\\$1')}%` }}`;
|
|
2168
2366
|
}
|
|
2169
2367
|
}
|
|
@@ -2174,7 +2372,7 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2174
2372
|
if (dataType === 'string' || (!_.isString(dataType) && dataType?.type === 'string')) {
|
|
2175
2373
|
return sql `${element} LIKE ${{ value: `%${expr.value.replace(/([\\_%])/g, '\\$1')}` }}`;
|
|
2176
2374
|
}
|
|
2177
|
-
|
|
2375
|
+
if (!dataType) {
|
|
2178
2376
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'string' AND (${element} #>> '{}') LIKE ${{ value: `%${expr.value.replace(/([\\_%])/g, '\\$1')}` }}`;
|
|
2179
2377
|
}
|
|
2180
2378
|
}
|
|
@@ -2185,10 +2383,10 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2185
2383
|
if (dataType === 'string' || (!_.isString(dataType) && dataType?.type === 'string')) {
|
|
2186
2384
|
return sql `COALESCE(length(${element}), 0) = ${{ value: expr.value }}`;
|
|
2187
2385
|
}
|
|
2188
|
-
|
|
2386
|
+
if (dataType === 'array' || (!_.isString(dataType) && (dataType?.type === 'array' || dataType?.type === 'vector' || dataType?.type === 'relation'))) {
|
|
2189
2387
|
return sql `COALESCE(array_length(${element}, 1), 0) = ${{ value: expr.value }}`;
|
|
2190
2388
|
}
|
|
2191
|
-
|
|
2389
|
+
if (!dataType) {
|
|
2192
2390
|
return sql `(
|
|
2193
2391
|
CASE jsonb_typeof(${element})
|
|
2194
2392
|
WHEN 'array' THEN jsonb_array_length(${element}) = ${{ value: expr.value }}
|
|
@@ -2205,10 +2403,10 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2205
2403
|
if (dataType === 'string' || (!_.isString(dataType) && dataType?.type === 'string')) {
|
|
2206
2404
|
return sql `COALESCE(length(${element}), 0) ${{ literal: expr.value ? '=' : '<>' }} 0`;
|
|
2207
2405
|
}
|
|
2208
|
-
|
|
2406
|
+
if (dataType === 'array' || (!_.isString(dataType) && (dataType?.type === 'array' || dataType?.type === 'vector' || dataType?.type === 'relation'))) {
|
|
2209
2407
|
return sql `COALESCE(array_length(${element}, 1), 0) ${{ literal: expr.value ? '=' : '<>' }} 0`;
|
|
2210
2408
|
}
|
|
2211
|
-
|
|
2409
|
+
if (!dataType) {
|
|
2212
2410
|
return sql `(
|
|
2213
2411
|
CASE jsonb_typeof(${element})
|
|
2214
2412
|
WHEN 'array' THEN jsonb_array_length(${element}) ${{ literal: expr.value ? '=' : '<>' }} 0
|
|
@@ -2222,23 +2420,34 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2222
2420
|
{
|
|
2223
2421
|
if (!(expr.value instanceof index$1.QuerySelector))
|
|
2224
2422
|
break;
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2423
|
+
if (relation?.populate && parent.className) {
|
|
2424
|
+
const tempName = `_populate_expr_$${compiler.nextIdx()}`;
|
|
2425
|
+
const filter = compiler._encodeFilter({
|
|
2426
|
+
name: tempName,
|
|
2427
|
+
className: relation.target,
|
|
2428
|
+
populates: relation.populate.populates,
|
|
2429
|
+
}, expr.value);
|
|
2430
|
+
if (!filter)
|
|
2431
|
+
break;
|
|
2230
2432
|
return sql `NOT EXISTS(
|
|
2231
|
-
SELECT * FROM (${
|
|
2433
|
+
SELECT * FROM (${_selectRelationPopulate(compiler, {
|
|
2434
|
+
className: parent.className,
|
|
2435
|
+
name: parent.name,
|
|
2436
|
+
}, relation.populate, `$${field}`, false)}) AS ${{ identifier: tempName }}
|
|
2232
2437
|
WHERE NOT (${filter})
|
|
2233
2438
|
)`;
|
|
2234
2439
|
}
|
|
2235
|
-
|
|
2440
|
+
const tempName = `_doller_expr_$${compiler.nextIdx()}`;
|
|
2441
|
+
const filter = compiler._encodeFilter({ name: tempName, className: relation?.target }, expr.value);
|
|
2442
|
+
if (!filter)
|
|
2443
|
+
break;
|
|
2444
|
+
if (dataType === 'array' || (!_.isString(dataType) && (dataType?.type === 'array' || dataType?.type === 'vector'))) {
|
|
2236
2445
|
return sql `NOT EXISTS(
|
|
2237
2446
|
SELECT * FROM (SELECT UNNEST AS "$" FROM UNNEST(${element})) AS ${{ identifier: tempName }}
|
|
2238
2447
|
WHERE NOT (${filter})
|
|
2239
2448
|
)`;
|
|
2240
2449
|
}
|
|
2241
|
-
|
|
2450
|
+
if (!dataType) {
|
|
2242
2451
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND NOT EXISTS(
|
|
2243
2452
|
SELECT * FROM (SELECT value AS "$" FROM jsonb_array_elements(${element})) AS ${{ identifier: tempName }}
|
|
2244
2453
|
WHERE NOT (${filter})
|
|
@@ -2249,23 +2458,34 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2249
2458
|
{
|
|
2250
2459
|
if (!(expr.value instanceof index$1.QuerySelector))
|
|
2251
2460
|
break;
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2461
|
+
if (relation?.populate && parent.className) {
|
|
2462
|
+
const tempName = `_populate_expr_$${compiler.nextIdx()}`;
|
|
2463
|
+
const filter = compiler._encodeFilter({
|
|
2464
|
+
name: tempName,
|
|
2465
|
+
className: relation.target,
|
|
2466
|
+
populates: relation.populate.populates,
|
|
2467
|
+
}, expr.value);
|
|
2468
|
+
if (!filter)
|
|
2469
|
+
break;
|
|
2257
2470
|
return sql `EXISTS(
|
|
2258
|
-
SELECT * FROM (${
|
|
2471
|
+
SELECT * FROM (${_selectRelationPopulate(compiler, {
|
|
2472
|
+
className: parent.className,
|
|
2473
|
+
name: parent.name,
|
|
2474
|
+
}, relation.populate, `$${field}`, false)}) AS ${{ identifier: tempName }}
|
|
2259
2475
|
WHERE ${filter}
|
|
2260
2476
|
)`;
|
|
2261
2477
|
}
|
|
2262
|
-
|
|
2478
|
+
const tempName = `_doller_expr_$${compiler.nextIdx()}`;
|
|
2479
|
+
const filter = compiler._encodeFilter({ name: tempName, className: relation?.target }, expr.value);
|
|
2480
|
+
if (!filter)
|
|
2481
|
+
break;
|
|
2482
|
+
if (dataType === 'array' || (!_.isString(dataType) && (dataType?.type === 'array' || dataType?.type === 'vector'))) {
|
|
2263
2483
|
return sql `EXISTS(
|
|
2264
2484
|
SELECT * FROM (SELECT UNNEST AS "$" FROM UNNEST(${element})) AS ${{ identifier: tempName }}
|
|
2265
2485
|
WHERE ${filter}
|
|
2266
2486
|
)`;
|
|
2267
2487
|
}
|
|
2268
|
-
|
|
2488
|
+
if (!dataType) {
|
|
2269
2489
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND EXISTS(
|
|
2270
2490
|
SELECT * FROM (SELECT value AS "$" FROM jsonb_array_elements(${element})) AS ${{ identifier: tempName }}
|
|
2271
2491
|
WHERE ${filter}
|
|
@@ -2276,215 +2496,6 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2276
2496
|
throw Error('Invalid expression');
|
|
2277
2497
|
};
|
|
2278
2498
|
|
|
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
2499
|
//
|
|
2489
2500
|
// relation.ts
|
|
2490
2501
|
//
|