@ruiapp/rapid-core 0.1.62 → 0.1.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dataAccess/dataAccessTypes.d.ts +7 -7
- package/dist/dataAccess/entityManager.d.ts +15 -1
- package/dist/index.js +116 -38
- package/dist/queryBuilder/queryBuilder.d.ts +2 -2
- package/dist/types.d.ts +8 -1
- package/package.json +1 -1
- package/src/dataAccess/dataAccessTypes.ts +36 -13
- package/src/dataAccess/entityManager.ts +147 -42
- package/src/queryBuilder/queryBuilder.ts +15 -15
- package/src/types.ts +60 -6
|
@@ -6,7 +6,7 @@ export type RowFilterExistenceOperators = "exists" | "notExists";
|
|
|
6
6
|
export type RowFilterOperators = RowFilterRelationalOperators | RowFilterSetOperators | RowFilterLogicalOperators | RowFilterUnaryOperators | RowFilterExistenceOperators;
|
|
7
7
|
export type RowFilterOptions = FindRowRelationalFilterOptions | FindRowSetFilterOptions | FindRowLogicalFilterOptions | FindRowUnaryFilterOptions | FindRowExistenceFilterOptions;
|
|
8
8
|
export type RowNonRelationPropertyFilterOptions = FindRowRelationalFilterOptions | FindRowSetFilterOptions | FindRowUnaryFilterOptions;
|
|
9
|
-
export type
|
|
9
|
+
export type ColumnSelectOptions = string | ColumnNameWithTableName;
|
|
10
10
|
export type ColumnNameWithTableName = {
|
|
11
11
|
name: string;
|
|
12
12
|
tableName?: string;
|
|
@@ -15,16 +15,16 @@ export interface FindRowOptions {
|
|
|
15
15
|
filters?: RowFilterOptions[];
|
|
16
16
|
orderBy?: FindRowOrderByOptions[];
|
|
17
17
|
pagination?: FindRowPaginationOptions;
|
|
18
|
-
fields?:
|
|
18
|
+
fields?: ColumnSelectOptions[];
|
|
19
19
|
keepNonPropertyFields?: boolean;
|
|
20
20
|
}
|
|
21
21
|
export interface FindRowRelationalFilterOptions {
|
|
22
|
-
field:
|
|
22
|
+
field: ColumnSelectOptions;
|
|
23
23
|
operator: RowFilterRelationalOperators;
|
|
24
24
|
value: any;
|
|
25
25
|
}
|
|
26
26
|
export interface FindRowSetFilterOptions {
|
|
27
|
-
field:
|
|
27
|
+
field: ColumnSelectOptions;
|
|
28
28
|
operator: RowFilterSetOperators;
|
|
29
29
|
value: any[];
|
|
30
30
|
itemType?: string;
|
|
@@ -34,11 +34,11 @@ export interface FindRowLogicalFilterOptions {
|
|
|
34
34
|
filters: RowFilterOptions[];
|
|
35
35
|
}
|
|
36
36
|
export interface FindRowUnaryFilterOptions {
|
|
37
|
-
field:
|
|
37
|
+
field: ColumnSelectOptions;
|
|
38
38
|
operator: RowFilterUnaryOperators;
|
|
39
39
|
}
|
|
40
40
|
export interface FindRowExistenceFilterOptions {
|
|
41
|
-
field:
|
|
41
|
+
field: ColumnSelectOptions;
|
|
42
42
|
operator: RowFilterExistenceOperators;
|
|
43
43
|
filters: RowFilterOptions[];
|
|
44
44
|
}
|
|
@@ -48,7 +48,7 @@ export interface FindRowPaginationOptions {
|
|
|
48
48
|
withoutTotal?: boolean;
|
|
49
49
|
}
|
|
50
50
|
export interface FindRowOrderByOptions {
|
|
51
|
-
field:
|
|
51
|
+
field: ColumnSelectOptions;
|
|
52
52
|
desc?: boolean;
|
|
53
53
|
}
|
|
54
54
|
export interface CountRowOptions {
|
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import { AddEntityRelationsOptions, CountEntityOptions, CountEntityResult, CreateEntityOptions, DeleteEntityByIdOptions, FindEntityByIdOptions, FindEntityOptions, IRpdDataAccessor, RemoveEntityRelationsOptions, RpdDataModel, UpdateEntityByIdOptions } from "../types";
|
|
1
|
+
import { AddEntityRelationsOptions, CountEntityOptions, CountEntityResult, CreateEntityOptions, DeleteEntityByIdOptions, FindEntityByIdOptions, FindEntityOptions, FindEntitySelectRelationOptions, IRpdDataAccessor, RemoveEntityRelationsOptions, RpdDataModel, RpdDataModelProperty, UpdateEntityByIdOptions } from "../types";
|
|
2
2
|
import { IRpdServer, RapidPlugin } from "../core/server";
|
|
3
|
+
export type FindOneRelationEntitiesOptions = {
|
|
4
|
+
server: IRpdServer;
|
|
5
|
+
mainModel: RpdDataModel;
|
|
6
|
+
relationProperty: RpdDataModelProperty;
|
|
7
|
+
relationEntityIds: any[];
|
|
8
|
+
selectRelationOptions?: FindEntitySelectRelationOptions;
|
|
9
|
+
};
|
|
10
|
+
export type FindManyRelationEntitiesOptions = {
|
|
11
|
+
server: IRpdServer;
|
|
12
|
+
mainModel: RpdDataModel;
|
|
13
|
+
relationProperty: RpdDataModelProperty;
|
|
14
|
+
mainEntityIds: any[];
|
|
15
|
+
selectRelationOptions?: FindEntitySelectRelationOptions;
|
|
16
|
+
};
|
|
3
17
|
export default class EntityManager<TEntity = any> {
|
|
4
18
|
#private;
|
|
5
19
|
constructor(server: IRpdServer, dataAccessor: IRpdDataAccessor);
|
package/dist/index.js
CHANGED
|
@@ -277,9 +277,11 @@ class QueryBuilder {
|
|
|
277
277
|
command += `${this.quoteObject(derivedModel.tableName)}.* FROM `;
|
|
278
278
|
}
|
|
279
279
|
else {
|
|
280
|
-
command += columns
|
|
280
|
+
command += columns
|
|
281
|
+
.map((column) => {
|
|
281
282
|
return this.quoteColumn(column, ctx.emitTableAlias);
|
|
282
|
-
})
|
|
283
|
+
})
|
|
284
|
+
.join(", ");
|
|
283
285
|
command += " FROM ";
|
|
284
286
|
}
|
|
285
287
|
command += `${this.quoteTable(derivedModel)} LEFT JOIN ${this.quoteTable(baseModel)} ON ${this.quoteObject(derivedModel.tableName)}.id = ${this.quoteObject(baseModel.tableName)}.id`;
|
|
@@ -2001,16 +2003,18 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
2001
2003
|
singularCode: model.base,
|
|
2002
2004
|
});
|
|
2003
2005
|
}
|
|
2004
|
-
let
|
|
2006
|
+
let propertiesToSelect;
|
|
2007
|
+
let relationOptions = options.relations || {};
|
|
2008
|
+
let relationPropertyCodes = Object.keys(relationOptions) || [];
|
|
2005
2009
|
if (!options.properties || !options.properties.length) {
|
|
2006
|
-
|
|
2010
|
+
propertiesToSelect = getEntityPropertiesIncludingBase(server, model).filter((property) => !isRelationProperty(property) || relationPropertyCodes.includes(property.code));
|
|
2007
2011
|
}
|
|
2008
2012
|
else {
|
|
2009
|
-
|
|
2013
|
+
propertiesToSelect = getEntityPropertiesIncludingBase(server, model).filter((property) => options.properties.includes(property.code) || relationPropertyCodes.includes(property.code));
|
|
2010
2014
|
}
|
|
2011
2015
|
const columnsToSelect = [];
|
|
2012
2016
|
const relationPropertiesToSelect = [];
|
|
2013
|
-
lodash.forEach(
|
|
2017
|
+
lodash.forEach(propertiesToSelect, (property) => {
|
|
2014
2018
|
if (isRelationProperty(property)) {
|
|
2015
2019
|
relationPropertiesToSelect.push(property);
|
|
2016
2020
|
if (property.relation === "one" && !property.linkTableName) {
|
|
@@ -2058,6 +2062,31 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
2058
2062
|
}
|
|
2059
2063
|
});
|
|
2060
2064
|
}
|
|
2065
|
+
if (options.extraColumnsToSelect) {
|
|
2066
|
+
lodash.forEach(options.extraColumnsToSelect, (extraColumnToSelect) => {
|
|
2067
|
+
const columnSelectOptionExists = lodash.find(columnsToSelect, (item) => {
|
|
2068
|
+
if (typeof item === "string") {
|
|
2069
|
+
if (typeof extraColumnToSelect === "string") {
|
|
2070
|
+
return item === extraColumnToSelect;
|
|
2071
|
+
}
|
|
2072
|
+
else {
|
|
2073
|
+
return item == extraColumnToSelect.name;
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
else {
|
|
2077
|
+
if (typeof extraColumnToSelect === "string") {
|
|
2078
|
+
return item.name === extraColumnToSelect;
|
|
2079
|
+
}
|
|
2080
|
+
else {
|
|
2081
|
+
return item.name == extraColumnToSelect.name;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
});
|
|
2085
|
+
if (!columnSelectOptionExists) {
|
|
2086
|
+
columnsToSelect.push(extraColumnToSelect);
|
|
2087
|
+
}
|
|
2088
|
+
});
|
|
2089
|
+
}
|
|
2061
2090
|
const rowFilters = await convertEntityFiltersToRowFilters(server, model, baseModel, options.filters);
|
|
2062
2091
|
const findRowOptions = {
|
|
2063
2092
|
filters: rowFilters,
|
|
@@ -2074,27 +2103,45 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
2074
2103
|
for (const relationProperty of relationPropertiesToSelect) {
|
|
2075
2104
|
const isManyRelation = relationProperty.relation === "many";
|
|
2076
2105
|
if (relationProperty.linkTableName) {
|
|
2077
|
-
const
|
|
2078
|
-
if (!
|
|
2106
|
+
const relationModel = server.getModel({ singularCode: relationProperty.targetSingularCode });
|
|
2107
|
+
if (!relationModel) {
|
|
2079
2108
|
continue;
|
|
2080
2109
|
}
|
|
2081
2110
|
if (isManyRelation) {
|
|
2082
|
-
const relationLinks = await findManyRelationLinksViaLinkTable(
|
|
2111
|
+
const relationLinks = await findManyRelationLinksViaLinkTable({
|
|
2112
|
+
server,
|
|
2113
|
+
mainModel: relationModel,
|
|
2114
|
+
relationProperty,
|
|
2115
|
+
mainEntityIds: entityIds,
|
|
2116
|
+
selectRelationOptions: relationOptions[relationProperty.code],
|
|
2117
|
+
});
|
|
2083
2118
|
lodash.forEach(rows, (row) => {
|
|
2084
2119
|
row[relationProperty.code] = lodash.filter(relationLinks, (link) => {
|
|
2085
2120
|
return link[relationProperty.selfIdColumnName] == row["id"];
|
|
2086
|
-
}).map((link) => mapDbRowToEntity(server,
|
|
2121
|
+
}).map((link) => mapDbRowToEntity(server, relationModel, link.targetEntity, options.keepNonPropertyFields));
|
|
2087
2122
|
});
|
|
2088
2123
|
}
|
|
2089
2124
|
}
|
|
2090
2125
|
else {
|
|
2091
2126
|
let relatedEntities;
|
|
2092
2127
|
if (isManyRelation) {
|
|
2093
|
-
relatedEntities = await findManyRelatedEntitiesViaIdPropertyCode(
|
|
2128
|
+
relatedEntities = await findManyRelatedEntitiesViaIdPropertyCode({
|
|
2129
|
+
server,
|
|
2130
|
+
mainModel: model,
|
|
2131
|
+
relationProperty,
|
|
2132
|
+
mainEntityIds: entityIds,
|
|
2133
|
+
selectRelationOptions: relationOptions[relationProperty.code],
|
|
2134
|
+
});
|
|
2094
2135
|
}
|
|
2095
2136
|
else {
|
|
2096
2137
|
const targetEntityIds = lodash.uniq(lodash.reject(lodash.map(rows, (entity) => entity[relationProperty.targetIdColumnName]), isNullOrUndefined));
|
|
2097
|
-
relatedEntities = await findOneRelatedEntitiesViaIdPropertyCode(
|
|
2138
|
+
relatedEntities = await findOneRelatedEntitiesViaIdPropertyCode({
|
|
2139
|
+
server,
|
|
2140
|
+
mainModel: model,
|
|
2141
|
+
relationProperty,
|
|
2142
|
+
relationEntityIds: targetEntityIds,
|
|
2143
|
+
selectRelationOptions: relationOptions[relationProperty.code],
|
|
2144
|
+
});
|
|
2098
2145
|
}
|
|
2099
2146
|
const targetModel = server.getModel({
|
|
2100
2147
|
singularCode: relationProperty.targetSingularCode,
|
|
@@ -2354,68 +2401,99 @@ async function convertEntityFiltersToRowFilters(server, model, baseModel, filter
|
|
|
2354
2401
|
}
|
|
2355
2402
|
return replacedFilters;
|
|
2356
2403
|
}
|
|
2357
|
-
async function findManyRelationLinksViaLinkTable(
|
|
2404
|
+
async function findManyRelationLinksViaLinkTable(options) {
|
|
2405
|
+
const { server, relationProperty, mainModel: relationModel, mainEntityIds, selectRelationOptions } = options;
|
|
2358
2406
|
const command = `SELECT * FROM ${server.queryBuilder.quoteTable({
|
|
2359
2407
|
schema: relationProperty.linkSchema,
|
|
2360
2408
|
tableName: relationProperty.linkTableName,
|
|
2361
2409
|
})} WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName)} = ANY($1::int[])`;
|
|
2362
|
-
const params = [
|
|
2410
|
+
const params = [mainEntityIds];
|
|
2363
2411
|
const links = await server.queryDatabaseObject(command, params);
|
|
2364
2412
|
const targetEntityIds = links.map((link) => link[relationProperty.targetIdColumnName]);
|
|
2413
|
+
const dataAccessor = server.getDataAccessor({
|
|
2414
|
+
namespace: relationModel.namespace,
|
|
2415
|
+
singularCode: relationModel.singularCode,
|
|
2416
|
+
});
|
|
2365
2417
|
const findEntityOptions = {
|
|
2366
2418
|
filters: [
|
|
2367
2419
|
{
|
|
2368
|
-
field:
|
|
2369
|
-
name: "id",
|
|
2370
|
-
},
|
|
2420
|
+
field: "id",
|
|
2371
2421
|
operator: "in",
|
|
2372
2422
|
value: targetEntityIds,
|
|
2373
2423
|
},
|
|
2374
2424
|
],
|
|
2425
|
+
keepNonPropertyFields: true,
|
|
2375
2426
|
};
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2427
|
+
if (selectRelationOptions) {
|
|
2428
|
+
if (typeof selectRelationOptions !== "boolean") {
|
|
2429
|
+
if (selectRelationOptions.properties) {
|
|
2430
|
+
findEntityOptions.properties = ["id", ...selectRelationOptions.properties];
|
|
2431
|
+
}
|
|
2432
|
+
if (selectRelationOptions.relations) {
|
|
2433
|
+
findEntityOptions.relations = selectRelationOptions.relations;
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
const targetEntities = await findEntities(server, dataAccessor, findEntityOptions);
|
|
2381
2438
|
lodash.forEach(links, (link) => {
|
|
2382
2439
|
link.targetEntity = lodash.find(targetEntities, (e) => e["id"] == link[relationProperty.targetIdColumnName]);
|
|
2383
2440
|
});
|
|
2384
2441
|
return links;
|
|
2385
2442
|
}
|
|
2386
|
-
function findManyRelatedEntitiesViaIdPropertyCode(
|
|
2443
|
+
async function findManyRelatedEntitiesViaIdPropertyCode(options) {
|
|
2444
|
+
const { server, relationProperty, mainEntityIds, selectRelationOptions } = options;
|
|
2445
|
+
const dataAccessor = server.getDataAccessor({
|
|
2446
|
+
singularCode: relationProperty.targetSingularCode,
|
|
2447
|
+
});
|
|
2387
2448
|
const findEntityOptions = {
|
|
2388
2449
|
filters: [
|
|
2389
2450
|
{
|
|
2390
|
-
field:
|
|
2391
|
-
name: relationProperty.selfIdColumnName,
|
|
2392
|
-
},
|
|
2451
|
+
field: relationProperty.selfIdColumnName,
|
|
2393
2452
|
operator: "in",
|
|
2394
|
-
value:
|
|
2453
|
+
value: mainEntityIds,
|
|
2395
2454
|
},
|
|
2396
2455
|
],
|
|
2456
|
+
extraColumnsToSelect: [relationProperty.selfIdColumnName],
|
|
2457
|
+
keepNonPropertyFields: true,
|
|
2397
2458
|
};
|
|
2459
|
+
if (selectRelationOptions) {
|
|
2460
|
+
if (typeof selectRelationOptions !== "boolean") {
|
|
2461
|
+
if (selectRelationOptions.properties) {
|
|
2462
|
+
findEntityOptions.properties = ["id", ...selectRelationOptions.properties];
|
|
2463
|
+
}
|
|
2464
|
+
if (selectRelationOptions.relations) {
|
|
2465
|
+
findEntityOptions.relations = selectRelationOptions.relations;
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
return await findEntities(server, dataAccessor, findEntityOptions);
|
|
2470
|
+
}
|
|
2471
|
+
async function findOneRelatedEntitiesViaIdPropertyCode(options) {
|
|
2472
|
+
const { server, relationProperty, relationEntityIds, selectRelationOptions } = options;
|
|
2398
2473
|
const dataAccessor = server.getDataAccessor({
|
|
2399
2474
|
singularCode: relationProperty.targetSingularCode,
|
|
2400
2475
|
});
|
|
2401
|
-
return dataAccessor.find(findEntityOptions);
|
|
2402
|
-
}
|
|
2403
|
-
function findOneRelatedEntitiesViaIdPropertyCode(server, model, relationProperty, targetEntityIds) {
|
|
2404
2476
|
const findEntityOptions = {
|
|
2405
2477
|
filters: [
|
|
2406
2478
|
{
|
|
2407
|
-
field:
|
|
2408
|
-
name: "id",
|
|
2409
|
-
},
|
|
2479
|
+
field: "id",
|
|
2410
2480
|
operator: "in",
|
|
2411
|
-
value:
|
|
2481
|
+
value: relationEntityIds,
|
|
2412
2482
|
},
|
|
2413
2483
|
],
|
|
2484
|
+
keepNonPropertyFields: true,
|
|
2414
2485
|
};
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2486
|
+
if (selectRelationOptions) {
|
|
2487
|
+
if (typeof selectRelationOptions !== "boolean") {
|
|
2488
|
+
if (selectRelationOptions.properties) {
|
|
2489
|
+
findEntityOptions.properties = ["id", ...selectRelationOptions.properties];
|
|
2490
|
+
}
|
|
2491
|
+
if (selectRelationOptions.relations) {
|
|
2492
|
+
findEntityOptions.relations = selectRelationOptions.relations;
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
return await findEntities(server, dataAccessor, findEntityOptions);
|
|
2419
2497
|
}
|
|
2420
2498
|
async function createEntity(server, dataAccessor, options, plugin) {
|
|
2421
2499
|
const model = dataAccessor.getModel();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RpdDataModel, CreateEntityOptions, QuoteTableOptions, DatabaseQuery } from "../types";
|
|
2
|
-
import { CountRowOptions, DeleteRowOptions, FindRowOptions, RowFilterOptions, UpdateRowOptions,
|
|
2
|
+
import { CountRowOptions, DeleteRowOptions, FindRowOptions, RowFilterOptions, UpdateRowOptions, ColumnSelectOptions } from "../dataAccess/dataAccessTypes";
|
|
3
3
|
export interface BuildQueryContext {
|
|
4
4
|
builder: QueryBuilder;
|
|
5
5
|
params: any[];
|
|
@@ -13,7 +13,7 @@ export default class QueryBuilder {
|
|
|
13
13
|
constructor(options: InitQueryBuilderOptions);
|
|
14
14
|
quoteTable(options: QuoteTableOptions): string;
|
|
15
15
|
quoteObject(name: string): string;
|
|
16
|
-
quoteColumn(column:
|
|
16
|
+
quoteColumn(column: ColumnSelectOptions, emitTableAlias: boolean): string;
|
|
17
17
|
select(model: RpdDataModel, options: FindRowOptions): DatabaseQuery;
|
|
18
18
|
selectDerived(derivedModel: RpdDataModel, baseModel: RpdDataModel, options: FindRowOptions): DatabaseQuery;
|
|
19
19
|
count(model: RpdDataModel, options: CountRowOptions): DatabaseQuery;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RouteContext } from "./core/routeContext";
|
|
2
2
|
import { IRpdServer, RapidPlugin } from "./core/server";
|
|
3
|
-
import { CountRowOptions, FindRowOptions } from "./dataAccess/dataAccessTypes";
|
|
3
|
+
import { ColumnSelectOptions, CountRowOptions, FindRowOptions } from "./dataAccess/dataAccessTypes";
|
|
4
4
|
export type RapidServerConfig = {
|
|
5
5
|
baseUrl?: string;
|
|
6
6
|
sessionCookieName: string;
|
|
@@ -355,12 +355,15 @@ export interface FindEntityOptions {
|
|
|
355
355
|
orderBy?: FindEntityOrderByOptions[];
|
|
356
356
|
pagination?: FindEntityPaginationOptions;
|
|
357
357
|
properties?: string[];
|
|
358
|
+
relations?: Record<string, FindEntitySelectRelationOptions>;
|
|
359
|
+
extraColumnsToSelect?: ColumnSelectOptions[];
|
|
358
360
|
keepNonPropertyFields?: boolean;
|
|
359
361
|
}
|
|
360
362
|
export interface FindEntityByIdOptions {
|
|
361
363
|
routeContext?: RouteContext;
|
|
362
364
|
id: any;
|
|
363
365
|
properties?: string[];
|
|
366
|
+
relations?: Record<string, FindEntitySelectRelationOptions>;
|
|
364
367
|
keepNonPropertyFields?: boolean;
|
|
365
368
|
}
|
|
366
369
|
export interface FindEntityRelationalFilterOptions {
|
|
@@ -392,6 +395,10 @@ export interface FindEntityPaginationOptions {
|
|
|
392
395
|
limit: number;
|
|
393
396
|
withoutTotal?: boolean;
|
|
394
397
|
}
|
|
398
|
+
export type FindEntitySelectRelationOptions = true | {
|
|
399
|
+
properties?: string[];
|
|
400
|
+
relations?: Record<string, FindEntitySelectRelationOptions>;
|
|
401
|
+
};
|
|
395
402
|
export interface FindEntityOrderByOptions {
|
|
396
403
|
field: string;
|
|
397
404
|
desc?: boolean;
|
package/package.json
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
export type RowFilterRelationalOperators =
|
|
1
|
+
export type RowFilterRelationalOperators =
|
|
2
|
+
| "eq"
|
|
3
|
+
| "ne"
|
|
4
|
+
| "lt"
|
|
5
|
+
| "lte"
|
|
6
|
+
| "gt"
|
|
7
|
+
| "gte"
|
|
8
|
+
| "contains"
|
|
9
|
+
| "notContains"
|
|
10
|
+
| "containsCS"
|
|
11
|
+
| "notContainsCS"
|
|
12
|
+
| "startsWith"
|
|
13
|
+
| "notStartsWith"
|
|
14
|
+
| "endsWith"
|
|
15
|
+
| "notEndsWith";
|
|
2
16
|
|
|
3
17
|
export type RowFilterSetOperators = "in" | "notIn";
|
|
4
18
|
|
|
@@ -8,38 +22,47 @@ export type RowFilterUnaryOperators = "null" | "notNull";
|
|
|
8
22
|
|
|
9
23
|
export type RowFilterExistenceOperators = "exists" | "notExists";
|
|
10
24
|
|
|
11
|
-
export type RowFilterOperators =
|
|
25
|
+
export type RowFilterOperators =
|
|
26
|
+
| RowFilterRelationalOperators
|
|
27
|
+
| RowFilterSetOperators
|
|
28
|
+
| RowFilterLogicalOperators
|
|
29
|
+
| RowFilterUnaryOperators
|
|
30
|
+
| RowFilterExistenceOperators;
|
|
12
31
|
|
|
13
|
-
export type RowFilterOptions =
|
|
32
|
+
export type RowFilterOptions =
|
|
33
|
+
| FindRowRelationalFilterOptions
|
|
34
|
+
| FindRowSetFilterOptions
|
|
35
|
+
| FindRowLogicalFilterOptions
|
|
36
|
+
| FindRowUnaryFilterOptions
|
|
37
|
+
| FindRowExistenceFilterOptions;
|
|
14
38
|
|
|
15
39
|
export type RowNonRelationPropertyFilterOptions = FindRowRelationalFilterOptions | FindRowSetFilterOptions | FindRowUnaryFilterOptions;
|
|
16
40
|
|
|
17
|
-
export type
|
|
41
|
+
export type ColumnSelectOptions = string | ColumnNameWithTableName;
|
|
18
42
|
|
|
19
43
|
export type ColumnNameWithTableName = {
|
|
20
44
|
name: string;
|
|
21
45
|
tableName?: string;
|
|
22
|
-
}
|
|
46
|
+
};
|
|
23
47
|
|
|
24
48
|
export interface FindRowOptions {
|
|
25
49
|
filters?: RowFilterOptions[];
|
|
26
50
|
orderBy?: FindRowOrderByOptions[];
|
|
27
51
|
pagination?: FindRowPaginationOptions;
|
|
28
52
|
// TODO: may be `columns` is a better name.
|
|
29
|
-
fields?:
|
|
53
|
+
fields?: ColumnSelectOptions[];
|
|
30
54
|
keepNonPropertyFields?: boolean;
|
|
31
55
|
}
|
|
32
56
|
|
|
33
|
-
|
|
34
57
|
export interface FindRowRelationalFilterOptions {
|
|
35
58
|
// TODO: may be `column` is a better name.
|
|
36
|
-
field:
|
|
59
|
+
field: ColumnSelectOptions;
|
|
37
60
|
operator: RowFilterRelationalOperators;
|
|
38
61
|
value: any;
|
|
39
62
|
}
|
|
40
63
|
|
|
41
64
|
export interface FindRowSetFilterOptions {
|
|
42
|
-
field:
|
|
65
|
+
field: ColumnSelectOptions;
|
|
43
66
|
operator: RowFilterSetOperators;
|
|
44
67
|
value: any[];
|
|
45
68
|
itemType?: string;
|
|
@@ -51,12 +74,12 @@ export interface FindRowLogicalFilterOptions {
|
|
|
51
74
|
}
|
|
52
75
|
|
|
53
76
|
export interface FindRowUnaryFilterOptions {
|
|
54
|
-
field:
|
|
77
|
+
field: ColumnSelectOptions;
|
|
55
78
|
operator: RowFilterUnaryOperators;
|
|
56
79
|
}
|
|
57
80
|
|
|
58
81
|
export interface FindRowExistenceFilterOptions {
|
|
59
|
-
field:
|
|
82
|
+
field: ColumnSelectOptions;
|
|
60
83
|
operator: RowFilterExistenceOperators;
|
|
61
84
|
filters: RowFilterOptions[];
|
|
62
85
|
}
|
|
@@ -68,7 +91,7 @@ export interface FindRowPaginationOptions {
|
|
|
68
91
|
}
|
|
69
92
|
|
|
70
93
|
export interface FindRowOrderByOptions {
|
|
71
|
-
field:
|
|
94
|
+
field: ColumnSelectOptions;
|
|
72
95
|
desc?: boolean;
|
|
73
96
|
}
|
|
74
97
|
|
|
@@ -83,4 +106,4 @@ export interface UpdateRowOptions {
|
|
|
83
106
|
|
|
84
107
|
export interface DeleteRowOptions {
|
|
85
108
|
filters?: RowFilterOptions[];
|
|
86
|
-
}
|
|
109
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
FindEntityByIdOptions,
|
|
11
11
|
FindEntityOptions,
|
|
12
12
|
FindEntityOrderByOptions,
|
|
13
|
+
FindEntitySelectRelationOptions,
|
|
13
14
|
IRpdDataAccessor,
|
|
14
15
|
RemoveEntityRelationsOptions,
|
|
15
16
|
RpdDataModel,
|
|
@@ -24,10 +25,26 @@ import { IRpdServer, RapidPlugin } from "~/core/server";
|
|
|
24
25
|
import { getEntityPartChanges } from "~/helpers/entityHelpers";
|
|
25
26
|
import { filter, find, first, forEach, isArray, isObject, keys, map, reject, uniq } from "lodash";
|
|
26
27
|
import { getEntityPropertiesIncludingBase, getEntityProperty, getEntityPropertyByCode } from "./metaHelper";
|
|
27
|
-
import {
|
|
28
|
+
import { ColumnSelectOptions, CountRowOptions, FindRowOptions, FindRowOrderByOptions, RowFilterOptions } from "./dataAccessTypes";
|
|
28
29
|
import { newEntityOperationError } from "~/utilities/errorUtility";
|
|
29
30
|
import { getNowStringWithTimezone } from "~/utilities/timeUtility";
|
|
30
31
|
|
|
32
|
+
export type FindOneRelationEntitiesOptions = {
|
|
33
|
+
server: IRpdServer;
|
|
34
|
+
mainModel: RpdDataModel;
|
|
35
|
+
relationProperty: RpdDataModelProperty;
|
|
36
|
+
relationEntityIds: any[];
|
|
37
|
+
selectRelationOptions?: FindEntitySelectRelationOptions;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type FindManyRelationEntitiesOptions = {
|
|
41
|
+
server: IRpdServer;
|
|
42
|
+
mainModel: RpdDataModel;
|
|
43
|
+
relationProperty: RpdDataModelProperty;
|
|
44
|
+
mainEntityIds: any[];
|
|
45
|
+
selectRelationOptions?: FindEntitySelectRelationOptions;
|
|
46
|
+
};
|
|
47
|
+
|
|
31
48
|
function convertEntityOrderByToRowOrderBy(server: IRpdServer, model: RpdDataModel, baseModel?: RpdDataModel, orderByList?: FindEntityOrderByOptions[]) {
|
|
32
49
|
if (!orderByList) {
|
|
33
50
|
return null;
|
|
@@ -66,17 +83,23 @@ async function findEntities(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
66
83
|
});
|
|
67
84
|
}
|
|
68
85
|
|
|
69
|
-
let
|
|
86
|
+
let propertiesToSelect: RpdDataModelProperty[];
|
|
87
|
+
let relationOptions = options.relations || {};
|
|
88
|
+
let relationPropertyCodes = Object.keys(relationOptions) || [];
|
|
70
89
|
if (!options.properties || !options.properties.length) {
|
|
71
|
-
|
|
90
|
+
propertiesToSelect = getEntityPropertiesIncludingBase(server, model).filter(
|
|
91
|
+
(property) => !isRelationProperty(property) || relationPropertyCodes.includes(property.code),
|
|
92
|
+
);
|
|
72
93
|
} else {
|
|
73
|
-
|
|
94
|
+
propertiesToSelect = getEntityPropertiesIncludingBase(server, model).filter(
|
|
95
|
+
(property) => options.properties.includes(property.code) || relationPropertyCodes.includes(property.code),
|
|
96
|
+
);
|
|
74
97
|
}
|
|
75
98
|
|
|
76
|
-
const columnsToSelect:
|
|
99
|
+
const columnsToSelect: ColumnSelectOptions[] = [];
|
|
77
100
|
|
|
78
101
|
const relationPropertiesToSelect: RpdDataModelProperty[] = [];
|
|
79
|
-
forEach(
|
|
102
|
+
forEach(propertiesToSelect, (property) => {
|
|
80
103
|
if (isRelationProperty(property)) {
|
|
81
104
|
relationPropertiesToSelect.push(property);
|
|
82
105
|
|
|
@@ -127,6 +150,30 @@ async function findEntities(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
127
150
|
});
|
|
128
151
|
}
|
|
129
152
|
|
|
153
|
+
if (options.extraColumnsToSelect) {
|
|
154
|
+
forEach(options.extraColumnsToSelect, (extraColumnToSelect: ColumnSelectOptions) => {
|
|
155
|
+
const columnSelectOptionExists = find(columnsToSelect, (item: ColumnSelectOptions) => {
|
|
156
|
+
if (typeof item === "string") {
|
|
157
|
+
if (typeof extraColumnToSelect === "string") {
|
|
158
|
+
return item === extraColumnToSelect;
|
|
159
|
+
} else {
|
|
160
|
+
return item == extraColumnToSelect.name;
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
if (typeof extraColumnToSelect === "string") {
|
|
164
|
+
return item.name === extraColumnToSelect;
|
|
165
|
+
} else {
|
|
166
|
+
return item.name == extraColumnToSelect.name;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
if (!columnSelectOptionExists) {
|
|
172
|
+
columnsToSelect.push(extraColumnToSelect);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
130
177
|
const rowFilters = await convertEntityFiltersToRowFilters(server, model, baseModel, options.filters);
|
|
131
178
|
const findRowOptions: FindRowOptions = {
|
|
132
179
|
filters: rowFilters,
|
|
@@ -145,24 +192,36 @@ async function findEntities(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
145
192
|
const isManyRelation = relationProperty.relation === "many";
|
|
146
193
|
|
|
147
194
|
if (relationProperty.linkTableName) {
|
|
148
|
-
const
|
|
149
|
-
if (!
|
|
195
|
+
const relationModel = server.getModel({ singularCode: relationProperty.targetSingularCode! });
|
|
196
|
+
if (!relationModel) {
|
|
150
197
|
continue;
|
|
151
198
|
}
|
|
152
199
|
|
|
153
200
|
if (isManyRelation) {
|
|
154
|
-
const relationLinks = await findManyRelationLinksViaLinkTable(
|
|
201
|
+
const relationLinks = await findManyRelationLinksViaLinkTable({
|
|
202
|
+
server,
|
|
203
|
+
mainModel: relationModel,
|
|
204
|
+
relationProperty,
|
|
205
|
+
mainEntityIds: entityIds,
|
|
206
|
+
selectRelationOptions: relationOptions[relationProperty.code],
|
|
207
|
+
});
|
|
155
208
|
|
|
156
209
|
forEach(rows, (row: any) => {
|
|
157
210
|
row[relationProperty.code] = filter(relationLinks, (link: any) => {
|
|
158
211
|
return link[relationProperty.selfIdColumnName!] == row["id"];
|
|
159
|
-
}).map((link) => mapDbRowToEntity(server,
|
|
212
|
+
}).map((link) => mapDbRowToEntity(server, relationModel, link.targetEntity, options.keepNonPropertyFields));
|
|
160
213
|
});
|
|
161
214
|
}
|
|
162
215
|
} else {
|
|
163
216
|
let relatedEntities: any[];
|
|
164
217
|
if (isManyRelation) {
|
|
165
|
-
relatedEntities = await findManyRelatedEntitiesViaIdPropertyCode(
|
|
218
|
+
relatedEntities = await findManyRelatedEntitiesViaIdPropertyCode({
|
|
219
|
+
server,
|
|
220
|
+
mainModel: model,
|
|
221
|
+
relationProperty,
|
|
222
|
+
mainEntityIds: entityIds,
|
|
223
|
+
selectRelationOptions: relationOptions[relationProperty.code],
|
|
224
|
+
});
|
|
166
225
|
} else {
|
|
167
226
|
const targetEntityIds = uniq(
|
|
168
227
|
reject(
|
|
@@ -170,7 +229,13 @@ async function findEntities(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
170
229
|
isNullOrUndefined,
|
|
171
230
|
),
|
|
172
231
|
);
|
|
173
|
-
relatedEntities = await findOneRelatedEntitiesViaIdPropertyCode(
|
|
232
|
+
relatedEntities = await findOneRelatedEntitiesViaIdPropertyCode({
|
|
233
|
+
server,
|
|
234
|
+
mainModel: model,
|
|
235
|
+
relationProperty,
|
|
236
|
+
relationEntityIds: targetEntityIds,
|
|
237
|
+
selectRelationOptions: relationOptions[relationProperty.code],
|
|
238
|
+
});
|
|
174
239
|
}
|
|
175
240
|
|
|
176
241
|
const targetModel = server.getModel({
|
|
@@ -451,30 +516,44 @@ async function convertEntityFiltersToRowFilters(
|
|
|
451
516
|
return replacedFilters;
|
|
452
517
|
}
|
|
453
518
|
|
|
454
|
-
async function findManyRelationLinksViaLinkTable(
|
|
519
|
+
async function findManyRelationLinksViaLinkTable(options: FindManyRelationEntitiesOptions) {
|
|
520
|
+
const { server, relationProperty, mainModel: relationModel, mainEntityIds, selectRelationOptions } = options;
|
|
455
521
|
const command = `SELECT * FROM ${server.queryBuilder.quoteTable({
|
|
456
522
|
schema: relationProperty.linkSchema,
|
|
457
523
|
tableName: relationProperty.linkTableName!,
|
|
458
524
|
})} WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName!)} = ANY($1::int[])`;
|
|
459
|
-
const params = [
|
|
525
|
+
const params = [mainEntityIds];
|
|
460
526
|
const links = await server.queryDatabaseObject(command, params);
|
|
461
527
|
const targetEntityIds = links.map((link) => link[relationProperty.targetIdColumnName!]);
|
|
462
|
-
|
|
528
|
+
|
|
529
|
+
const dataAccessor = server.getDataAccessor({
|
|
530
|
+
namespace: relationModel.namespace,
|
|
531
|
+
singularCode: relationModel.singularCode,
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
const findEntityOptions: FindEntityOptions = {
|
|
463
535
|
filters: [
|
|
464
536
|
{
|
|
465
|
-
field:
|
|
466
|
-
name: "id",
|
|
467
|
-
},
|
|
537
|
+
field: "id",
|
|
468
538
|
operator: "in",
|
|
469
539
|
value: targetEntityIds,
|
|
470
540
|
},
|
|
471
541
|
],
|
|
542
|
+
keepNonPropertyFields: true,
|
|
472
543
|
};
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
544
|
+
|
|
545
|
+
if (selectRelationOptions) {
|
|
546
|
+
if (typeof selectRelationOptions !== "boolean") {
|
|
547
|
+
if (selectRelationOptions.properties) {
|
|
548
|
+
findEntityOptions.properties = ["id", ...selectRelationOptions.properties];
|
|
549
|
+
}
|
|
550
|
+
if (selectRelationOptions.relations) {
|
|
551
|
+
findEntityOptions.relations = selectRelationOptions.relations;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const targetEntities = await findEntities(server, dataAccessor, findEntityOptions);
|
|
478
557
|
|
|
479
558
|
forEach(links, (link: any) => {
|
|
480
559
|
link.targetEntity = find(targetEntities, (e: any) => e["id"] == link[relationProperty.targetIdColumnName!]);
|
|
@@ -483,42 +562,68 @@ async function findManyRelationLinksViaLinkTable(server: IRpdServer, targetModel
|
|
|
483
562
|
return links;
|
|
484
563
|
}
|
|
485
564
|
|
|
486
|
-
function findManyRelatedEntitiesViaIdPropertyCode(
|
|
487
|
-
const
|
|
565
|
+
async function findManyRelatedEntitiesViaIdPropertyCode(options: FindManyRelationEntitiesOptions) {
|
|
566
|
+
const { server, relationProperty, mainEntityIds, selectRelationOptions } = options;
|
|
567
|
+
const dataAccessor = server.getDataAccessor({
|
|
568
|
+
singularCode: relationProperty.targetSingularCode as string,
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
const findEntityOptions: FindEntityOptions = {
|
|
488
572
|
filters: [
|
|
489
573
|
{
|
|
490
|
-
field:
|
|
491
|
-
name: relationProperty.selfIdColumnName,
|
|
492
|
-
},
|
|
574
|
+
field: relationProperty.selfIdColumnName,
|
|
493
575
|
operator: "in",
|
|
494
|
-
value:
|
|
576
|
+
value: mainEntityIds,
|
|
495
577
|
},
|
|
496
578
|
],
|
|
579
|
+
extraColumnsToSelect: [relationProperty.selfIdColumnName],
|
|
580
|
+
keepNonPropertyFields: true,
|
|
497
581
|
};
|
|
582
|
+
|
|
583
|
+
if (selectRelationOptions) {
|
|
584
|
+
if (typeof selectRelationOptions !== "boolean") {
|
|
585
|
+
if (selectRelationOptions.properties) {
|
|
586
|
+
findEntityOptions.properties = ["id", ...selectRelationOptions.properties];
|
|
587
|
+
}
|
|
588
|
+
if (selectRelationOptions.relations) {
|
|
589
|
+
findEntityOptions.relations = selectRelationOptions.relations;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
return await findEntities(server, dataAccessor, findEntityOptions);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
async function findOneRelatedEntitiesViaIdPropertyCode(options: FindOneRelationEntitiesOptions) {
|
|
598
|
+
const { server, relationProperty, relationEntityIds, selectRelationOptions } = options;
|
|
599
|
+
|
|
498
600
|
const dataAccessor = server.getDataAccessor({
|
|
499
601
|
singularCode: relationProperty.targetSingularCode as string,
|
|
500
602
|
});
|
|
501
603
|
|
|
502
|
-
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
function findOneRelatedEntitiesViaIdPropertyCode(server: IRpdServer, model: RpdDataModel, relationProperty: RpdDataModelProperty, targetEntityIds: any[]) {
|
|
506
|
-
const findEntityOptions: FindRowOptions = {
|
|
604
|
+
const findEntityOptions: FindEntityOptions = {
|
|
507
605
|
filters: [
|
|
508
606
|
{
|
|
509
|
-
field:
|
|
510
|
-
name: "id",
|
|
511
|
-
},
|
|
607
|
+
field: "id",
|
|
512
608
|
operator: "in",
|
|
513
|
-
value:
|
|
609
|
+
value: relationEntityIds,
|
|
514
610
|
},
|
|
515
611
|
],
|
|
612
|
+
keepNonPropertyFields: true,
|
|
516
613
|
};
|
|
517
|
-
const dataAccessor = server.getDataAccessor({
|
|
518
|
-
singularCode: relationProperty.targetSingularCode as string,
|
|
519
|
-
});
|
|
520
614
|
|
|
521
|
-
|
|
615
|
+
if (selectRelationOptions) {
|
|
616
|
+
if (typeof selectRelationOptions !== "boolean") {
|
|
617
|
+
if (selectRelationOptions.properties) {
|
|
618
|
+
findEntityOptions.properties = ["id", ...selectRelationOptions.properties];
|
|
619
|
+
}
|
|
620
|
+
if (selectRelationOptions.relations) {
|
|
621
|
+
findEntityOptions.relations = selectRelationOptions.relations;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return await findEntities(server, dataAccessor, findEntityOptions);
|
|
522
627
|
}
|
|
523
628
|
|
|
524
629
|
async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor, options: CreateEntityOptions, plugin?: RapidPlugin) {
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { find } from "lodash";
|
|
2
|
-
import {
|
|
3
|
-
RpdDataModel,
|
|
4
|
-
RpdDataModelProperty,
|
|
5
|
-
CreateEntityOptions,
|
|
6
|
-
QuoteTableOptions,
|
|
7
|
-
DatabaseQuery,
|
|
8
|
-
} from "../types";
|
|
2
|
+
import { RpdDataModel, RpdDataModelProperty, CreateEntityOptions, QuoteTableOptions, DatabaseQuery } from "../types";
|
|
9
3
|
import {
|
|
10
4
|
CountRowOptions,
|
|
11
5
|
DeleteRowOptions,
|
|
@@ -17,7 +11,7 @@ import {
|
|
|
17
11
|
RowFilterOptions,
|
|
18
12
|
RowFilterRelationalOperators,
|
|
19
13
|
UpdateRowOptions,
|
|
20
|
-
|
|
14
|
+
ColumnSelectOptions,
|
|
21
15
|
} from "~/dataAccess/dataAccessTypes";
|
|
22
16
|
|
|
23
17
|
const objLeftQuoteChar = '"';
|
|
@@ -64,7 +58,7 @@ export default class QueryBuilder {
|
|
|
64
58
|
return `${objLeftQuoteChar}${name}${objRightQuoteChar}`;
|
|
65
59
|
}
|
|
66
60
|
|
|
67
|
-
quoteColumn(column:
|
|
61
|
+
quoteColumn(column: ColumnSelectOptions, emitTableAlias: boolean) {
|
|
68
62
|
if (typeof column === "string") {
|
|
69
63
|
return `${objLeftQuoteChar}${column}${objRightQuoteChar}`;
|
|
70
64
|
} else if (emitTableAlias && column.tableName) {
|
|
@@ -100,7 +94,7 @@ export default class QueryBuilder {
|
|
|
100
94
|
command += " ORDER BY ";
|
|
101
95
|
command += orderBy
|
|
102
96
|
.map((item) => {
|
|
103
|
-
const quotedName = this.quoteColumn(item.field,
|
|
97
|
+
const quotedName = this.quoteColumn(item.field, ctx.emitTableAlias);
|
|
104
98
|
return item.desc ? quotedName + " DESC" : quotedName;
|
|
105
99
|
})
|
|
106
100
|
.join(", ");
|
|
@@ -133,13 +127,17 @@ export default class QueryBuilder {
|
|
|
133
127
|
if (!columns || !columns.length) {
|
|
134
128
|
command += `${this.quoteObject(derivedModel.tableName)}.* FROM `;
|
|
135
129
|
} else {
|
|
136
|
-
command += columns
|
|
137
|
-
|
|
138
|
-
|
|
130
|
+
command += columns
|
|
131
|
+
.map((column) => {
|
|
132
|
+
return this.quoteColumn(column, ctx.emitTableAlias);
|
|
133
|
+
})
|
|
134
|
+
.join(", ");
|
|
139
135
|
command += " FROM ";
|
|
140
136
|
}
|
|
141
137
|
|
|
142
|
-
command += `${this.quoteTable(derivedModel)} LEFT JOIN ${this.quoteTable(baseModel)} ON ${this.quoteObject(derivedModel.tableName)}.id = ${this.quoteObject(
|
|
138
|
+
command += `${this.quoteTable(derivedModel)} LEFT JOIN ${this.quoteTable(baseModel)} ON ${this.quoteObject(derivedModel.tableName)}.id = ${this.quoteObject(
|
|
139
|
+
baseModel.tableName,
|
|
140
|
+
)}.id`;
|
|
143
141
|
|
|
144
142
|
if (filters && filters.length) {
|
|
145
143
|
command += " WHERE ";
|
|
@@ -203,7 +201,9 @@ export default class QueryBuilder {
|
|
|
203
201
|
let { filters } = options;
|
|
204
202
|
let command = 'SELECT COUNT(*)::int as "count" FROM ';
|
|
205
203
|
|
|
206
|
-
command += `${this.quoteTable(derivedModel)} LEFT JOIN ${this.quoteTable(baseModel)} ON ${this.quoteObject(derivedModel.tableName)}.id = ${this.quoteObject(
|
|
204
|
+
command += `${this.quoteTable(derivedModel)} LEFT JOIN ${this.quoteTable(baseModel)} ON ${this.quoteObject(derivedModel.tableName)}.id = ${this.quoteObject(
|
|
205
|
+
baseModel.tableName,
|
|
206
|
+
)}.id`;
|
|
207
207
|
|
|
208
208
|
if (filters && filters.length) {
|
|
209
209
|
command += " WHERE ";
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RouteContext } from "./core/routeContext";
|
|
2
2
|
import { IRpdServer, RapidPlugin } from "./core/server";
|
|
3
|
-
import { CountRowOptions, FindRowOptions } from "./dataAccess/dataAccessTypes";
|
|
3
|
+
import { ColumnSelectOptions, CountRowOptions, FindRowOptions } from "./dataAccess/dataAccessTypes";
|
|
4
4
|
|
|
5
5
|
export type RapidServerConfig = {
|
|
6
6
|
baseUrl?: string;
|
|
@@ -296,7 +296,21 @@ export interface RpdDataModelProperty {
|
|
|
296
296
|
linkSchema?: string;
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
-
export type RpdDataPropertyTypes =
|
|
299
|
+
export type RpdDataPropertyTypes =
|
|
300
|
+
| "integer"
|
|
301
|
+
| "long"
|
|
302
|
+
| "float"
|
|
303
|
+
| "double"
|
|
304
|
+
| "decimal"
|
|
305
|
+
| "text"
|
|
306
|
+
| "boolean"
|
|
307
|
+
| "date"
|
|
308
|
+
| "time"
|
|
309
|
+
| "datetime"
|
|
310
|
+
| "json"
|
|
311
|
+
| "relation"
|
|
312
|
+
| "relation[]"
|
|
313
|
+
| "option";
|
|
300
314
|
|
|
301
315
|
/**
|
|
302
316
|
* 数据字典
|
|
@@ -388,7 +402,21 @@ export interface IRpdDataAccessor<T = any> {
|
|
|
388
402
|
deleteById(id: any): Promise<void>;
|
|
389
403
|
}
|
|
390
404
|
|
|
391
|
-
export type EntityFilterRelationalOperators =
|
|
405
|
+
export type EntityFilterRelationalOperators =
|
|
406
|
+
| "eq"
|
|
407
|
+
| "ne"
|
|
408
|
+
| "lt"
|
|
409
|
+
| "lte"
|
|
410
|
+
| "gt"
|
|
411
|
+
| "gte"
|
|
412
|
+
| "contains"
|
|
413
|
+
| "notContains"
|
|
414
|
+
| "containsCS"
|
|
415
|
+
| "notContainsCS"
|
|
416
|
+
| "startsWith"
|
|
417
|
+
| "notStartsWith"
|
|
418
|
+
| "endsWith"
|
|
419
|
+
| "notEndsWith";
|
|
392
420
|
|
|
393
421
|
export type EntityFilterSetOperators = "in" | "notIn";
|
|
394
422
|
|
|
@@ -398,9 +426,19 @@ export type EntityFilterUnaryOperators = "null" | "notNull";
|
|
|
398
426
|
|
|
399
427
|
export type EntityFilterExistenceOperators = "exists" | "notExists";
|
|
400
428
|
|
|
401
|
-
export type EntityFilterOperators =
|
|
429
|
+
export type EntityFilterOperators =
|
|
430
|
+
| EntityFilterRelationalOperators
|
|
431
|
+
| EntityFilterSetOperators
|
|
432
|
+
| EntityFilterLogicalOperators
|
|
433
|
+
| EntityFilterUnaryOperators
|
|
434
|
+
| EntityFilterExistenceOperators;
|
|
402
435
|
|
|
403
|
-
export type EntityFilterOptions =
|
|
436
|
+
export type EntityFilterOptions =
|
|
437
|
+
| FindEntityRelationalFilterOptions
|
|
438
|
+
| FindEntitySetFilterOptions
|
|
439
|
+
| FindEntityLogicalFilterOptions
|
|
440
|
+
| FindEntityUnaryFilterOptions
|
|
441
|
+
| FindEntityExistenceFilterOptions;
|
|
404
442
|
|
|
405
443
|
export type EntityNonRelationPropertyFilterOptions = FindEntityRelationalFilterOptions | FindEntitySetFilterOptions | FindEntityUnaryFilterOptions;
|
|
406
444
|
|
|
@@ -410,6 +448,8 @@ export interface FindEntityOptions {
|
|
|
410
448
|
orderBy?: FindEntityOrderByOptions[];
|
|
411
449
|
pagination?: FindEntityPaginationOptions;
|
|
412
450
|
properties?: string[];
|
|
451
|
+
relations?: Record<string, FindEntitySelectRelationOptions>;
|
|
452
|
+
extraColumnsToSelect?: ColumnSelectOptions[];
|
|
413
453
|
keepNonPropertyFields?: boolean;
|
|
414
454
|
}
|
|
415
455
|
|
|
@@ -417,6 +457,7 @@ export interface FindEntityByIdOptions {
|
|
|
417
457
|
routeContext?: RouteContext;
|
|
418
458
|
id: any;
|
|
419
459
|
properties?: string[];
|
|
460
|
+
relations?: Record<string, FindEntitySelectRelationOptions>;
|
|
420
461
|
keepNonPropertyFields?: boolean;
|
|
421
462
|
}
|
|
422
463
|
|
|
@@ -455,6 +496,13 @@ export interface FindEntityPaginationOptions {
|
|
|
455
496
|
withoutTotal?: boolean;
|
|
456
497
|
}
|
|
457
498
|
|
|
499
|
+
export type FindEntitySelectRelationOptions =
|
|
500
|
+
| true
|
|
501
|
+
| {
|
|
502
|
+
properties?: string[];
|
|
503
|
+
relations?: Record<string, FindEntitySelectRelationOptions>;
|
|
504
|
+
};
|
|
505
|
+
|
|
458
506
|
export interface FindEntityOrderByOptions {
|
|
459
507
|
field: string;
|
|
460
508
|
desc?: boolean;
|
|
@@ -514,7 +562,13 @@ export interface RemoveEntityRelationsOptions {
|
|
|
514
562
|
relations: { id?: number; [k: string]: any }[];
|
|
515
563
|
}
|
|
516
564
|
|
|
517
|
-
export type EntityWatcherType =
|
|
565
|
+
export type EntityWatcherType =
|
|
566
|
+
| EntityWatcher<"entity.create">
|
|
567
|
+
| EntityWatcher<"entity.update">
|
|
568
|
+
| EntityWatcher<"entity.delete">
|
|
569
|
+
| EntityWatcher<"entity.addRelations">
|
|
570
|
+
| EntityWatcher<"entity.removeRelations">
|
|
571
|
+
| EntityWatcher<any>;
|
|
518
572
|
|
|
519
573
|
export interface EntityWatcher<TEventName extends keyof RpdServerEventTypes = any> {
|
|
520
574
|
eventName: TEventName;
|