rez_core 5.0.152 → 5.0.154
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/config/bull.config.js +4 -4
- package/dist/config/bull.config.js.map +1 -1
- package/dist/core.module.js +2 -5
- package/dist/core.module.js.map +1 -1
- package/dist/module/entity_json/entity_json.module.js +1 -1
- package/dist/module/entity_json/entity_json.module.js.map +1 -1
- package/dist/module/entity_json/service/entity_json.service.js +1 -1
- package/dist/module/entity_json/service/entity_json.service.js.map +1 -1
- package/dist/module/filter/controller/filter.controller.d.ts +0 -12
- package/dist/module/filter/controller/filter.controller.js +1 -1
- package/dist/module/filter/controller/filter.controller.js.map +1 -1
- package/dist/module/filter/entity/saved-filter-master.entity.d.ts +2 -1
- package/dist/module/filter/entity/saved-filter-master.entity.js +6 -2
- package/dist/module/filter/entity/saved-filter-master.entity.js.map +1 -1
- package/dist/module/filter/filter.module.js +2 -9
- package/dist/module/filter/filter.module.js.map +1 -1
- package/dist/module/filter/repository/saved-filter.repository.d.ts +1 -5
- package/dist/module/filter/repository/saved-filter.repository.js +1 -5
- package/dist/module/filter/repository/saved-filter.repository.js.map +1 -1
- package/dist/module/filter/service/filter.service.d.ts +1 -37
- package/dist/module/filter/service/filter.service.js +2 -30
- package/dist/module/filter/service/filter.service.js.map +1 -1
- package/dist/module/integration/service/wrapper.service.d.ts +3 -1
- package/dist/module/integration/service/wrapper.service.js +24 -2
- package/dist/module/integration/service/wrapper.service.js.map +1 -1
- package/dist/module/linked_attributes/controller/linked_attributes.controller.d.ts +0 -19
- package/dist/module/linked_attributes/controller/linked_attributes.controller.js +0 -77
- package/dist/module/linked_attributes/controller/linked_attributes.controller.js.map +1 -1
- package/dist/module/linked_attributes/linked_attributes.module.js +1 -8
- package/dist/module/linked_attributes/linked_attributes.module.js.map +1 -1
- package/dist/module/linked_attributes/service/linked_attributes.service.d.ts +1 -41
- package/dist/module/linked_attributes/service/linked_attributes.service.js +2 -266
- package/dist/module/linked_attributes/service/linked_attributes.service.js.map +1 -1
- package/dist/module/meta/dto/entity-table.dto.d.ts +1 -4
- package/dist/module/meta/dto/entity-table.dto.js.map +1 -1
- package/dist/module/meta/service/media-data.service.js +18 -5
- package/dist/module/meta/service/media-data.service.js.map +1 -1
- package/dist/module/workflow/service/action.service.js +2 -10
- package/dist/module/workflow/service/action.service.js.map +1 -1
- package/dist/table.config.d.ts +1 -3
- package/dist/table.config.js +0 -2
- package/dist/table.config.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/config/bull.config.ts +4 -4
- package/src/core.module.ts +2 -5
- package/src/module/entity_json/entity_json.module.ts +1 -1
- package/src/module/entity_json/service/entity_json.service.ts +1 -1
- package/src/module/filter/controller/filter.controller.ts +3 -1
- package/src/module/filter/entity/saved-filter-master.entity.ts +5 -2
- package/src/module/filter/filter.module.ts +2 -9
- package/src/module/filter/repository/saved-filter.repository.ts +9 -5
- package/src/module/filter/service/filter.service.ts +0 -49
- package/src/module/integration/service/wrapper.service.ts +37 -0
- package/src/module/linked_attributes/controller/linked_attributes.controller.ts +0 -86
- package/src/module/linked_attributes/linked_attributes.module.ts +2 -9
- package/src/module/linked_attributes/service/linked_attributes.service.ts +3 -548
- package/src/module/meta/dto/entity-table.dto.ts +3 -1
- package/src/module/meta/service/media-data.service.ts +27 -9
- package/src/module/workflow/service/action.service.ts +6 -10
- package/src/table.config.ts +0 -2
- package/dist/migrations/1732612800000-AddEntityJsonGinIndex.d.ts +0 -6
- package/dist/migrations/1732612800000-AddEntityJsonGinIndex.js +0 -32
- package/dist/migrations/1732612800000-AddEntityJsonGinIndex.js.map +0 -1
- package/dist/module/filter/service/flatjson-filter.service.d.ts +0 -30
- package/dist/module/filter/service/flatjson-filter.service.js +0 -615
- package/dist/module/filter/service/flatjson-filter.service.js.map +0 -1
- package/dist/module/linked_attributes/dto/create-linked-attribute-smart.dto.d.ts +0 -13
- package/dist/module/linked_attributes/dto/create-linked-attribute-smart.dto.js +0 -64
- package/dist/module/linked_attributes/dto/create-linked-attribute-smart.dto.js.map +0 -1
- package/src/migrations/1732612800000-AddEntityJsonGinIndex.ts +0 -41
- package/src/module/entity_json/docs/FlatJson_Filterin_System.md +0 -2804
- package/src/module/filter/service/flatjson-filter.service.ts +0 -888
- package/src/module/filter/test/flatjson-filter.service.spec.ts +0 -415
- package/src/module/linked_attributes/dto/create-linked-attribute-smart.dto.ts +0 -54
- package/src/module/linked_attributes/test/linked-attributes.service.spec.ts +0 -244
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AddEntityJsonGinIndex1732612800000 = void 0;
|
|
4
|
-
class AddEntityJsonGinIndex1732612800000 {
|
|
5
|
-
constructor() {
|
|
6
|
-
this.name = 'AddEntityJsonGinIndex1732612800000';
|
|
7
|
-
}
|
|
8
|
-
async up(queryRunner) {
|
|
9
|
-
await queryRunner.query(`
|
|
10
|
-
CREATE INDEX IF NOT EXISTS idx_entity_json_data_gin
|
|
11
|
-
ON frm_entity_json
|
|
12
|
-
USING GIN (json_data jsonb_path_ops);
|
|
13
|
-
`);
|
|
14
|
-
await queryRunner.query(`
|
|
15
|
-
CREATE INDEX IF NOT EXISTS idx_entity_json_entity_type
|
|
16
|
-
ON frm_entity_json (entity_type);
|
|
17
|
-
`);
|
|
18
|
-
await queryRunner.query(`
|
|
19
|
-
CREATE INDEX IF NOT EXISTS idx_entity_json_composite
|
|
20
|
-
ON frm_entity_json (entity_type, entity_id);
|
|
21
|
-
`);
|
|
22
|
-
console.log('✅ GIN indexes created successfully');
|
|
23
|
-
}
|
|
24
|
-
async down(queryRunner) {
|
|
25
|
-
await queryRunner.query(`DROP INDEX IF EXISTS idx_entity_json_data_gin;`);
|
|
26
|
-
await queryRunner.query(`DROP INDEX IF EXISTS idx_entity_json_entity_type;`);
|
|
27
|
-
await queryRunner.query(`DROP INDEX IF EXISTS idx_entity_json_composite;`);
|
|
28
|
-
console.log('✅ GIN indexes dropped successfully');
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
exports.AddEntityJsonGinIndex1732612800000 = AddEntityJsonGinIndex1732612800000;
|
|
32
|
-
//# sourceMappingURL=1732612800000-AddEntityJsonGinIndex.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"1732612800000-AddEntityJsonGinIndex.js","sourceRoot":"","sources":["../../src/migrations/1732612800000-AddEntityJsonGinIndex.ts"],"names":[],"mappings":";;;AAEA,MAAa,kCAAkC;IAA/C;QACE,SAAI,GAAG,oCAAoC,CAAC;IAqC9C,CAAC;IAnCQ,KAAK,CAAC,EAAE,CAAC,WAAwB;QAGtC,MAAM,WAAW,CAAC,KAAK,CAAC;;;;KAIvB,CAAC,CAAC;QAGH,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;QAGH,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IACpD,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,WAAwB;QACxC,MAAM,WAAW,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAC1E,MAAM,WAAW,CAAC,KAAK,CACrB,mDAAmD,CACpD,CAAC;QACF,MAAM,WAAW,CAAC,KAAK,CACrB,iDAAiD,CAClD,CAAC;QAEF,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IACpD,CAAC;CACF;AAtCD,gFAsCC"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { EntityManager } from 'typeorm';
|
|
2
|
-
import { EntityMasterService } from 'src/module/meta/service/entity-master.service';
|
|
3
|
-
import { AttributeMasterService } from 'src/module/meta/service/attribute-master.service';
|
|
4
|
-
import { ResolverService } from 'src/module/meta/service/resolver.service';
|
|
5
|
-
import { LoggingService } from 'src/utils/service/loggingUtil.service';
|
|
6
|
-
import { ConfigService } from '@nestjs/config';
|
|
7
|
-
import { FilterRequestDto } from '../dto/filter-request.dto';
|
|
8
|
-
import { SavedFilterRepositoryService } from '../repository/saved-filter.repository';
|
|
9
|
-
export declare class FlatjsonFilterService {
|
|
10
|
-
private readonly entityManager;
|
|
11
|
-
private readonly entityMasterService;
|
|
12
|
-
private readonly attributeMasterService;
|
|
13
|
-
private readonly resolverService;
|
|
14
|
-
private readonly loggingService;
|
|
15
|
-
private readonly configService;
|
|
16
|
-
private readonly savedFilterRepositoryService;
|
|
17
|
-
constructor(entityManager: EntityManager, entityMasterService: EntityMasterService, attributeMasterService: AttributeMasterService, resolverService: ResolverService, loggingService: LoggingService, configService: ConfigService, savedFilterRepositoryService: SavedFilterRepositoryService);
|
|
18
|
-
applyFlatjsonFilter(dto: FilterRequestDto): Promise<any>;
|
|
19
|
-
private buildJsonbConditions;
|
|
20
|
-
private resolveEntityData;
|
|
21
|
-
private buildJsonbCondition;
|
|
22
|
-
private buildTextCondition;
|
|
23
|
-
private buildNumberCondition;
|
|
24
|
-
private buildDateCondition;
|
|
25
|
-
private buildSelectCondition;
|
|
26
|
-
private buildMultiSelectCondition;
|
|
27
|
-
private buildYearCondition;
|
|
28
|
-
private getJsonbTabCounts;
|
|
29
|
-
private applyJsonbSorting;
|
|
30
|
-
}
|
|
@@ -1,615 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
-
};
|
|
8
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.FlatjsonFilterService = void 0;
|
|
13
|
-
const common_1 = require("@nestjs/common");
|
|
14
|
-
const typeorm_1 = require("typeorm");
|
|
15
|
-
const entity_master_service_1 = require("../../meta/service/entity-master.service");
|
|
16
|
-
const attribute_master_service_1 = require("../../meta/service/attribute-master.service");
|
|
17
|
-
const resolver_service_1 = require("../../meta/service/resolver.service");
|
|
18
|
-
const loggingUtil_service_1 = require("../../../utils/service/loggingUtil.service");
|
|
19
|
-
const config_1 = require("@nestjs/config");
|
|
20
|
-
const entityJson_entity_1 = require("../../entity_json/entity/entityJson.entity");
|
|
21
|
-
const saved_filter_repository_1 = require("../repository/saved-filter.repository");
|
|
22
|
-
let FlatjsonFilterService = class FlatjsonFilterService {
|
|
23
|
-
constructor(entityManager, entityMasterService, attributeMasterService, resolverService, loggingService, configService, savedFilterRepositoryService) {
|
|
24
|
-
this.entityManager = entityManager;
|
|
25
|
-
this.entityMasterService = entityMasterService;
|
|
26
|
-
this.attributeMasterService = attributeMasterService;
|
|
27
|
-
this.resolverService = resolverService;
|
|
28
|
-
this.loggingService = loggingService;
|
|
29
|
-
this.configService = configService;
|
|
30
|
-
this.savedFilterRepositoryService = savedFilterRepositoryService;
|
|
31
|
-
}
|
|
32
|
-
async applyFlatjsonFilter(dto) {
|
|
33
|
-
const { entity_type, quickFilter = [], savedFilterCode, attributeFilter = [], sortby = [], tabs, page = 1, size = 20, loggedInUser, } = dto;
|
|
34
|
-
await this.loggingService.log('info', 'FlatjsonFilterService', 'applyFlatjsonFilter', `Filtering entity: ${entity_type}`);
|
|
35
|
-
const attributes = await this.attributeMasterService.findAttributesByMappedEntityType(entity_type, loggedInUser);
|
|
36
|
-
const attributeMetaMap = {};
|
|
37
|
-
attributes.forEach((attr) => {
|
|
38
|
-
attributeMetaMap[attr.attribute_key] = attr;
|
|
39
|
-
});
|
|
40
|
-
await this.loggingService.log('debug', 'FlatjsonFilterService', 'applyFlatjsonFilter', `Loaded ${attributes.length} attributes`);
|
|
41
|
-
let allFilters = [...quickFilter, ...attributeFilter];
|
|
42
|
-
if (savedFilterCode) {
|
|
43
|
-
const savedFilterDetails = await this.savedFilterRepositoryService.getDetailsByCode(savedFilterCode);
|
|
44
|
-
allFilters = [...allFilters, ...savedFilterDetails];
|
|
45
|
-
}
|
|
46
|
-
await this.loggingService.log('debug', 'FlatjsonFilterService', 'applyFlatjsonFilter', `Total filters: ${allFilters.length}`);
|
|
47
|
-
const jsonbConditions = this.buildJsonbConditions(allFilters, attributeMetaMap);
|
|
48
|
-
const qb = this.entityManager
|
|
49
|
-
.getRepository(entityJson_entity_1.EntityJson)
|
|
50
|
-
.createQueryBuilder('ej')
|
|
51
|
-
.where('ej.entity_type = :entity_type', { entity_type })
|
|
52
|
-
.andWhere('ej.organization_id = :orgId', {
|
|
53
|
-
orgId: loggedInUser.organization_id,
|
|
54
|
-
});
|
|
55
|
-
jsonbConditions.forEach((condition, index) => {
|
|
56
|
-
qb.andWhere(condition.query, condition.params);
|
|
57
|
-
});
|
|
58
|
-
if (tabs?.columnName && tabs?.value) {
|
|
59
|
-
const tabMeta = attributeMetaMap[tabs.columnName];
|
|
60
|
-
if (tabMeta) {
|
|
61
|
-
const flatJsonKey = tabMeta.flat_json_key ||
|
|
62
|
-
`${entity_type}__${tabs.columnName}`;
|
|
63
|
-
qb.andWhere(`json_data->>'${flatJsonKey}' = :tabValue`, {
|
|
64
|
-
tabValue: tabs.value,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
let tabCounts = [];
|
|
69
|
-
if (tabs?.columnName && !tabs?.value) {
|
|
70
|
-
const tabMeta = attributeMetaMap[tabs.columnName];
|
|
71
|
-
if (tabMeta) {
|
|
72
|
-
const flatJsonKey = tabMeta.flat_json_key ||
|
|
73
|
-
`${entity_type}__${tabs.columnName}`;
|
|
74
|
-
tabCounts = await this.getJsonbTabCounts(entity_type, flatJsonKey, jsonbConditions);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (sortby && sortby.length > 0) {
|
|
78
|
-
this.applyJsonbSorting(qb, sortby, attributeMetaMap);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
qb.orderBy('ej.created_date', 'DESC');
|
|
82
|
-
}
|
|
83
|
-
const totalCount = await qb.getCount();
|
|
84
|
-
if (page && size) {
|
|
85
|
-
const skip = (page - 1) * size;
|
|
86
|
-
qb.skip(skip).take(size);
|
|
87
|
-
}
|
|
88
|
-
const results = await qb.getMany();
|
|
89
|
-
await this.loggingService.log('info', 'FlatjsonFilterService', 'applyFlatjsonFilter', `Found ${totalCount} total, returning ${results.length} records`);
|
|
90
|
-
const resolvedData = await this.resolveEntityData(results, entity_type, loggedInUser);
|
|
91
|
-
return {
|
|
92
|
-
data: resolvedData,
|
|
93
|
-
total: totalCount,
|
|
94
|
-
page: page || 1,
|
|
95
|
-
size: size || 20,
|
|
96
|
-
totalPages: size ? Math.ceil(totalCount / size) : 1,
|
|
97
|
-
tabCounts: tabCounts.length > 0 ? tabCounts : undefined,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
buildJsonbConditions(filters, attributeMetaMap) {
|
|
101
|
-
const conditions = [];
|
|
102
|
-
for (const filter of filters) {
|
|
103
|
-
const meta = attributeMetaMap[filter.filter_attribute];
|
|
104
|
-
const condition = this.buildJsonbCondition(filter, meta);
|
|
105
|
-
if (condition) {
|
|
106
|
-
conditions.push(condition);
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
console.warn(`Could not build condition for filter: ${filter.filter_attribute}`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return conditions;
|
|
113
|
-
}
|
|
114
|
-
async resolveEntityData(entityJsonRecords, entity_type, loggedInUser) {
|
|
115
|
-
if (entityJsonRecords.length === 0)
|
|
116
|
-
return [];
|
|
117
|
-
const entityIds = entityJsonRecords.map((ej) => ej.entity_id);
|
|
118
|
-
try {
|
|
119
|
-
const fullEntities = await this.resolverService.getResolvedData(entity_type, entityIds, loggedInUser);
|
|
120
|
-
return entityJsonRecords.map((ej) => {
|
|
121
|
-
const fullEntity = fullEntities.find((e) => e.id === ej.entity_id);
|
|
122
|
-
return {
|
|
123
|
-
...fullEntity,
|
|
124
|
-
_flatjson: ej.json_data,
|
|
125
|
-
};
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
console.error('Error resolving entity data:', error);
|
|
130
|
-
return entityJsonRecords.map((ej) => ({
|
|
131
|
-
id: ej.entity_id,
|
|
132
|
-
entity_type: ej.entity_type,
|
|
133
|
-
...ej.json_data,
|
|
134
|
-
}));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
buildJsonbCondition(filter, meta) {
|
|
138
|
-
if (!meta)
|
|
139
|
-
return null;
|
|
140
|
-
const flatJsonKey = meta.flat_json_key ||
|
|
141
|
-
`${meta.mapped_entity_type}__${filter.filter_attribute}`;
|
|
142
|
-
const op = filter.filter_operator;
|
|
143
|
-
const val = filter.filter_value;
|
|
144
|
-
const key = `param_${filter.filter_attribute}_${Math.random().toString(36).substring(2, 8)}`;
|
|
145
|
-
switch (meta.data_type) {
|
|
146
|
-
case 'text':
|
|
147
|
-
return this.buildTextCondition(flatJsonKey, op, val, key);
|
|
148
|
-
case 'number':
|
|
149
|
-
return this.buildNumberCondition(flatJsonKey, op, val, key);
|
|
150
|
-
case 'date':
|
|
151
|
-
return this.buildDateCondition(flatJsonKey, op, val, key);
|
|
152
|
-
case 'select':
|
|
153
|
-
case 'radio':
|
|
154
|
-
return this.buildSelectCondition(flatJsonKey, op, val, key);
|
|
155
|
-
case 'multiselect':
|
|
156
|
-
case 'checkbox':
|
|
157
|
-
return this.buildMultiSelectCondition(flatJsonKey, op, val, key);
|
|
158
|
-
case 'year':
|
|
159
|
-
return this.buildYearCondition(flatJsonKey, op, val, key);
|
|
160
|
-
default:
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
buildTextCondition(flatJsonKey, operator, value, paramKey) {
|
|
165
|
-
const lowerValue = value ? String(value).toLowerCase() : '';
|
|
166
|
-
switch (operator) {
|
|
167
|
-
case 'equal':
|
|
168
|
-
return {
|
|
169
|
-
query: `json_data->>'${flatJsonKey}' = :${paramKey}`,
|
|
170
|
-
params: { [paramKey]: lowerValue },
|
|
171
|
-
};
|
|
172
|
-
case 'not_equal':
|
|
173
|
-
return {
|
|
174
|
-
query: `json_data->>'${flatJsonKey}' != :${paramKey}`,
|
|
175
|
-
params: { [paramKey]: lowerValue },
|
|
176
|
-
};
|
|
177
|
-
case 'contains':
|
|
178
|
-
return {
|
|
179
|
-
query: `json_data->>'${flatJsonKey}' LIKE :${paramKey}`,
|
|
180
|
-
params: { [paramKey]: `%${lowerValue}%` },
|
|
181
|
-
};
|
|
182
|
-
case 'not_contains':
|
|
183
|
-
return {
|
|
184
|
-
query: `json_data->>'${flatJsonKey}' NOT LIKE :${paramKey}`,
|
|
185
|
-
params: { [paramKey]: `%${lowerValue}%` },
|
|
186
|
-
};
|
|
187
|
-
case 'starts_with':
|
|
188
|
-
return {
|
|
189
|
-
query: `json_data->>'${flatJsonKey}' LIKE :${paramKey}`,
|
|
190
|
-
params: { [paramKey]: `${lowerValue}%` },
|
|
191
|
-
};
|
|
192
|
-
case 'ends_with':
|
|
193
|
-
return {
|
|
194
|
-
query: `json_data->>'${flatJsonKey}' LIKE :${paramKey}`,
|
|
195
|
-
params: { [paramKey]: `%${lowerValue}` },
|
|
196
|
-
};
|
|
197
|
-
case 'empty':
|
|
198
|
-
return {
|
|
199
|
-
query: `(json_data->>'${flatJsonKey}' IS NULL OR json_data->>'${flatJsonKey}' = '')`,
|
|
200
|
-
params: {},
|
|
201
|
-
};
|
|
202
|
-
case 'not_empty':
|
|
203
|
-
return {
|
|
204
|
-
query: `(json_data->>'${flatJsonKey}' IS NOT NULL AND json_data->>'${flatJsonKey}' != '')`,
|
|
205
|
-
params: {},
|
|
206
|
-
};
|
|
207
|
-
default:
|
|
208
|
-
console.warn(`Unsupported text operator: ${operator}`);
|
|
209
|
-
return null;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
buildNumberCondition(flatJsonKey, operator, value, paramKey) {
|
|
213
|
-
const jsonbField = `(json_data->>'${flatJsonKey}')::numeric`;
|
|
214
|
-
switch (operator) {
|
|
215
|
-
case 'equal':
|
|
216
|
-
return {
|
|
217
|
-
query: `${jsonbField} = :${paramKey}`,
|
|
218
|
-
params: { [paramKey]: Number(value) },
|
|
219
|
-
};
|
|
220
|
-
case 'not_equal':
|
|
221
|
-
return {
|
|
222
|
-
query: `${jsonbField} != :${paramKey}`,
|
|
223
|
-
params: { [paramKey]: Number(value) },
|
|
224
|
-
};
|
|
225
|
-
case 'greater_than':
|
|
226
|
-
return {
|
|
227
|
-
query: `${jsonbField} > :${paramKey}`,
|
|
228
|
-
params: { [paramKey]: Number(value) },
|
|
229
|
-
};
|
|
230
|
-
case 'less_than':
|
|
231
|
-
return {
|
|
232
|
-
query: `${jsonbField} < :${paramKey}`,
|
|
233
|
-
params: { [paramKey]: Number(value) },
|
|
234
|
-
};
|
|
235
|
-
case 'greater_than_equal_to':
|
|
236
|
-
return {
|
|
237
|
-
query: `${jsonbField} >= :${paramKey}`,
|
|
238
|
-
params: { [paramKey]: Number(value) },
|
|
239
|
-
};
|
|
240
|
-
case 'less_than_equal_to':
|
|
241
|
-
return {
|
|
242
|
-
query: `${jsonbField} <= :${paramKey}`,
|
|
243
|
-
params: { [paramKey]: Number(value) },
|
|
244
|
-
};
|
|
245
|
-
case 'between': {
|
|
246
|
-
let range;
|
|
247
|
-
if (typeof value === 'string') {
|
|
248
|
-
range = value.split(',').map((v) => Number(v.trim()));
|
|
249
|
-
}
|
|
250
|
-
else if (Array.isArray(value)) {
|
|
251
|
-
range = value.map((v) => Number(v));
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
256
|
-
if (range.length !== 2)
|
|
257
|
-
return null;
|
|
258
|
-
return {
|
|
259
|
-
query: `${jsonbField} BETWEEN :${paramKey}_min AND :${paramKey}_max`,
|
|
260
|
-
params: {
|
|
261
|
-
[`${paramKey}_min`]: range[0],
|
|
262
|
-
[`${paramKey}_max`]: range[1],
|
|
263
|
-
},
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
case 'empty':
|
|
267
|
-
return {
|
|
268
|
-
query: `json_data->>'${flatJsonKey}' IS NULL`,
|
|
269
|
-
params: {},
|
|
270
|
-
};
|
|
271
|
-
case 'not_empty':
|
|
272
|
-
return {
|
|
273
|
-
query: `json_data->>'${flatJsonKey}' IS NOT NULL`,
|
|
274
|
-
params: {},
|
|
275
|
-
};
|
|
276
|
-
default:
|
|
277
|
-
console.warn(`Unsupported number operator: ${operator}`);
|
|
278
|
-
return null;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
buildDateCondition(flatJsonKey, operator, value, paramKey) {
|
|
282
|
-
const jsonbField = `(json_data->>'${flatJsonKey}')::bigint`;
|
|
283
|
-
const toEpochMs = (dateStr) => {
|
|
284
|
-
return new Date(dateStr).getTime();
|
|
285
|
-
};
|
|
286
|
-
const daysAgo = (days) => {
|
|
287
|
-
const d = new Date();
|
|
288
|
-
d.setDate(d.getDate() - days);
|
|
289
|
-
return d.getTime();
|
|
290
|
-
};
|
|
291
|
-
const daysFromNow = (days) => {
|
|
292
|
-
const d = new Date();
|
|
293
|
-
d.setDate(d.getDate() + days);
|
|
294
|
-
return d.getTime();
|
|
295
|
-
};
|
|
296
|
-
const subtractBusinessDays = (days) => {
|
|
297
|
-
let d = new Date();
|
|
298
|
-
let count = 0;
|
|
299
|
-
while (count < days) {
|
|
300
|
-
d.setDate(d.getDate() - 1);
|
|
301
|
-
const day = d.getDay();
|
|
302
|
-
if (day !== 0 && day !== 6) {
|
|
303
|
-
count++;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
return d.getTime();
|
|
307
|
-
};
|
|
308
|
-
const numVal = Number(value);
|
|
309
|
-
switch (operator) {
|
|
310
|
-
case 'equal':
|
|
311
|
-
case 'is':
|
|
312
|
-
return {
|
|
313
|
-
query: `${jsonbField} = :${paramKey}`,
|
|
314
|
-
params: { [paramKey]: toEpochMs(value) },
|
|
315
|
-
};
|
|
316
|
-
case 'before':
|
|
317
|
-
case 'is_before':
|
|
318
|
-
return {
|
|
319
|
-
query: `${jsonbField} < :${paramKey}`,
|
|
320
|
-
params: { [paramKey]: toEpochMs(value) },
|
|
321
|
-
};
|
|
322
|
-
case 'after':
|
|
323
|
-
case 'is_after':
|
|
324
|
-
return {
|
|
325
|
-
query: `${jsonbField} > :${paramKey}`,
|
|
326
|
-
params: { [paramKey]: toEpochMs(value) },
|
|
327
|
-
};
|
|
328
|
-
case 'is_on_or_before':
|
|
329
|
-
return {
|
|
330
|
-
query: `${jsonbField} <= :${paramKey}`,
|
|
331
|
-
params: { [paramKey]: toEpochMs(value) },
|
|
332
|
-
};
|
|
333
|
-
case 'is_on_or_after':
|
|
334
|
-
return {
|
|
335
|
-
query: `${jsonbField} >= :${paramKey}`,
|
|
336
|
-
params: { [paramKey]: toEpochMs(value) },
|
|
337
|
-
};
|
|
338
|
-
case 'is_day_before':
|
|
339
|
-
if (isNaN(numVal))
|
|
340
|
-
return null;
|
|
341
|
-
return {
|
|
342
|
-
query: `${jsonbField} <= :${paramKey}`,
|
|
343
|
-
params: { [paramKey]: daysAgo(numVal) },
|
|
344
|
-
};
|
|
345
|
-
case 'is_day_after':
|
|
346
|
-
if (isNaN(numVal))
|
|
347
|
-
return null;
|
|
348
|
-
return {
|
|
349
|
-
query: `${jsonbField} >= :${paramKey}`,
|
|
350
|
-
params: { [paramKey]: daysFromNow(numVal) },
|
|
351
|
-
};
|
|
352
|
-
case 'is_before_business_days':
|
|
353
|
-
if (isNaN(numVal))
|
|
354
|
-
return null;
|
|
355
|
-
return {
|
|
356
|
-
query: `${jsonbField} <= :${paramKey}`,
|
|
357
|
-
params: { [paramKey]: subtractBusinessDays(numVal) },
|
|
358
|
-
};
|
|
359
|
-
case 'between': {
|
|
360
|
-
let range;
|
|
361
|
-
if (typeof value === 'string') {
|
|
362
|
-
range = value.split(',').map((v) => v.trim());
|
|
363
|
-
}
|
|
364
|
-
else if (Array.isArray(value)) {
|
|
365
|
-
range = value;
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
return null;
|
|
369
|
-
}
|
|
370
|
-
if (range.length !== 2)
|
|
371
|
-
return null;
|
|
372
|
-
return {
|
|
373
|
-
query: `${jsonbField} BETWEEN :${paramKey}_start AND :${paramKey}_end`,
|
|
374
|
-
params: {
|
|
375
|
-
[`${paramKey}_start`]: toEpochMs(range[0]),
|
|
376
|
-
[`${paramKey}_end`]: toEpochMs(range[1]),
|
|
377
|
-
},
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
case 'in_last_day':
|
|
381
|
-
if (isNaN(numVal))
|
|
382
|
-
return null;
|
|
383
|
-
return {
|
|
384
|
-
query: `${jsonbField} BETWEEN :${paramKey}_start AND :${paramKey}_end`,
|
|
385
|
-
params: {
|
|
386
|
-
[`${paramKey}_start`]: daysAgo(numVal),
|
|
387
|
-
[`${paramKey}_end`]: Date.now(),
|
|
388
|
-
},
|
|
389
|
-
};
|
|
390
|
-
case 'in_next_day':
|
|
391
|
-
if (isNaN(numVal))
|
|
392
|
-
return null;
|
|
393
|
-
return {
|
|
394
|
-
query: `${jsonbField} BETWEEN :${paramKey}_start AND :${paramKey}_end`,
|
|
395
|
-
params: {
|
|
396
|
-
[`${paramKey}_start`]: Date.now(),
|
|
397
|
-
[`${paramKey}_end`]: daysFromNow(numVal),
|
|
398
|
-
},
|
|
399
|
-
};
|
|
400
|
-
case 'today': {
|
|
401
|
-
const todayStart = new Date().setHours(0, 0, 0, 0);
|
|
402
|
-
const todayEnd = new Date().setHours(23, 59, 59, 999);
|
|
403
|
-
return {
|
|
404
|
-
query: `${jsonbField} BETWEEN :${paramKey}_start AND :${paramKey}_end`,
|
|
405
|
-
params: {
|
|
406
|
-
[`${paramKey}_start`]: todayStart,
|
|
407
|
-
[`${paramKey}_end`]: todayEnd,
|
|
408
|
-
},
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
case 'empty':
|
|
412
|
-
return {
|
|
413
|
-
query: `json_data->>'${flatJsonKey}' IS NULL`,
|
|
414
|
-
params: {},
|
|
415
|
-
};
|
|
416
|
-
case 'not_empty':
|
|
417
|
-
return {
|
|
418
|
-
query: `json_data->>'${flatJsonKey}' IS NOT NULL`,
|
|
419
|
-
params: {},
|
|
420
|
-
};
|
|
421
|
-
default:
|
|
422
|
-
console.warn(`Unsupported date operator: ${operator}`);
|
|
423
|
-
return null;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
buildSelectCondition(flatJsonKey, operator, value, paramKey) {
|
|
427
|
-
switch (operator) {
|
|
428
|
-
case 'equal':
|
|
429
|
-
if (Array.isArray(value)) {
|
|
430
|
-
return {
|
|
431
|
-
query: `json_data->>'${flatJsonKey}' = ANY(:${paramKey})`,
|
|
432
|
-
params: { [paramKey]: value.map(String) },
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
return {
|
|
436
|
-
query: `json_data->>'${flatJsonKey}' = :${paramKey}`,
|
|
437
|
-
params: { [paramKey]: String(value) },
|
|
438
|
-
};
|
|
439
|
-
case 'not_equal':
|
|
440
|
-
if (Array.isArray(value)) {
|
|
441
|
-
return {
|
|
442
|
-
query: `json_data->>'${flatJsonKey}' != ALL(:${paramKey})`,
|
|
443
|
-
params: { [paramKey]: value.map(String) },
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
return {
|
|
447
|
-
query: `json_data->>'${flatJsonKey}' != :${paramKey}`,
|
|
448
|
-
params: { [paramKey]: String(value) },
|
|
449
|
-
};
|
|
450
|
-
case 'in': {
|
|
451
|
-
const inValues = Array.isArray(value) ? value : [value];
|
|
452
|
-
return {
|
|
453
|
-
query: `json_data->>'${flatJsonKey}' = ANY(:${paramKey})`,
|
|
454
|
-
params: { [paramKey]: inValues.map(String) },
|
|
455
|
-
};
|
|
456
|
-
}
|
|
457
|
-
case 'not_in': {
|
|
458
|
-
const notInValues = Array.isArray(value) ? value : [value];
|
|
459
|
-
return {
|
|
460
|
-
query: `json_data->>'${flatJsonKey}' != ALL(:${paramKey})`,
|
|
461
|
-
params: { [paramKey]: notInValues.map(String) },
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
|
-
case 'empty':
|
|
465
|
-
return {
|
|
466
|
-
query: `json_data->>'${flatJsonKey}' IS NULL`,
|
|
467
|
-
params: {},
|
|
468
|
-
};
|
|
469
|
-
case 'not_empty':
|
|
470
|
-
return {
|
|
471
|
-
query: `json_data->>'${flatJsonKey}' IS NOT NULL`,
|
|
472
|
-
params: {},
|
|
473
|
-
};
|
|
474
|
-
default:
|
|
475
|
-
console.warn(`Unsupported select operator: ${operator}`);
|
|
476
|
-
return null;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
buildMultiSelectCondition(flatJsonKey, operator, value, paramKey) {
|
|
480
|
-
let arr;
|
|
481
|
-
if (Array.isArray(value)) {
|
|
482
|
-
arr = value.map(String);
|
|
483
|
-
}
|
|
484
|
-
else if (typeof value === 'string') {
|
|
485
|
-
arr = value.split(',').map((v) => v.trim());
|
|
486
|
-
}
|
|
487
|
-
else {
|
|
488
|
-
arr = [String(value)];
|
|
489
|
-
}
|
|
490
|
-
if (arr.length === 0) {
|
|
491
|
-
return { query: '1=1', params: {} };
|
|
492
|
-
}
|
|
493
|
-
switch (operator) {
|
|
494
|
-
case 'contains':
|
|
495
|
-
case 'has':
|
|
496
|
-
if (arr.length === 1) {
|
|
497
|
-
return {
|
|
498
|
-
query: `json_data->'${flatJsonKey}' ? :${paramKey}`,
|
|
499
|
-
params: { [paramKey]: arr[0] },
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
return {
|
|
503
|
-
query: `json_data->'${flatJsonKey}' ?| ARRAY[:...${paramKey}]::text[]`,
|
|
504
|
-
params: { [paramKey]: arr },
|
|
505
|
-
};
|
|
506
|
-
case 'contains_all':
|
|
507
|
-
return {
|
|
508
|
-
query: `json_data->'${flatJsonKey}' ?& ARRAY[:...${paramKey}]::text[]`,
|
|
509
|
-
params: { [paramKey]: arr },
|
|
510
|
-
};
|
|
511
|
-
case 'contains_any':
|
|
512
|
-
return {
|
|
513
|
-
query: `json_data->'${flatJsonKey}' ?| ARRAY[:...${paramKey}]::text[]`,
|
|
514
|
-
params: { [paramKey]: arr },
|
|
515
|
-
};
|
|
516
|
-
case 'not_contains':
|
|
517
|
-
if (arr.length === 1) {
|
|
518
|
-
return {
|
|
519
|
-
query: `NOT (json_data->'${flatJsonKey}' ? :${paramKey})`,
|
|
520
|
-
params: { [paramKey]: arr[0] },
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
return {
|
|
524
|
-
query: `NOT (json_data->'${flatJsonKey}' ?| ARRAY[:...${paramKey}]::text[])`,
|
|
525
|
-
params: { [paramKey]: arr },
|
|
526
|
-
};
|
|
527
|
-
case 'equal':
|
|
528
|
-
return {
|
|
529
|
-
query: `json_data->'${flatJsonKey}'::jsonb = :${paramKey}::jsonb`,
|
|
530
|
-
params: { [paramKey]: JSON.stringify(arr) },
|
|
531
|
-
};
|
|
532
|
-
case 'empty':
|
|
533
|
-
return {
|
|
534
|
-
query: `(json_data->>'${flatJsonKey}' IS NULL OR json_data->'${flatJsonKey}' = '[]'::jsonb)`,
|
|
535
|
-
params: {},
|
|
536
|
-
};
|
|
537
|
-
case 'not_empty':
|
|
538
|
-
return {
|
|
539
|
-
query: `(json_data->>'${flatJsonKey}' IS NOT NULL AND json_data->'${flatJsonKey}' != '[]'::jsonb)`,
|
|
540
|
-
params: {},
|
|
541
|
-
};
|
|
542
|
-
default:
|
|
543
|
-
console.warn(`Unsupported multiselect operator: ${operator}`);
|
|
544
|
-
return null;
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
buildYearCondition(flatJsonKey, operator, value, paramKey) {
|
|
548
|
-
return this.buildNumberCondition(flatJsonKey, operator, value, paramKey);
|
|
549
|
-
}
|
|
550
|
-
async getJsonbTabCounts(entity_type, flatJsonKey, whereClauses) {
|
|
551
|
-
const qb = this.entityManager
|
|
552
|
-
.getRepository(entityJson_entity_1.EntityJson)
|
|
553
|
-
.createQueryBuilder('ej')
|
|
554
|
-
.select(`json_data->>'${flatJsonKey}'`, 'tab_value')
|
|
555
|
-
.addSelect('COUNT(*)', 'tab_value_count')
|
|
556
|
-
.where('ej.entity_type = :entity_type', { entity_type })
|
|
557
|
-
.groupBy(`json_data->>'${flatJsonKey}'`);
|
|
558
|
-
whereClauses.forEach((condition) => {
|
|
559
|
-
qb.andWhere(condition.query, condition.params);
|
|
560
|
-
});
|
|
561
|
-
const results = await qb.getRawMany();
|
|
562
|
-
return results
|
|
563
|
-
.filter((r) => r.tab_value != null && r.tab_value !== '')
|
|
564
|
-
.map((r) => ({
|
|
565
|
-
tab_value: r.tab_value,
|
|
566
|
-
tab_value_count: parseInt(r.tab_value_count, 10),
|
|
567
|
-
}))
|
|
568
|
-
.sort((a, b) => b.tab_value_count - a.tab_value_count);
|
|
569
|
-
}
|
|
570
|
-
applyJsonbSorting(qb, sortby, attributeMetaMap) {
|
|
571
|
-
sortby.forEach((sort, index) => {
|
|
572
|
-
const meta = attributeMetaMap[sort.sortColum];
|
|
573
|
-
if (!meta) {
|
|
574
|
-
console.warn(`No metadata found for sort column: ${sort.sortColum}`);
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
const flatJsonKey = meta.flat_json_key || `${meta.mapped_entity_type}__${sort.sortColum}`;
|
|
578
|
-
const direction = sort.sortType === 'ASC' ? 'ASC' : 'DESC';
|
|
579
|
-
let sortExpression;
|
|
580
|
-
switch (meta.data_type) {
|
|
581
|
-
case 'number':
|
|
582
|
-
case 'year':
|
|
583
|
-
sortExpression = `(json_data->>'${flatJsonKey}')::numeric`;
|
|
584
|
-
break;
|
|
585
|
-
case 'date':
|
|
586
|
-
sortExpression = `(json_data->>'${flatJsonKey}')::bigint`;
|
|
587
|
-
break;
|
|
588
|
-
case 'text':
|
|
589
|
-
case 'select':
|
|
590
|
-
case 'radio':
|
|
591
|
-
default:
|
|
592
|
-
sortExpression = `json_data->>'${flatJsonKey}'`;
|
|
593
|
-
break;
|
|
594
|
-
}
|
|
595
|
-
if (index === 0) {
|
|
596
|
-
qb.orderBy(sortExpression, direction);
|
|
597
|
-
}
|
|
598
|
-
else {
|
|
599
|
-
qb.addOrderBy(sortExpression, direction);
|
|
600
|
-
}
|
|
601
|
-
});
|
|
602
|
-
}
|
|
603
|
-
};
|
|
604
|
-
exports.FlatjsonFilterService = FlatjsonFilterService;
|
|
605
|
-
exports.FlatjsonFilterService = FlatjsonFilterService = __decorate([
|
|
606
|
-
(0, common_1.Injectable)(),
|
|
607
|
-
__metadata("design:paramtypes", [typeorm_1.EntityManager,
|
|
608
|
-
entity_master_service_1.EntityMasterService,
|
|
609
|
-
attribute_master_service_1.AttributeMasterService,
|
|
610
|
-
resolver_service_1.ResolverService,
|
|
611
|
-
loggingUtil_service_1.LoggingService,
|
|
612
|
-
config_1.ConfigService,
|
|
613
|
-
saved_filter_repository_1.SavedFilterRepositoryService])
|
|
614
|
-
], FlatjsonFilterService);
|
|
615
|
-
//# sourceMappingURL=flatjson-filter.service.js.map
|