@ruiapp/rapid-core 0.2.2 → 0.2.3
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.
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import { EntityFilterOptions } from "../types";
|
|
1
|
+
import { EntityFilterOptions, RpdDataModel, RpdDataModelIndexOptions } from "../types";
|
|
2
|
+
import { RowFilterOptions } from "../dataAccess/dataAccessTypes";
|
|
2
3
|
export declare function removeFiltersWithNullValue(filters?: EntityFilterOptions[]): EntityFilterOptions[];
|
|
4
|
+
export declare function convertModelIndexConditionsToRowFilterOptions(model: RpdDataModel, filters: RpdDataModelIndexOptions[]): RowFilterOptions[];
|
|
5
|
+
export declare function replaceModelIndexConditionEntityPropertyWithTableColumn(model: RpdDataModel, filter: RpdDataModelIndexOptions): RowFilterOptions;
|
|
@@ -7,4 +7,6 @@ export declare function getEntityProperties(server: IRpdServer, model: RpdDataMo
|
|
|
7
7
|
export declare function getEntityPropertiesIncludingBase(server: IRpdServer, model: RpdDataModel): RpdDataModelProperty[];
|
|
8
8
|
export declare function getEntityPropertyByCode(server: IRpdServer, model: RpdDataModel, propertyCode: string): RpdDataModelProperty | undefined;
|
|
9
9
|
export declare function getEntityProperty(server: IRpdServer, model: RpdDataModel, predicate: (item: RpdDataModelProperty) => boolean): RpdDataModelProperty | undefined;
|
|
10
|
+
export declare function getEntityOwnPropertyByCode(model: RpdDataModel, propertyCode: string): RpdDataModelProperty | undefined;
|
|
11
|
+
export declare function getEntityOwnProperty(model: RpdDataModel, predicate: (item: RpdDataModelProperty) => boolean): RpdDataModelProperty | undefined;
|
|
10
12
|
export declare function getEntityPropertyByFieldName(server: IRpdServer, model: RpdDataModel, fieldName: string): RpdDataModelProperty | undefined;
|
package/dist/index.js
CHANGED
|
@@ -2064,6 +2064,13 @@ function getEntityProperty(server, model, predicate) {
|
|
|
2064
2064
|
}
|
|
2065
2065
|
return property;
|
|
2066
2066
|
}
|
|
2067
|
+
function getEntityOwnPropertyByCode(model, propertyCode) {
|
|
2068
|
+
return getEntityOwnProperty(model, (e) => e.code === propertyCode);
|
|
2069
|
+
}
|
|
2070
|
+
function getEntityOwnProperty(model, predicate) {
|
|
2071
|
+
let property = model.properties.find(predicate);
|
|
2072
|
+
return property;
|
|
2073
|
+
}
|
|
2067
2074
|
function getEntityPropertyByFieldName(server, model, fieldName) {
|
|
2068
2075
|
let property = getEntityPropertyByCode(server, model, fieldName);
|
|
2069
2076
|
if (!property) {
|
|
@@ -4150,6 +4157,120 @@ var getMetaModelDetail = /*#__PURE__*/Object.freeze({
|
|
|
4150
4157
|
handler: handler$r
|
|
4151
4158
|
});
|
|
4152
4159
|
|
|
4160
|
+
function removeFiltersWithNullValue(filters) {
|
|
4161
|
+
const result = [];
|
|
4162
|
+
if (!filters) {
|
|
4163
|
+
return result;
|
|
4164
|
+
}
|
|
4165
|
+
for (const filter of filters) {
|
|
4166
|
+
const { operator } = filter;
|
|
4167
|
+
switch (operator) {
|
|
4168
|
+
case "null":
|
|
4169
|
+
case "notNull":
|
|
4170
|
+
result.push(filter);
|
|
4171
|
+
break;
|
|
4172
|
+
case "exists":
|
|
4173
|
+
case "notExists":
|
|
4174
|
+
case "and":
|
|
4175
|
+
case "or":
|
|
4176
|
+
const transformedFilter = transformFilterWithSubFilters(filter);
|
|
4177
|
+
if (transformedFilter !== null) {
|
|
4178
|
+
result.push(transformedFilter);
|
|
4179
|
+
}
|
|
4180
|
+
break;
|
|
4181
|
+
default:
|
|
4182
|
+
if (!isNullOrUndefined(filter.value)) {
|
|
4183
|
+
result.push(filter);
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
}
|
|
4187
|
+
return result;
|
|
4188
|
+
}
|
|
4189
|
+
function transformFilterWithSubFilters(filter) {
|
|
4190
|
+
const subFilters = removeFiltersWithNullValue(filter.filters);
|
|
4191
|
+
if (!subFilters.length) {
|
|
4192
|
+
return null;
|
|
4193
|
+
}
|
|
4194
|
+
filter.filters = subFilters;
|
|
4195
|
+
return filter;
|
|
4196
|
+
}
|
|
4197
|
+
function convertModelIndexConditionsToRowFilterOptions(model, filters) {
|
|
4198
|
+
if (!filters || !filters.length) {
|
|
4199
|
+
return [];
|
|
4200
|
+
}
|
|
4201
|
+
const replacedFilters = [];
|
|
4202
|
+
for (const filter of filters) {
|
|
4203
|
+
const { operator } = filter;
|
|
4204
|
+
if (operator === "and" || operator === "or") {
|
|
4205
|
+
replacedFilters.push({
|
|
4206
|
+
operator: operator,
|
|
4207
|
+
filters: convertModelIndexConditionsToRowFilterOptions(model, filter.filters),
|
|
4208
|
+
});
|
|
4209
|
+
}
|
|
4210
|
+
else {
|
|
4211
|
+
replacedFilters.push(replaceModelIndexConditionEntityPropertyWithTableColumn(model, filter));
|
|
4212
|
+
}
|
|
4213
|
+
}
|
|
4214
|
+
return replacedFilters;
|
|
4215
|
+
}
|
|
4216
|
+
function replaceModelIndexConditionEntityPropertyWithTableColumn(model, filter) {
|
|
4217
|
+
const { operator } = filter;
|
|
4218
|
+
const filterField = filter.field;
|
|
4219
|
+
let property = getEntityOwnPropertyByCode(model, filterField);
|
|
4220
|
+
let filterValue = filter.value;
|
|
4221
|
+
let columnName = "";
|
|
4222
|
+
if (property) {
|
|
4223
|
+
if (isOneRelationProperty(property)) {
|
|
4224
|
+
columnName = property.targetIdColumnName;
|
|
4225
|
+
if (lodash.isPlainObject(filterValue)) {
|
|
4226
|
+
filterValue = filterValue.id;
|
|
4227
|
+
}
|
|
4228
|
+
}
|
|
4229
|
+
else if (isManyRelationProperty(property)) {
|
|
4230
|
+
throw new Error(`Condition on many-relation property "${property.code}" is not supported.`);
|
|
4231
|
+
}
|
|
4232
|
+
else {
|
|
4233
|
+
columnName = property.columnName || property.code;
|
|
4234
|
+
}
|
|
4235
|
+
}
|
|
4236
|
+
else if (operator === "exists" || operator === "notExists") {
|
|
4237
|
+
throw new Error(`"exists" and "notExists" operators are not supported in index conditions.`);
|
|
4238
|
+
}
|
|
4239
|
+
else {
|
|
4240
|
+
property = getEntityOwnProperty(model, (property) => {
|
|
4241
|
+
return property.columnName === filterField;
|
|
4242
|
+
});
|
|
4243
|
+
if (property) {
|
|
4244
|
+
columnName = property.columnName;
|
|
4245
|
+
}
|
|
4246
|
+
else {
|
|
4247
|
+
// may be relation property.
|
|
4248
|
+
property = getEntityOwnProperty(model, (property) => {
|
|
4249
|
+
return property.targetIdColumnName === filterField;
|
|
4250
|
+
});
|
|
4251
|
+
if (property) {
|
|
4252
|
+
if (isManyRelationProperty(property)) {
|
|
4253
|
+
throw new Error(`Condition on many-relation property "${property.code}" is not supported.`);
|
|
4254
|
+
}
|
|
4255
|
+
columnName = property.targetIdColumnName;
|
|
4256
|
+
if (lodash.isPlainObject(filterValue)) {
|
|
4257
|
+
filterValue = filterValue.id;
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
else {
|
|
4261
|
+
throw new Error(`Unknown field "${filterField}" in index conditions.`);
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
// TODO: do not use `any` here
|
|
4266
|
+
return {
|
|
4267
|
+
operator: filter.operator,
|
|
4268
|
+
field: columnName,
|
|
4269
|
+
value: filterValue,
|
|
4270
|
+
itemType: filter.itemType,
|
|
4271
|
+
};
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4153
4274
|
/**
|
|
4154
4275
|
* Meta manager plugin
|
|
4155
4276
|
*/
|
|
@@ -4431,6 +4552,7 @@ async function syncDatabaseSchema(server, applicationConfig) {
|
|
|
4431
4552
|
if (!model.indexes || !model.indexes.length) {
|
|
4432
4553
|
continue;
|
|
4433
4554
|
}
|
|
4555
|
+
logger.debug(`Creating indexes of table ${queryBuilder.quoteTable(model)}`);
|
|
4434
4556
|
for (const index of model.indexes) {
|
|
4435
4557
|
const sqlCreateIndex = generateTableIndexDDL(queryBuilder, server, model, index);
|
|
4436
4558
|
await server.tryQueryDatabaseObject(sqlCreateIndex, []);
|
|
@@ -4508,7 +4630,8 @@ function generateTableIndexDDL(queryBuilder, server, model, index) {
|
|
|
4508
4630
|
tableName: model.tableName,
|
|
4509
4631
|
})} (${indexColumns.join(", ")})`;
|
|
4510
4632
|
if (index.conditions) {
|
|
4511
|
-
|
|
4633
|
+
const rowFilterOptions = convertModelIndexConditionsToRowFilterOptions(model, index.conditions);
|
|
4634
|
+
ddl += ` WHERE ${queryBuilder.buildFiltersExpression(model, rowFilterOptions)}`;
|
|
4512
4635
|
}
|
|
4513
4636
|
return ddl;
|
|
4514
4637
|
}
|
|
@@ -4537,44 +4660,6 @@ async function runCollectionEntityActionHandler(ctx, options, code, handleEntity
|
|
|
4537
4660
|
}
|
|
4538
4661
|
}
|
|
4539
4662
|
|
|
4540
|
-
function removeFiltersWithNullValue(filters) {
|
|
4541
|
-
const result = [];
|
|
4542
|
-
if (!filters) {
|
|
4543
|
-
return result;
|
|
4544
|
-
}
|
|
4545
|
-
for (const filter of filters) {
|
|
4546
|
-
const { operator } = filter;
|
|
4547
|
-
switch (operator) {
|
|
4548
|
-
case "null":
|
|
4549
|
-
case "notNull":
|
|
4550
|
-
result.push(filter);
|
|
4551
|
-
break;
|
|
4552
|
-
case "exists":
|
|
4553
|
-
case "notExists":
|
|
4554
|
-
case "and":
|
|
4555
|
-
case "or":
|
|
4556
|
-
const transformedFilter = transformFilterWithSubFilters(filter);
|
|
4557
|
-
if (transformedFilter !== null) {
|
|
4558
|
-
result.push(transformedFilter);
|
|
4559
|
-
}
|
|
4560
|
-
break;
|
|
4561
|
-
default:
|
|
4562
|
-
if (!isNullOrUndefined(filter.value)) {
|
|
4563
|
-
result.push(filter);
|
|
4564
|
-
}
|
|
4565
|
-
}
|
|
4566
|
-
}
|
|
4567
|
-
return result;
|
|
4568
|
-
}
|
|
4569
|
-
function transformFilterWithSubFilters(filter) {
|
|
4570
|
-
const subFilters = removeFiltersWithNullValue(filter.filters);
|
|
4571
|
-
if (!subFilters.length) {
|
|
4572
|
-
return null;
|
|
4573
|
-
}
|
|
4574
|
-
filter.filters = subFilters;
|
|
4575
|
-
return filter;
|
|
4576
|
-
}
|
|
4577
|
-
|
|
4578
4663
|
const code$q = "findCollectionEntities";
|
|
4579
4664
|
async function handler$q(plugin, ctx, options) {
|
|
4580
4665
|
await runCollectionEntityActionHandler(ctx, options, code$q, async (entityManager, input) => {
|
package/package.json
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
EntityFilterOptions,
|
|
3
|
+
EntityNonRelationPropertyFilterOptions,
|
|
4
|
+
FindEntityExistenceFilterOptions,
|
|
5
|
+
FindEntityLogicalFilterOptions,
|
|
6
|
+
RpdDataModel,
|
|
7
|
+
RpdDataModelIndexOptions,
|
|
8
|
+
RpdDataModelProperty,
|
|
9
|
+
} from "~/types";
|
|
2
10
|
import { isNullOrUndefined } from "~/utilities/typeUtility";
|
|
11
|
+
import { getEntityOwnProperty, getEntityOwnPropertyByCode, isManyRelationProperty, isOneRelationProperty } from "./metaHelper";
|
|
12
|
+
import { IRpdServer } from "~/core/server";
|
|
13
|
+
import { isPlainObject } from "lodash";
|
|
14
|
+
import { RowFilterOptions } from "~/dataAccess/dataAccessTypes";
|
|
3
15
|
|
|
4
16
|
export function removeFiltersWithNullValue(filters?: EntityFilterOptions[]) {
|
|
5
17
|
const result: EntityFilterOptions[] = [];
|
|
@@ -45,3 +57,79 @@ function transformFilterWithSubFilters(
|
|
|
45
57
|
filter.filters = subFilters;
|
|
46
58
|
return filter;
|
|
47
59
|
}
|
|
60
|
+
|
|
61
|
+
export function convertModelIndexConditionsToRowFilterOptions(model: RpdDataModel, filters: RpdDataModelIndexOptions[]) {
|
|
62
|
+
if (!filters || !filters.length) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const replacedFilters: RowFilterOptions[] = [];
|
|
67
|
+
for (const filter of filters) {
|
|
68
|
+
const { operator } = filter;
|
|
69
|
+
if (operator === "and" || operator === "or") {
|
|
70
|
+
replacedFilters.push({
|
|
71
|
+
operator: operator,
|
|
72
|
+
filters: convertModelIndexConditionsToRowFilterOptions(model, filter.filters),
|
|
73
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
replacedFilters.push(replaceModelIndexConditionEntityPropertyWithTableColumn(model, filter));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return replacedFilters;
|
|
79
|
+
}
|
|
80
|
+
export function replaceModelIndexConditionEntityPropertyWithTableColumn(model: RpdDataModel, filter: RpdDataModelIndexOptions): RowFilterOptions {
|
|
81
|
+
const { operator } = filter;
|
|
82
|
+
const filterField = (filter as EntityNonRelationPropertyFilterOptions).field;
|
|
83
|
+
let property: RpdDataModelProperty = getEntityOwnPropertyByCode(model, filterField);
|
|
84
|
+
|
|
85
|
+
let filterValue = (filter as any).value;
|
|
86
|
+
|
|
87
|
+
let columnName = "";
|
|
88
|
+
if (property) {
|
|
89
|
+
if (isOneRelationProperty(property)) {
|
|
90
|
+
columnName = property.targetIdColumnName;
|
|
91
|
+
if (isPlainObject(filterValue)) {
|
|
92
|
+
filterValue = filterValue.id;
|
|
93
|
+
}
|
|
94
|
+
} else if (isManyRelationProperty(property)) {
|
|
95
|
+
throw new Error(`Condition on many-relation property "${property.code}" is not supported.`);
|
|
96
|
+
} else {
|
|
97
|
+
columnName = property.columnName || property.code;
|
|
98
|
+
}
|
|
99
|
+
} else if ((operator as any) === "exists" || (operator as any) === "notExists") {
|
|
100
|
+
throw new Error(`"exists" and "notExists" operators are not supported in index conditions.`);
|
|
101
|
+
} else {
|
|
102
|
+
property = getEntityOwnProperty(model, (property) => {
|
|
103
|
+
return property.columnName === filterField;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (property) {
|
|
107
|
+
columnName = property.columnName;
|
|
108
|
+
} else {
|
|
109
|
+
// may be relation property.
|
|
110
|
+
property = getEntityOwnProperty(model, (property) => {
|
|
111
|
+
return property.targetIdColumnName === filterField;
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (property) {
|
|
115
|
+
if (isManyRelationProperty(property)) {
|
|
116
|
+
throw new Error(`Condition on many-relation property "${property.code}" is not supported.`);
|
|
117
|
+
}
|
|
118
|
+
columnName = property.targetIdColumnName;
|
|
119
|
+
if (isPlainObject(filterValue)) {
|
|
120
|
+
filterValue = filterValue.id;
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
throw new Error(`Unknown field "${filterField}" in index conditions.`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// TODO: do not use `any` here
|
|
129
|
+
return {
|
|
130
|
+
operator: filter.operator,
|
|
131
|
+
field: columnName,
|
|
132
|
+
value: filterValue,
|
|
133
|
+
itemType: (filter as any).itemType,
|
|
134
|
+
} as RowFilterOptions;
|
|
135
|
+
}
|
|
@@ -66,6 +66,15 @@ export function getEntityProperty(
|
|
|
66
66
|
return property;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
export function getEntityOwnPropertyByCode(model: RpdDataModel, propertyCode: string): RpdDataModelProperty | undefined {
|
|
70
|
+
return getEntityOwnProperty(model, (e) => e.code === propertyCode);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getEntityOwnProperty(model: RpdDataModel, predicate: (item: RpdDataModelProperty) => boolean): RpdDataModelProperty | undefined {
|
|
74
|
+
let property = model.properties.find(predicate);
|
|
75
|
+
return property;
|
|
76
|
+
}
|
|
77
|
+
|
|
69
78
|
export function getEntityPropertyByFieldName(server: IRpdServer, model: RpdDataModel, fieldName: string): RpdDataModelProperty | undefined {
|
|
70
79
|
let property = getEntityPropertyByCode(server, model, fieldName);
|
|
71
80
|
if (!property) {
|
|
@@ -30,6 +30,7 @@ import { find, isString, map } from "lodash";
|
|
|
30
30
|
import { getEntityPropertiesIncludingBase, getEntityPropertyByCode, isOneRelationProperty, isRelationProperty } from "~/helpers/metaHelper";
|
|
31
31
|
import { DataAccessPgColumnTypes } from "~/dataAccess/dataAccessTypes";
|
|
32
32
|
import { pgPropertyTypeColumnMap } from "~/dataAccess/columnTypeMapper";
|
|
33
|
+
import { convertModelIndexConditionsToRowFilterOptions } from "~/helpers/filterHelper";
|
|
33
34
|
|
|
34
35
|
class MetaManager implements RapidPlugin {
|
|
35
36
|
get code(): string {
|
|
@@ -388,6 +389,7 @@ async function syncDatabaseSchema(server: IRpdServer, applicationConfig: RpdAppl
|
|
|
388
389
|
continue;
|
|
389
390
|
}
|
|
390
391
|
|
|
392
|
+
logger.debug(`Creating indexes of table ${queryBuilder.quoteTable(model)}`);
|
|
391
393
|
for (const index of model.indexes) {
|
|
392
394
|
const sqlCreateIndex = generateTableIndexDDL(queryBuilder, server, model, index);
|
|
393
395
|
await server.tryQueryDatabaseObject(sqlCreateIndex, []);
|
|
@@ -493,7 +495,8 @@ function generateTableIndexDDL(queryBuilder: IQueryBuilder, server: IRpdServer,
|
|
|
493
495
|
})} (${indexColumns.join(", ")})`;
|
|
494
496
|
|
|
495
497
|
if (index.conditions) {
|
|
496
|
-
|
|
498
|
+
const rowFilterOptions = convertModelIndexConditionsToRowFilterOptions(model, index.conditions);
|
|
499
|
+
ddl += ` WHERE ${queryBuilder.buildFiltersExpression(model, rowFilterOptions)}`;
|
|
497
500
|
}
|
|
498
501
|
|
|
499
502
|
return ddl;
|