@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
- ddl += ` WHERE ${queryBuilder.buildFiltersExpression(model, index.conditions)}`;
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruiapp/rapid-core",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,5 +1,17 @@
1
- import { EntityFilterOptions, FindEntityExistenceFilterOptions, FindEntityLogicalFilterOptions } from "~/types";
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
- ddl += ` WHERE ${queryBuilder.buildFiltersExpression(model, index.conditions)}`;
498
+ const rowFilterOptions = convertModelIndexConditionsToRowFilterOptions(model, index.conditions);
499
+ ddl += ` WHERE ${queryBuilder.buildFiltersExpression(model, rowFilterOptions)}`;
497
500
  }
498
501
 
499
502
  return ddl;