@ruiapp/rapid-core 0.1.74 → 0.1.76

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.
@@ -0,0 +1,3 @@
1
+ import { RpdDataPropertyTypes } from "../types";
2
+ import { DataAccessPgColumnTypes } from "./dataAccessTypes";
3
+ export declare const pgPropertyTypeColumnMap: Record<Exclude<RpdDataPropertyTypes, "relation" | "relation[]">, DataAccessPgColumnTypes>;
@@ -1,11 +1,13 @@
1
+ export type DataAccessPgColumnTypes = "int4" | "int8" | "float4" | "float8" | "decimal" | "text" | "text[]" | "bool" | "date" | "time" | "timestamptz" | "jsonb";
1
2
  export type RowFilterRelationalOperators = "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "contains" | "notContains" | "containsCS" | "notContainsCS" | "startsWith" | "notStartsWith" | "endsWith" | "notEndsWith";
3
+ export type RowFilterArrayOperators = "arrayContains" | "arrayOverlap";
2
4
  export type RowFilterSetOperators = "in" | "notIn";
3
5
  export type RowFilterLogicalOperators = "or" | "and";
4
6
  export type RowFilterUnaryOperators = "null" | "notNull";
5
7
  export type RowFilterExistenceOperators = "exists" | "notExists";
6
- export type RowFilterOperators = RowFilterRelationalOperators | RowFilterSetOperators | RowFilterLogicalOperators | RowFilterUnaryOperators | RowFilterExistenceOperators;
7
- export type RowFilterOptions = FindRowRelationalFilterOptions | FindRowSetFilterOptions | FindRowLogicalFilterOptions | FindRowUnaryFilterOptions | FindRowExistenceFilterOptions;
8
- export type RowNonRelationPropertyFilterOptions = FindRowRelationalFilterOptions | FindRowSetFilterOptions | FindRowUnaryFilterOptions;
8
+ export type RowFilterOperators = RowFilterRelationalOperators | RowFilterArrayOperators | RowFilterSetOperators | RowFilterLogicalOperators | RowFilterUnaryOperators | RowFilterExistenceOperators;
9
+ export type RowFilterOptions = FindRowRelationalFilterOptions | FindRowArrayFilterOptions | FindRowSetFilterOptions | FindRowLogicalFilterOptions | FindRowUnaryFilterOptions | FindRowExistenceFilterOptions;
10
+ export type RowNonRelationPropertyFilterOptions = FindRowRelationalFilterOptions | FindRowArrayFilterOptions | FindRowSetFilterOptions | FindRowUnaryFilterOptions;
9
11
  export type ColumnSelectOptions = string | ColumnNameWithTableName;
10
12
  export type ColumnNameWithTableName = {
11
13
  name: string;
@@ -24,6 +26,12 @@ export interface FindRowRelationalFilterOptions {
24
26
  operator: RowFilterRelationalOperators;
25
27
  value: any;
26
28
  }
29
+ export interface FindRowArrayFilterOptions {
30
+ field: ColumnSelectOptions;
31
+ operator: RowFilterArrayOperators;
32
+ value: any[];
33
+ itemType?: string;
34
+ }
27
35
  export interface FindRowSetFilterOptions {
28
36
  field: ColumnSelectOptions;
29
37
  operator: RowFilterSetOperators;
package/dist/index.js CHANGED
@@ -182,6 +182,26 @@ class DataAccessor {
182
182
  }
183
183
  }
184
184
 
185
+ const pgPropertyTypeColumnMap = {
186
+ integer: "int4",
187
+ long: "int8",
188
+ float: "float4",
189
+ double: "float8",
190
+ decimal: "decimal",
191
+ text: "text",
192
+ boolean: "bool",
193
+ date: "date",
194
+ time: "time",
195
+ datetime: "timestamptz",
196
+ json: "jsonb",
197
+ option: "text",
198
+ "option[]": "text[]",
199
+ file: "jsonb",
200
+ "file[]": "jsonb",
201
+ image: "jsonb",
202
+ "image[]": "jsonb",
203
+ };
204
+
185
205
  const objLeftQuoteChar = '"';
186
206
  const objRightQuoteChar = '"';
187
207
  const relationalOperatorsMap = new Map([
@@ -392,26 +412,27 @@ class QueryBuilder {
392
412
  const { entity } = options;
393
413
  let command = "INSERT INTO ";
394
414
  command += this.quoteTable(model);
395
- const propertyNames = Object.keys(entity);
415
+ const columnNames = Object.keys(entity);
396
416
  let values = "";
397
- propertyNames.forEach((propertyName, index) => {
417
+ columnNames.forEach((columnName, index) => {
398
418
  if (index) {
399
419
  values += ", ";
400
420
  }
401
421
  let property = null;
402
422
  if (model) {
403
- property = lodash.find(model.properties, (e) => e.code === propertyName);
423
+ property = lodash.find(model.properties, (e) => (e.columnName || e.code) === columnName);
404
424
  }
405
- if (property && property.type === "json") {
406
- params.push(JSON.stringify(entity[propertyName]));
425
+ const columnType = property ? pgPropertyTypeColumnMap[property.type] : null;
426
+ if (columnType === "jsonb") {
427
+ params.push(JSON.stringify(entity[columnName]));
407
428
  values += `$${params.length}::jsonb`;
408
429
  }
409
430
  else {
410
- params.push(entity[propertyName]);
431
+ params.push(entity[columnName]);
411
432
  values += `$${params.length}`;
412
433
  }
413
434
  });
414
- command += ` (${propertyNames.map(this.quoteObject).join(", ")})`;
435
+ command += ` (${columnNames.map(this.quoteObject).join(", ")})`;
415
436
  command += ` VALUES (${values}) RETURNING *`;
416
437
  return {
417
438
  command,
@@ -431,22 +452,24 @@ class QueryBuilder {
431
452
  let command = "UPDATE ";
432
453
  command += this.quoteTable(model);
433
454
  command += " SET ";
434
- const propertyNames = Object.keys(entity);
435
- propertyNames.forEach((propertyName, index) => {
455
+ const columnNames = Object.keys(entity);
456
+ columnNames.forEach((columnName, index) => {
436
457
  if (index) {
437
458
  command += ", ";
438
459
  }
460
+ command += `${this.quoteObject(columnName)}=`;
439
461
  let property = null;
440
462
  if (model) {
441
- property = lodash.find(model.properties, (e) => (e.columnName || e.code) === propertyName);
463
+ property = lodash.find(model.properties, (e) => (e.columnName || e.code) === columnName);
442
464
  }
443
- if (property && property.type === "json") {
444
- params.push(JSON.stringify(entity[propertyName]));
445
- command += `${this.quoteObject(propertyName)}=$${params.length}::jsonb`;
465
+ const columnType = property ? pgPropertyTypeColumnMap[property.type] : null;
466
+ if (columnType === "jsonb") {
467
+ params.push(JSON.stringify(entity[columnName]));
468
+ command += `$${params.length}::jsonb`;
446
469
  }
447
470
  else {
448
- params.push(entity[propertyName]);
449
- command += `${this.quoteObject(propertyName)}=$${params.length}`;
471
+ params.push(entity[columnName]);
472
+ command += `$${params.length}`;
450
473
  }
451
474
  });
452
475
  if (filters && filters.length) {
@@ -530,6 +553,12 @@ function buildFilterQuery(level, ctx, filter) {
530
553
  else if (operator === "notEndsWith") {
531
554
  return buildNotEndsWithFilterQuery(ctx, filter);
532
555
  }
556
+ else if (operator === "arrayContains") {
557
+ return buildArrayContainsFilterQuery(ctx, filter);
558
+ }
559
+ else if (operator === "arrayOverlap") {
560
+ return buildArrayOverlapFilterQuery(ctx, filter);
561
+ }
533
562
  else {
534
563
  throw new Error(`Filter operator '${operator}' is not supported.`);
535
564
  }
@@ -645,6 +674,26 @@ function buildRelationalFilterQuery(ctx, filter) {
645
674
  }
646
675
  return command;
647
676
  }
677
+ function buildArrayContainsFilterQuery(ctx, filter) {
678
+ let command = ctx.builder.quoteColumn(ctx.model, filter.field, ctx.emitTableAlias);
679
+ command += " @> ";
680
+ if (ctx.paramToLiteral) ;
681
+ else {
682
+ ctx.params.push(filter.value);
683
+ command += "$" + ctx.params.length;
684
+ }
685
+ return command;
686
+ }
687
+ function buildArrayOverlapFilterQuery(ctx, filter) {
688
+ let command = ctx.builder.quoteColumn(ctx.model, filter.field, ctx.emitTableAlias);
689
+ command += " && ";
690
+ if (ctx.paramToLiteral) ;
691
+ else {
692
+ ctx.params.push(filter.value);
693
+ command += "$" + ctx.params.length;
694
+ }
695
+ return command;
696
+ }
648
697
  function formatValueToSqlLiteral(value) {
649
698
  if (lodash.isNull(value) || lodash.isUndefined(value)) {
650
699
  return "null";
@@ -2618,12 +2667,18 @@ async function convertEntityFiltersToRowFilters(server, model, baseModel, filter
2618
2667
  }
2619
2668
  else {
2620
2669
  const filterField = filter.field;
2621
- let property = getEntityProperty(server, model, (property) => {
2622
- return property.code === filterField;
2623
- });
2670
+ let property = getEntityPropertyByCode(server, model, filterField);
2624
2671
  let columnName = "";
2625
2672
  if (property) {
2626
- columnName = property.columnName || property.code;
2673
+ if (isOneRelationProperty(property)) {
2674
+ columnName = property.targetIdColumnName;
2675
+ }
2676
+ else if (isManyRelationProperty(property)) {
2677
+ throw new Error(`Operator "${operator}" is not supported on many-relation property "${property.code}"`);
2678
+ }
2679
+ else {
2680
+ columnName = property.columnName || property.code;
2681
+ }
2627
2682
  }
2628
2683
  else {
2629
2684
  property = getEntityProperty(server, model, (property) => {
@@ -4336,21 +4391,7 @@ function generateTableIndexDDL(queryBuilder, server, model, index) {
4336
4391
  ddl += ` WHERE ${queryBuilder.buildFiltersExpression(model, index.conditions)}`;
4337
4392
  }
4338
4393
  return ddl;
4339
- }
4340
- const pgPropertyTypeColumnMap = {
4341
- integer: "int4",
4342
- long: "int8",
4343
- float: "float4",
4344
- double: "float8",
4345
- decimal: "decimal",
4346
- text: "text",
4347
- boolean: "bool",
4348
- date: "date",
4349
- time: "time",
4350
- datetime: "timestamptz",
4351
- json: "jsonb",
4352
- option: "text",
4353
- };
4394
+ }
4354
4395
 
4355
4396
  function mergeInput(defaultInput, input, fixedInput) {
4356
4397
  return lodash.mergeWith({}, defaultInput, input, fixedInput, doNotMergeArray);
package/dist/types.d.ts CHANGED
@@ -271,7 +271,7 @@ export interface RpdDataModelProperty {
271
271
  */
272
272
  linkSchema?: string;
273
273
  }
274
- export type RpdDataPropertyTypes = "integer" | "long" | "float" | "double" | "decimal" | "text" | "boolean" | "date" | "time" | "datetime" | "json" | "relation" | "relation[]" | "option";
274
+ export type RpdDataPropertyTypes = "integer" | "long" | "float" | "double" | "decimal" | "text" | "boolean" | "date" | "time" | "datetime" | "json" | "relation" | "relation[]" | "option" | "option[]" | "file" | "file[]" | "image" | "image[]";
275
275
  /**
276
276
  * 数据字典
277
277
  */
@@ -359,13 +359,14 @@ export interface IRpdDataAccessor<T = any> {
359
359
  deleteById(id: any): Promise<void>;
360
360
  }
361
361
  export type EntityFilterRelationalOperators = "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "contains" | "notContains" | "containsCS" | "notContainsCS" | "startsWith" | "notStartsWith" | "endsWith" | "notEndsWith";
362
+ export type EntityFilterArrayOperators = "arrayContains" | "arrayOverlap";
362
363
  export type EntityFilterSetOperators = "in" | "notIn";
363
364
  export type EntityFilterLogicalOperators = "or" | "and";
364
365
  export type EntityFilterUnaryOperators = "null" | "notNull";
365
366
  export type EntityFilterExistenceOperators = "exists" | "notExists";
366
- export type EntityFilterOperators = EntityFilterRelationalOperators | EntityFilterSetOperators | EntityFilterLogicalOperators | EntityFilterUnaryOperators | EntityFilterExistenceOperators;
367
- export type EntityFilterOptions = FindEntityRelationalFilterOptions | FindEntitySetFilterOptions | FindEntityLogicalFilterOptions | FindEntityUnaryFilterOptions | FindEntityExistenceFilterOptions;
368
- export type EntityNonRelationPropertyFilterOptions = FindEntityRelationalFilterOptions | FindEntitySetFilterOptions | FindEntityUnaryFilterOptions;
367
+ export type EntityFilterOperators = EntityFilterRelationalOperators | EntityFilterArrayOperators | EntityFilterSetOperators | EntityFilterLogicalOperators | EntityFilterUnaryOperators | EntityFilterExistenceOperators;
368
+ export type EntityFilterOptions = FindEntityRelationalFilterOptions | FindEntityArrayFilterOptions | FindEntitySetFilterOptions | FindEntityLogicalFilterOptions | FindEntityUnaryFilterOptions | FindEntityExistenceFilterOptions;
369
+ export type EntityNonRelationPropertyFilterOptions = FindEntityRelationalFilterOptions | FindEntityArrayFilterOptions | FindEntitySetFilterOptions | FindEntityUnaryFilterOptions;
369
370
  export interface FindEntityOptions {
370
371
  routeContext?: RouteContext;
371
372
  filters?: EntityFilterOptions[];
@@ -388,6 +389,12 @@ export interface FindEntityRelationalFilterOptions {
388
389
  operator: EntityFilterRelationalOperators;
389
390
  value: any;
390
391
  }
392
+ export interface FindEntityArrayFilterOptions {
393
+ field: string;
394
+ operator: EntityFilterArrayOperators;
395
+ value: any[];
396
+ itemType?: string;
397
+ }
391
398
  export interface FindEntitySetFilterOptions {
392
399
  field: string;
393
400
  operator: EntityFilterSetOperators;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruiapp/rapid-core",
3
- "version": "0.1.74",
3
+ "version": "0.1.76",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,22 @@
1
+ import { RpdDataPropertyTypes } from "~/types";
2
+ import { DataAccessPgColumnTypes } from "./dataAccessTypes";
3
+
4
+ export const pgPropertyTypeColumnMap: Record<Exclude<RpdDataPropertyTypes, "relation" | "relation[]">, DataAccessPgColumnTypes> = {
5
+ integer: "int4",
6
+ long: "int8",
7
+ float: "float4",
8
+ double: "float8",
9
+ decimal: "decimal",
10
+ text: "text",
11
+ boolean: "bool",
12
+ date: "date",
13
+ time: "time",
14
+ datetime: "timestamptz",
15
+ json: "jsonb",
16
+ option: "text",
17
+ "option[]": "text[]",
18
+ file: "jsonb",
19
+ "file[]": "jsonb",
20
+ image: "jsonb",
21
+ "image[]": "jsonb",
22
+ };
@@ -1,3 +1,17 @@
1
+ export type DataAccessPgColumnTypes =
2
+ | "int4"
3
+ | "int8"
4
+ | "float4"
5
+ | "float8"
6
+ | "decimal"
7
+ | "text"
8
+ | "text[]"
9
+ | "bool"
10
+ | "date"
11
+ | "time"
12
+ | "timestamptz"
13
+ | "jsonb";
14
+
1
15
  export type RowFilterRelationalOperators =
2
16
  | "eq"
3
17
  | "ne"
@@ -14,6 +28,8 @@ export type RowFilterRelationalOperators =
14
28
  | "endsWith"
15
29
  | "notEndsWith";
16
30
 
31
+ export type RowFilterArrayOperators = "arrayContains" | "arrayOverlap";
32
+
17
33
  export type RowFilterSetOperators = "in" | "notIn";
18
34
 
19
35
  export type RowFilterLogicalOperators = "or" | "and";
@@ -24,6 +40,7 @@ export type RowFilterExistenceOperators = "exists" | "notExists";
24
40
 
25
41
  export type RowFilterOperators =
26
42
  | RowFilterRelationalOperators
43
+ | RowFilterArrayOperators
27
44
  | RowFilterSetOperators
28
45
  | RowFilterLogicalOperators
29
46
  | RowFilterUnaryOperators
@@ -31,12 +48,17 @@ export type RowFilterOperators =
31
48
 
32
49
  export type RowFilterOptions =
33
50
  | FindRowRelationalFilterOptions
51
+ | FindRowArrayFilterOptions
34
52
  | FindRowSetFilterOptions
35
53
  | FindRowLogicalFilterOptions
36
54
  | FindRowUnaryFilterOptions
37
55
  | FindRowExistenceFilterOptions;
38
56
 
39
- export type RowNonRelationPropertyFilterOptions = FindRowRelationalFilterOptions | FindRowSetFilterOptions | FindRowUnaryFilterOptions;
57
+ export type RowNonRelationPropertyFilterOptions =
58
+ | FindRowRelationalFilterOptions
59
+ | FindRowArrayFilterOptions
60
+ | FindRowSetFilterOptions
61
+ | FindRowUnaryFilterOptions;
40
62
 
41
63
  export type ColumnSelectOptions = string | ColumnNameWithTableName;
42
64
 
@@ -62,6 +84,13 @@ export interface FindRowRelationalFilterOptions {
62
84
  value: any;
63
85
  }
64
86
 
87
+ export interface FindRowArrayFilterOptions {
88
+ field: ColumnSelectOptions;
89
+ operator: RowFilterArrayOperators;
90
+ value: any[];
91
+ itemType?: string;
92
+ }
93
+
65
94
  export interface FindRowSetFilterOptions {
66
95
  field: ColumnSelectOptions;
67
96
  operator: RowFilterSetOperators;
@@ -31,6 +31,7 @@ import {
31
31
  getEntityPropertyByCode,
32
32
  getEntityPropertyByFieldName,
33
33
  isManyRelationProperty,
34
+ isOneRelationProperty,
34
35
  isRelationProperty,
35
36
  } from "../helpers/metaHelper";
36
37
  import { ColumnSelectOptions, CountRowOptions, FindRowOptions, FindRowOrderByOptions, RowFilterOptions } from "./dataAccessTypes";
@@ -520,13 +521,17 @@ async function convertEntityFiltersToRowFilters(
520
521
  }
521
522
  } else {
522
523
  const filterField = (filter as EntityNonRelationPropertyFilterOptions).field;
523
- let property: RpdDataModelProperty = getEntityProperty(server, model, (property) => {
524
- return property.code === filterField;
525
- });
524
+ let property: RpdDataModelProperty = getEntityPropertyByCode(server, model, filterField);
526
525
 
527
526
  let columnName = "";
528
527
  if (property) {
529
- columnName = property.columnName || property.code;
528
+ if (isOneRelationProperty(property)) {
529
+ columnName = property.targetIdColumnName;
530
+ } else if (isManyRelationProperty(property)) {
531
+ throw new Error(`Operator "${operator}" is not supported on many-relation property "${property.code}"`);
532
+ } else {
533
+ columnName = property.columnName || property.code;
534
+ }
530
535
  } else {
531
536
  property = getEntityProperty(server, model, (property) => {
532
537
  return property.columnName === filterField;
@@ -27,6 +27,8 @@ import * as listMetaRoutes from "./actionHandlers/listMetaRoutes";
27
27
  import * as getMetaModelDetail from "./actionHandlers/getMetaModelDetail";
28
28
  import { find, isString, map } from "lodash";
29
29
  import { getEntityPropertiesIncludingBase, getEntityPropertyByCode, isOneRelationProperty, isRelationProperty } from "~/helpers/metaHelper";
30
+ import { DataAccessPgColumnTypes } from "~/dataAccess/dataAccessTypes";
31
+ import { pgPropertyTypeColumnMap } from "~/dataAccess/columnTypeMapper";
30
32
 
31
33
  class MetaManager implements RapidPlugin {
32
34
  get code(): string {
@@ -484,18 +486,3 @@ function generateTableIndexDDL(queryBuilder: IQueryBuilder, server: IRpdServer,
484
486
 
485
487
  return ddl;
486
488
  }
487
-
488
- const pgPropertyTypeColumnMap: Partial<Record<RpdDataPropertyTypes, string>> = {
489
- integer: "int4",
490
- long: "int8",
491
- float: "float4",
492
- double: "float8",
493
- decimal: "decimal",
494
- text: "text",
495
- boolean: "bool",
496
- date: "date",
497
- time: "time",
498
- datetime: "timestamptz",
499
- json: "jsonb",
500
- option: "text",
501
- };
@@ -13,7 +13,10 @@ import {
13
13
  UpdateRowOptions,
14
14
  ColumnSelectOptions,
15
15
  ColumnNameWithTableName,
16
+ DataAccessPgColumnTypes,
17
+ FindRowArrayFilterOptions,
16
18
  } from "~/dataAccess/dataAccessTypes";
19
+ import { pgPropertyTypeColumnMap } from "~/dataAccess/columnTypeMapper";
17
20
 
18
21
  const objLeftQuoteChar = '"';
19
22
  const objRightQuoteChar = '"';
@@ -274,28 +277,28 @@ export default class QueryBuilder {
274
277
 
275
278
  command += this.quoteTable(model);
276
279
 
277
- const propertyNames: string[] = Object.keys(entity);
280
+ const columnNames: string[] = Object.keys(entity);
278
281
  let values = "";
279
- propertyNames.forEach((propertyName, index) => {
282
+ columnNames.forEach((columnName, index) => {
280
283
  if (index) {
281
284
  values += ", ";
282
285
  }
283
286
 
284
287
  let property: RpdDataModelProperty | null = null;
285
288
  if (model) {
286
- property = find(model.properties, (e: RpdDataModelProperty) => e.code === propertyName);
289
+ property = find(model.properties, (e: RpdDataModelProperty) => (e.columnName || e.code) === columnName);
287
290
  }
288
-
289
- if (property && property.type === "json") {
290
- params.push(JSON.stringify(entity[propertyName]));
291
+ const columnType: DataAccessPgColumnTypes | null = property ? pgPropertyTypeColumnMap[property.type] : null;
292
+ if (columnType === "jsonb") {
293
+ params.push(JSON.stringify(entity[columnName]));
291
294
  values += `$${params.length}::jsonb`;
292
295
  } else {
293
- params.push(entity[propertyName]);
296
+ params.push(entity[columnName]);
294
297
  values += `$${params.length}`;
295
298
  }
296
299
  });
297
300
 
298
- command += ` (${propertyNames.map(this.quoteObject).join(", ")})`;
301
+ command += ` (${columnNames.map(this.quoteObject).join(", ")})`;
299
302
  command += ` VALUES (${values}) RETURNING *`;
300
303
 
301
304
  return {
@@ -319,23 +322,25 @@ export default class QueryBuilder {
319
322
  command += this.quoteTable(model);
320
323
 
321
324
  command += " SET ";
322
- const propertyNames: string[] = Object.keys(entity);
323
- propertyNames.forEach((propertyName, index) => {
325
+ const columnNames: string[] = Object.keys(entity);
326
+ columnNames.forEach((columnName, index) => {
324
327
  if (index) {
325
328
  command += ", ";
326
329
  }
327
330
 
331
+ command += `${this.quoteObject(columnName)}=`;
332
+
328
333
  let property: RpdDataModelProperty | null = null;
329
334
  if (model) {
330
- property = find(model.properties, (e: RpdDataModelProperty) => (e.columnName || e.code) === propertyName);
335
+ property = find(model.properties, (e: RpdDataModelProperty) => (e.columnName || e.code) === columnName);
331
336
  }
332
-
333
- if (property && property.type === "json") {
334
- params.push(JSON.stringify(entity[propertyName]));
335
- command += `${this.quoteObject(propertyName)}=$${params.length}::jsonb`;
337
+ const columnType: DataAccessPgColumnTypes | null = property ? pgPropertyTypeColumnMap[property.type] : null;
338
+ if (columnType === "jsonb") {
339
+ params.push(JSON.stringify(entity[columnName]));
340
+ command += `$${params.length}::jsonb`;
336
341
  } else {
337
- params.push(entity[propertyName]);
338
- command += `${this.quoteObject(propertyName)}=$${params.length}`;
342
+ params.push(entity[columnName]);
343
+ command += `$${params.length}`;
339
344
  }
340
345
  });
341
346
 
@@ -420,6 +425,10 @@ function buildFilterQuery(level: number, ctx: BuildQueryContext, filter: RowFilt
420
425
  return buildEndsWithFilterQuery(ctx, filter);
421
426
  } else if (operator === "notEndsWith") {
422
427
  return buildNotEndsWithFilterQuery(ctx, filter);
428
+ } else if (operator === "arrayContains") {
429
+ return buildArrayContainsFilterQuery(ctx, filter);
430
+ } else if (operator === "arrayOverlap") {
431
+ return buildArrayOverlapFilterQuery(ctx, filter);
423
432
  } else {
424
433
  throw new Error(`Filter operator '${operator}' is not supported.`);
425
434
  }
@@ -573,6 +582,36 @@ function buildRelationalFilterQuery(ctx: BuildQueryContext, filter: FindRowRelat
573
582
  return command;
574
583
  }
575
584
 
585
+ function buildArrayContainsFilterQuery(ctx: BuildQueryContext, filter: FindRowArrayFilterOptions) {
586
+ let command = ctx.builder.quoteColumn(ctx.model, filter.field, ctx.emitTableAlias);
587
+
588
+ command += " @> ";
589
+
590
+ if (ctx.paramToLiteral) {
591
+ // TODO: implement it
592
+ } else {
593
+ ctx.params.push(filter.value);
594
+ command += "$" + ctx.params.length;
595
+ }
596
+
597
+ return command;
598
+ }
599
+
600
+ function buildArrayOverlapFilterQuery(ctx: BuildQueryContext, filter: FindRowArrayFilterOptions) {
601
+ let command = ctx.builder.quoteColumn(ctx.model, filter.field, ctx.emitTableAlias);
602
+
603
+ command += " && ";
604
+
605
+ if (ctx.paramToLiteral) {
606
+ // TODO: implement it
607
+ } else {
608
+ ctx.params.push(filter.value);
609
+ command += "$" + ctx.params.length;
610
+ }
611
+
612
+ return command;
613
+ }
614
+
576
615
  function formatValueToSqlLiteral(value: any) {
577
616
  if (isNull(value) || isUndefined(value)) {
578
617
  return "null";
package/src/types.ts CHANGED
@@ -316,7 +316,12 @@ export type RpdDataPropertyTypes =
316
316
  | "json"
317
317
  | "relation"
318
318
  | "relation[]"
319
- | "option";
319
+ | "option"
320
+ | "option[]"
321
+ | "file"
322
+ | "file[]"
323
+ | "image"
324
+ | "image[]";
320
325
 
321
326
  /**
322
327
  * 数据字典
@@ -444,6 +449,8 @@ export type EntityFilterRelationalOperators =
444
449
  | "endsWith"
445
450
  | "notEndsWith";
446
451
 
452
+ export type EntityFilterArrayOperators = "arrayContains" | "arrayOverlap";
453
+
447
454
  export type EntityFilterSetOperators = "in" | "notIn";
448
455
 
449
456
  export type EntityFilterLogicalOperators = "or" | "and";
@@ -454,6 +461,7 @@ export type EntityFilterExistenceOperators = "exists" | "notExists";
454
461
 
455
462
  export type EntityFilterOperators =
456
463
  | EntityFilterRelationalOperators
464
+ | EntityFilterArrayOperators
457
465
  | EntityFilterSetOperators
458
466
  | EntityFilterLogicalOperators
459
467
  | EntityFilterUnaryOperators
@@ -461,12 +469,17 @@ export type EntityFilterOperators =
461
469
 
462
470
  export type EntityFilterOptions =
463
471
  | FindEntityRelationalFilterOptions
472
+ | FindEntityArrayFilterOptions
464
473
  | FindEntitySetFilterOptions
465
474
  | FindEntityLogicalFilterOptions
466
475
  | FindEntityUnaryFilterOptions
467
476
  | FindEntityExistenceFilterOptions;
468
477
 
469
- export type EntityNonRelationPropertyFilterOptions = FindEntityRelationalFilterOptions | FindEntitySetFilterOptions | FindEntityUnaryFilterOptions;
478
+ export type EntityNonRelationPropertyFilterOptions =
479
+ | FindEntityRelationalFilterOptions
480
+ | FindEntityArrayFilterOptions
481
+ | FindEntitySetFilterOptions
482
+ | FindEntityUnaryFilterOptions;
470
483
 
471
484
  export interface FindEntityOptions {
472
485
  routeContext?: RouteContext;
@@ -493,6 +506,13 @@ export interface FindEntityRelationalFilterOptions {
493
506
  value: any;
494
507
  }
495
508
 
509
+ export interface FindEntityArrayFilterOptions {
510
+ field: string;
511
+ operator: EntityFilterArrayOperators;
512
+ value: any[];
513
+ itemType?: string;
514
+ }
515
+
496
516
  export interface FindEntitySetFilterOptions {
497
517
  field: string;
498
518
  operator: EntityFilterSetOperators;