rez_core 6.5.75 → 6.5.77
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/constant/db-data-type.constant.d.ts +30 -0
- package/dist/constant/db-data-type.constant.js +59 -0
- package/dist/constant/db-data-type.constant.js.map +1 -0
- package/dist/constant/storage-type.constant.d.ts +4 -0
- package/dist/constant/storage-type.constant.js +9 -0
- package/dist/constant/storage-type.constant.js.map +1 -0
- package/dist/module/eav/controller/eav.controller.d.ts +21 -0
- package/dist/module/eav/controller/eav.controller.js +127 -0
- package/dist/module/eav/controller/eav.controller.js.map +1 -0
- package/dist/module/eav/dto/eav-operation.dto.d.ts +20 -0
- package/dist/module/eav/dto/eav-operation.dto.js +75 -0
- package/dist/module/eav/dto/eav-operation.dto.js.map +1 -0
- package/dist/module/eav/eav.module.d.ts +2 -0
- package/dist/module/eav/eav.module.js +84 -0
- package/dist/module/eav/eav.module.js.map +1 -0
- package/dist/module/eav/entity/eav-boolean.entity.d.ts +9 -0
- package/dist/module/eav/entity/eav-boolean.entity.js +48 -0
- package/dist/module/eav/entity/eav-boolean.entity.js.map +1 -0
- package/dist/module/eav/entity/eav-date.entity.d.ts +9 -0
- package/dist/module/eav/entity/eav-date.entity.js +48 -0
- package/dist/module/eav/entity/eav-date.entity.js.map +1 -0
- package/dist/module/eav/entity/eav-decimal.entity.d.ts +9 -0
- package/dist/module/eav/entity/eav-decimal.entity.js +48 -0
- package/dist/module/eav/entity/eav-decimal.entity.js.map +1 -0
- package/dist/module/eav/entity/eav-int.entity.d.ts +9 -0
- package/dist/module/eav/entity/eav-int.entity.js +48 -0
- package/dist/module/eav/entity/eav-int.entity.js.map +1 -0
- package/dist/module/eav/entity/eav-json.entity.d.ts +9 -0
- package/dist/module/eav/entity/eav-json.entity.js +48 -0
- package/dist/module/eav/entity/eav-json.entity.js.map +1 -0
- package/dist/module/eav/entity/eav-text.entity.d.ts +9 -0
- package/dist/module/eav/entity/eav-text.entity.js +48 -0
- package/dist/module/eav/entity/eav-text.entity.js.map +1 -0
- package/dist/module/eav/entity/eav-time.entity.d.ts +9 -0
- package/dist/module/eav/entity/eav-time.entity.js +48 -0
- package/dist/module/eav/entity/eav-time.entity.js.map +1 -0
- package/dist/module/eav/entity/eav-timestamp.entity.d.ts +9 -0
- package/dist/module/eav/entity/eav-timestamp.entity.js +48 -0
- package/dist/module/eav/entity/eav-timestamp.entity.js.map +1 -0
- package/dist/module/eav/entity/eav-varchar.entity.d.ts +9 -0
- package/dist/module/eav/entity/eav-varchar.entity.js +48 -0
- package/dist/module/eav/entity/eav-varchar.entity.js.map +1 -0
- package/dist/module/eav/interface/eav-strategy.interface.d.ts +8 -0
- package/dist/module/eav/interface/eav-strategy.interface.js +3 -0
- package/dist/module/eav/interface/eav-strategy.interface.js.map +1 -0
- package/dist/module/eav/repository/eav-boolean.repository.d.ts +13 -0
- package/dist/module/eav/repository/eav-boolean.repository.js +57 -0
- package/dist/module/eav/repository/eav-boolean.repository.js.map +1 -0
- package/dist/module/eav/repository/eav-date.repository.d.ts +13 -0
- package/dist/module/eav/repository/eav-date.repository.js +57 -0
- package/dist/module/eav/repository/eav-date.repository.js.map +1 -0
- package/dist/module/eav/repository/eav-decimal.repository.d.ts +13 -0
- package/dist/module/eav/repository/eav-decimal.repository.js +57 -0
- package/dist/module/eav/repository/eav-decimal.repository.js.map +1 -0
- package/dist/module/eav/repository/eav-int.repository.d.ts +13 -0
- package/dist/module/eav/repository/eav-int.repository.js +57 -0
- package/dist/module/eav/repository/eav-int.repository.js.map +1 -0
- package/dist/module/eav/repository/eav-json.repository.d.ts +13 -0
- package/dist/module/eav/repository/eav-json.repository.js +57 -0
- package/dist/module/eav/repository/eav-json.repository.js.map +1 -0
- package/dist/module/eav/repository/eav-text.repository.d.ts +13 -0
- package/dist/module/eav/repository/eav-text.repository.js +57 -0
- package/dist/module/eav/repository/eav-text.repository.js.map +1 -0
- package/dist/module/eav/repository/eav-time.repository.d.ts +13 -0
- package/dist/module/eav/repository/eav-time.repository.js +57 -0
- package/dist/module/eav/repository/eav-time.repository.js.map +1 -0
- package/dist/module/eav/repository/eav-timestamp.repository.d.ts +13 -0
- package/dist/module/eav/repository/eav-timestamp.repository.js +57 -0
- package/dist/module/eav/repository/eav-timestamp.repository.js.map +1 -0
- package/dist/module/eav/repository/eav-varchar.repository.d.ts +13 -0
- package/dist/module/eav/repository/eav-varchar.repository.js +57 -0
- package/dist/module/eav/repository/eav-varchar.repository.js.map +1 -0
- package/dist/module/eav/service/eav-boolean.service.d.ts +12 -0
- package/dist/module/eav/service/eav-boolean.service.js +59 -0
- package/dist/module/eav/service/eav-boolean.service.js.map +1 -0
- package/dist/module/eav/service/eav-date.service.d.ts +12 -0
- package/dist/module/eav/service/eav-date.service.js +59 -0
- package/dist/module/eav/service/eav-date.service.js.map +1 -0
- package/dist/module/eav/service/eav-decimal.service.d.ts +12 -0
- package/dist/module/eav/service/eav-decimal.service.js +59 -0
- package/dist/module/eav/service/eav-decimal.service.js.map +1 -0
- package/dist/module/eav/service/eav-factory.service.d.ts +26 -0
- package/dist/module/eav/service/eav-factory.service.js +81 -0
- package/dist/module/eav/service/eav-factory.service.js.map +1 -0
- package/dist/module/eav/service/eav-int.service.d.ts +12 -0
- package/dist/module/eav/service/eav-int.service.js +59 -0
- package/dist/module/eav/service/eav-int.service.js.map +1 -0
- package/dist/module/eav/service/eav-json.service.d.ts +12 -0
- package/dist/module/eav/service/eav-json.service.js +59 -0
- package/dist/module/eav/service/eav-json.service.js.map +1 -0
- package/dist/module/eav/service/eav-text.service.d.ts +12 -0
- package/dist/module/eav/service/eav-text.service.js +59 -0
- package/dist/module/eav/service/eav-text.service.js.map +1 -0
- package/dist/module/eav/service/eav-time.service.d.ts +12 -0
- package/dist/module/eav/service/eav-time.service.js +59 -0
- package/dist/module/eav/service/eav-time.service.js.map +1 -0
- package/dist/module/eav/service/eav-timestamp.service.d.ts +12 -0
- package/dist/module/eav/service/eav-timestamp.service.js +59 -0
- package/dist/module/eav/service/eav-timestamp.service.js.map +1 -0
- package/dist/module/eav/service/eav-varchar.service.d.ts +12 -0
- package/dist/module/eav/service/eav-varchar.service.js +59 -0
- package/dist/module/eav/service/eav-varchar.service.js.map +1 -0
- package/dist/module/eav/service/eav.service.d.ts +14 -0
- package/dist/module/eav/service/eav.service.js +65 -0
- package/dist/module/eav/service/eav.service.js.map +1 -0
- package/dist/module/enterprise/entity/brand.entity.d.ts +0 -0
- package/dist/module/enterprise/entity/brand.entity.js +1 -0
- package/dist/module/enterprise/entity/brand.entity.js.map +1 -0
- package/dist/module/enterprise/entity/school.entity.d.ts +0 -0
- package/dist/module/enterprise/entity/school.entity.js +1 -0
- package/dist/module/enterprise/entity/school.entity.js.map +1 -0
- package/dist/module/enterprise/repository/brand.repository.d.ts +0 -0
- package/dist/module/enterprise/repository/brand.repository.js +1 -0
- package/dist/module/enterprise/repository/brand.repository.js.map +1 -0
- package/dist/module/meta/entity/brand-profile.entity.d.ts +3 -0
- package/dist/module/meta/entity/brand-profile.entity.js +18 -0
- package/dist/module/meta/entity/brand-profile.entity.js.map +1 -0
- package/dist/module/meta/entity/dynamic.entity.d.ts +3 -0
- package/dist/module/meta/entity/dynamic.entity.js +8 -0
- package/dist/module/meta/entity/dynamic.entity.js.map +1 -0
- package/dist/module/meta/entity/field-group.entity.d.ts +0 -0
- package/dist/module/meta/entity/field-group.entity.js +1 -0
- package/dist/module/meta/entity/field-group.entity.js.map +1 -0
- package/dist/module/meta/entity/school.entity.d.ts +8 -0
- package/dist/module/meta/entity/school.entity.js +44 -0
- package/dist/module/meta/entity/school.entity.js.map +1 -0
- package/dist/module/meta/entity/schoolAddress.entity.d.ts +9 -0
- package/dist/module/meta/entity/schoolAddress.entity.js +48 -0
- package/dist/module/meta/entity/schoolAddress.entity.js.map +1 -0
- package/dist/module/meta/entity/section-master.entity.d.ts +0 -0
- package/dist/module/meta/entity/section-master.entity.js +1 -0
- package/dist/module/meta/entity/section-master.entity.js.map +1 -0
- package/dist/module/meta/entity/user-app-mapping.entity.d.ts +0 -0
- package/dist/module/meta/entity/user-app-mapping.entity.js +1 -0
- package/dist/module/meta/entity/user-app-mapping.entity.js.map +1 -0
- package/dist/resources/dev.properties.yaml +31 -0
- package/dist/resources/local.properties.yaml +27 -0
- package/dist/resources/uat.properties.yaml +31 -0
- package/dist/table.config.d.ts +3 -3
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/app.module.ts +3 -1
- package/src/constant/db-data-type.constant.ts +81 -0
- package/src/constant/storage-type.constant.ts +4 -0
- package/src/module/eav/EAV_USAGE_GUIDE.md +351 -0
- package/src/module/eav/controller/eav.controller.ts +119 -0
- package/src/module/eav/dto/eav-operation.dto.ts +62 -0
- package/src/module/eav/eav.module.ts +80 -0
- package/src/module/eav/entity/eav-boolean.entity.ts +26 -0
- package/src/module/eav/entity/eav-date.entity.ts +25 -0
- package/src/module/eav/entity/eav-decimal.entity.ts +25 -0
- package/src/module/eav/entity/eav-int.entity.ts +25 -0
- package/src/module/eav/entity/eav-json.entity.ts +25 -0
- package/src/module/eav/entity/eav-text.entity.ts +25 -0
- package/src/module/eav/entity/eav-time.entity.ts +25 -0
- package/src/module/eav/entity/eav-timestamp.entity.ts +25 -0
- package/src/module/eav/entity/eav-varchar.entity.ts +25 -0
- package/src/module/eav/interface/eav-strategy.interface.ts +32 -0
- package/src/module/eav/repository/eav-boolean.repository.ts +67 -0
- package/src/module/eav/repository/eav-date.repository.ts +67 -0
- package/src/module/eav/repository/eav-decimal.repository.ts +67 -0
- package/src/module/eav/repository/eav-int.repository.ts +67 -0
- package/src/module/eav/repository/eav-json.repository.ts +67 -0
- package/src/module/eav/repository/eav-text.repository.ts +67 -0
- package/src/module/eav/repository/eav-time.repository.ts +67 -0
- package/src/module/eav/repository/eav-timestamp.repository.ts +67 -0
- package/src/module/eav/repository/eav-varchar.repository.ts +67 -0
- package/src/module/eav/service/eav-boolean.service.ts +64 -0
- package/src/module/eav/service/eav-date.service.ts +64 -0
- package/src/module/eav/service/eav-decimal.service.ts +64 -0
- package/src/module/eav/service/eav-factory.service.ts +93 -0
- package/src/module/eav/service/eav-int.service.ts +64 -0
- package/src/module/eav/service/eav-json.service.ts +64 -0
- package/src/module/eav/service/eav-text.service.ts +64 -0
- package/src/module/eav/service/eav-time.service.ts +64 -0
- package/src/module/eav/service/eav-timestamp.service.ts +64 -0
- package/src/module/eav/service/eav-varchar.service.ts +65 -0
- package/src/module/eav/service/eav.service.ts +116 -0
- package/src/module/listmaster/service/list-master-item.service.ts +11 -61
- package/src/module/meta/controller/entity.controller.ts +2 -10
- package/src/module/meta/entity/base-entity.entity.ts +3 -0
- package/src/module/meta/entity/dynamic.entity.ts +4 -0
- package/src/module/meta/entity/entity-master.entity.ts +16 -52
- package/src/module/meta/service/entity-master.service.ts +135 -6
- package/src/module/meta/service/media-data.service.ts +0 -206
package/package.json
CHANGED
package/src/app.module.ts
CHANGED
|
@@ -29,6 +29,7 @@ import { LinkedAttributesModule } from './module/linked_attributes/linked_attrib
|
|
|
29
29
|
import { EntityJSONModule } from './module/entity_json/entity_json.module';
|
|
30
30
|
import { ExportModule } from './module/export/export.module';
|
|
31
31
|
import { AppMasterModule } from './module/app_master/app-master.module';
|
|
32
|
+
import { EAVModule } from './module/eav/eav.module';
|
|
32
33
|
|
|
33
34
|
@Module({
|
|
34
35
|
imports: [
|
|
@@ -64,7 +65,8 @@ import { AppMasterModule } from './module/app_master/app-master.module';
|
|
|
64
65
|
EntityJSONModule,
|
|
65
66
|
ExportModule,
|
|
66
67
|
EntityModule,
|
|
67
|
-
AppMasterModule
|
|
68
|
+
AppMasterModule,
|
|
69
|
+
EAVModule
|
|
68
70
|
],
|
|
69
71
|
})
|
|
70
72
|
export class AppModule { }
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EAV Data Type Enum
|
|
3
|
+
* Defines all supported data types for Entity-Attribute-Value storage
|
|
4
|
+
*/
|
|
5
|
+
export enum EavDataType {
|
|
6
|
+
// String types
|
|
7
|
+
VARCHAR = 'varchar',
|
|
8
|
+
STRING = 'string', // Alias for VARCHAR
|
|
9
|
+
|
|
10
|
+
// Numeric types
|
|
11
|
+
INT = 'int',
|
|
12
|
+
INTEGER = 'integer', // Alias for INT
|
|
13
|
+
DECIMAL = 'decimal',
|
|
14
|
+
FLOAT = 'float', // Alias for DECIMAL
|
|
15
|
+
|
|
16
|
+
// Boolean type
|
|
17
|
+
BOOLEAN = 'boolean',
|
|
18
|
+
BOOL = 'bool', // Alias for BOOLEAN
|
|
19
|
+
|
|
20
|
+
// Text types
|
|
21
|
+
TEXT = 'text',
|
|
22
|
+
JSON = 'json',
|
|
23
|
+
|
|
24
|
+
// Date/Time types
|
|
25
|
+
DATE = 'date',
|
|
26
|
+
TIME = 'time',
|
|
27
|
+
TIMESTAMP = 'timestamp',
|
|
28
|
+
DATETIME = 'datetime', // Alias for TIMESTAMP
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Primary EAV Data Types (without aliases)
|
|
33
|
+
* Use this for mapping to actual database tables
|
|
34
|
+
*/
|
|
35
|
+
export enum EavPrimaryDataType {
|
|
36
|
+
VARCHAR = 'varchar',
|
|
37
|
+
INT = 'int',
|
|
38
|
+
DECIMAL = 'decimal',
|
|
39
|
+
BOOLEAN = 'boolean',
|
|
40
|
+
TEXT = 'text',
|
|
41
|
+
JSON = 'json',
|
|
42
|
+
DATE = 'date',
|
|
43
|
+
TIME = 'time',
|
|
44
|
+
TIMESTAMP = 'timestamp',
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Map of data type aliases to their primary types
|
|
49
|
+
*/
|
|
50
|
+
export const EAV_DATA_TYPE_ALIAS_MAP: Record<string, EavPrimaryDataType> = {
|
|
51
|
+
[EavDataType.VARCHAR]: EavPrimaryDataType.VARCHAR,
|
|
52
|
+
[EavDataType.STRING]: EavPrimaryDataType.VARCHAR,
|
|
53
|
+
[EavDataType.INT]: EavPrimaryDataType.INT,
|
|
54
|
+
[EavDataType.INTEGER]: EavPrimaryDataType.INT,
|
|
55
|
+
[EavDataType.DECIMAL]: EavPrimaryDataType.DECIMAL,
|
|
56
|
+
[EavDataType.FLOAT]: EavPrimaryDataType.DECIMAL,
|
|
57
|
+
[EavDataType.BOOLEAN]: EavPrimaryDataType.BOOLEAN,
|
|
58
|
+
[EavDataType.BOOL]: EavPrimaryDataType.BOOLEAN,
|
|
59
|
+
[EavDataType.TEXT]: EavPrimaryDataType.TEXT,
|
|
60
|
+
[EavDataType.JSON]: EavPrimaryDataType.JSON,
|
|
61
|
+
[EavDataType.DATE]: EavPrimaryDataType.DATE,
|
|
62
|
+
[EavDataType.TIME]: EavPrimaryDataType.TIME,
|
|
63
|
+
[EavDataType.TIMESTAMP]: EavPrimaryDataType.TIMESTAMP,
|
|
64
|
+
[EavDataType.DATETIME]: EavPrimaryDataType.TIMESTAMP,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get the primary data type from an alias or primary type
|
|
69
|
+
*/
|
|
70
|
+
export function getPrimaryDataType(dataType: string): EavPrimaryDataType | null {
|
|
71
|
+
const normalized = dataType.toLowerCase().trim();
|
|
72
|
+
return EAV_DATA_TYPE_ALIAS_MAP[normalized] || null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Check if a data type is supported
|
|
77
|
+
*/
|
|
78
|
+
export function isValidEavDataType(dataType: string): boolean {
|
|
79
|
+
const normalized = dataType.toLowerCase().trim();
|
|
80
|
+
return normalized in EAV_DATA_TYPE_ALIAS_MAP;
|
|
81
|
+
}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# EAV Module Usage Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The EAV (Entity-Attribute-Value) module provides a flexible way to store dynamic attributes for entities using different data types. It implements the **Strategy Pattern** and **Factory Pattern** for clean, maintainable code.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
graph TD
|
|
11
|
+
A[EavService - Orchestrator] --> B[EavFactoryService]
|
|
12
|
+
B --> C[IEavStrategy Interface]
|
|
13
|
+
C --> D[EavVarcharService]
|
|
14
|
+
C --> E[EavIntService]
|
|
15
|
+
C --> F[EavBooleanService]
|
|
16
|
+
C --> G[EavDecimalService]
|
|
17
|
+
C --> H[EavTextService]
|
|
18
|
+
C --> I[EavJsonService]
|
|
19
|
+
C --> J[EavDateService]
|
|
20
|
+
C --> K[EavTimeService]
|
|
21
|
+
C --> L[EavTimestampService]
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Supported Data Types
|
|
25
|
+
|
|
26
|
+
- `varchar` / `string` - String values
|
|
27
|
+
- `int` / `integer` - Integer values
|
|
28
|
+
- `boolean` / `bool` - Boolean values
|
|
29
|
+
- `decimal` / `float` - Decimal/Float values
|
|
30
|
+
- `text` - Large text values
|
|
31
|
+
- `json` - JSON objects
|
|
32
|
+
- `date` - Date values
|
|
33
|
+
- `time` - Time values
|
|
34
|
+
- `timestamp` / `datetime` - Timestamp values
|
|
35
|
+
|
|
36
|
+
## Basic Usage
|
|
37
|
+
|
|
38
|
+
### 1. Import the Module
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { Module } from '@nestjs/common';
|
|
42
|
+
import { EavModule } from './module/eav/eav.module';
|
|
43
|
+
|
|
44
|
+
@Module({
|
|
45
|
+
imports: [EavModule],
|
|
46
|
+
})
|
|
47
|
+
export class AppModule {}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Inject the Service
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { Injectable } from '@nestjs/common';
|
|
54
|
+
import { EavService } from './module/eav/service/eav.service';
|
|
55
|
+
|
|
56
|
+
@Injectable()
|
|
57
|
+
export class YourService {
|
|
58
|
+
constructor(private readonly eavService: EavService) {}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. Perform CRUD Operations
|
|
63
|
+
|
|
64
|
+
#### Create a Record
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// Create a varchar attribute
|
|
68
|
+
const result = await this.eavService.create('varchar', {
|
|
69
|
+
entity_type: 'user',
|
|
70
|
+
entity_id: 123,
|
|
71
|
+
key: 'nickname',
|
|
72
|
+
value: 'JohnDoe',
|
|
73
|
+
}, 1); // modifiedBy user ID
|
|
74
|
+
|
|
75
|
+
// Create an integer attribute
|
|
76
|
+
await this.eavService.create('int', {
|
|
77
|
+
entity_type: 'product',
|
|
78
|
+
entity_id: 456,
|
|
79
|
+
key: 'stock_quantity',
|
|
80
|
+
value: 100,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Create a JSON attribute
|
|
84
|
+
await this.eavService.create('json', {
|
|
85
|
+
entity_type: 'user',
|
|
86
|
+
entity_id: 123,
|
|
87
|
+
key: 'preferences',
|
|
88
|
+
value: { theme: 'dark', language: 'en' },
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### Find One Record
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const attribute = await this.eavService.findOne('varchar', {
|
|
96
|
+
entity_type: 'user',
|
|
97
|
+
entity_id: 123,
|
|
98
|
+
key: 'nickname',
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
console.log(attribute.value); // 'JohnDoe'
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### Find All Records
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// Find all attributes for a specific entity
|
|
108
|
+
const userAttributes = await this.eavService.findAll('varchar', {
|
|
109
|
+
entity_type: 'user',
|
|
110
|
+
entity_id: 123,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Find all attributes of a type for an entity type
|
|
114
|
+
const allUserVarchars = await this.eavService.findAll('varchar', {
|
|
115
|
+
entity_type: 'user',
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Update a Record
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const updated = await this.eavService.update(
|
|
123
|
+
'varchar',
|
|
124
|
+
{
|
|
125
|
+
entity_type: 'user',
|
|
126
|
+
entity_id: 123,
|
|
127
|
+
key: 'nickname',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
value: 'JaneDoe',
|
|
131
|
+
},
|
|
132
|
+
1, // modifiedBy user ID
|
|
133
|
+
);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Delete a Record
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const deleted = await this.eavService.delete('varchar', {
|
|
140
|
+
entity_type: 'user',
|
|
141
|
+
entity_id: 123,
|
|
142
|
+
key: 'nickname',
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
console.log(deleted); // true if deleted, false otherwise
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### Upsert (Create or Update)
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// Will create if doesn't exist, update if exists
|
|
152
|
+
const result = await this.eavService.upsert('varchar', {
|
|
153
|
+
entity_type: 'user',
|
|
154
|
+
entity_id: 123,
|
|
155
|
+
key: 'nickname',
|
|
156
|
+
value: 'UpdatedNickname',
|
|
157
|
+
}, 1);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Advanced Usage
|
|
161
|
+
|
|
162
|
+
### Using the Factory Directly
|
|
163
|
+
|
|
164
|
+
If you need more control, you can inject the factory service:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { EavFactoryService } from './module/eav/service/eav-factory.service';
|
|
168
|
+
|
|
169
|
+
@Injectable()
|
|
170
|
+
export class YourService {
|
|
171
|
+
constructor(private readonly eavFactory: EavFactoryService) {}
|
|
172
|
+
|
|
173
|
+
async customOperation() {
|
|
174
|
+
// Get the service for a specific type
|
|
175
|
+
const varcharService = this.eavFactory.getService('varchar');
|
|
176
|
+
|
|
177
|
+
// Use the service directly
|
|
178
|
+
const result = await varcharService.create({
|
|
179
|
+
entity_type: 'custom',
|
|
180
|
+
entity_id: 999,
|
|
181
|
+
key: 'custom_key',
|
|
182
|
+
value: 'custom_value',
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Type Checking
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
// Check if a type is supported
|
|
192
|
+
const isSupported = this.eavService.isTypeSupported('varchar'); // true
|
|
193
|
+
const notSupported = this.eavService.isTypeSupported('unknown'); // false
|
|
194
|
+
|
|
195
|
+
// Get all supported types
|
|
196
|
+
const types = this.eavService.getSupportedTypes();
|
|
197
|
+
console.log(types); // ['varchar', 'string', 'int', 'integer', ...]
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## REST API Examples (Using the Controller)
|
|
201
|
+
|
|
202
|
+
### Create
|
|
203
|
+
```bash
|
|
204
|
+
POST /eav/varchar?modifiedBy=1
|
|
205
|
+
Content-Type: application/json
|
|
206
|
+
|
|
207
|
+
{
|
|
208
|
+
"entity_type": "user",
|
|
209
|
+
"entity_id": 123,
|
|
210
|
+
"key": "nickname",
|
|
211
|
+
"value": "JohnDoe"
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Find One
|
|
216
|
+
```bash
|
|
217
|
+
GET /eav/varchar/find-one?entity_type=user&entity_id=123&key=nickname
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Find All
|
|
221
|
+
```bash
|
|
222
|
+
GET /eav/varchar?entity_type=user&entity_id=123
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Update
|
|
226
|
+
```bash
|
|
227
|
+
PUT /eav/varchar?entity_type=user&entity_id=123&key=nickname&modifiedBy=1
|
|
228
|
+
Content-Type: application/json
|
|
229
|
+
|
|
230
|
+
{
|
|
231
|
+
"value": "JaneDoe"
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Delete
|
|
236
|
+
```bash
|
|
237
|
+
DELETE /eav/varchar?entity_type=user&entity_id=123&key=nickname
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Upsert
|
|
241
|
+
```bash
|
|
242
|
+
POST /eav/varchar/upsert?modifiedBy=1
|
|
243
|
+
Content-Type: application/json
|
|
244
|
+
|
|
245
|
+
{
|
|
246
|
+
"entity_type": "user",
|
|
247
|
+
"entity_id": 123,
|
|
248
|
+
"key": "nickname",
|
|
249
|
+
"value": "UpdatedNickname"
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Get Supported Types
|
|
254
|
+
```bash
|
|
255
|
+
GET /eav/meta/supported-types
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Design Pattern Benefits
|
|
259
|
+
|
|
260
|
+
### Strategy Pattern
|
|
261
|
+
- Each data type has its own service implementing `IEavStrategy`
|
|
262
|
+
- Easy to add new data types without modifying existing code
|
|
263
|
+
- Each service is independently testable
|
|
264
|
+
|
|
265
|
+
### Factory Pattern
|
|
266
|
+
- `EavFactoryService` resolves the correct service based on data type
|
|
267
|
+
- Centralizes service selection logic
|
|
268
|
+
- Supports type aliases (e.g., 'string' → 'varchar')
|
|
269
|
+
|
|
270
|
+
### Facade Pattern
|
|
271
|
+
- `EavService` provides a simple, unified interface
|
|
272
|
+
- Hides complexity of service resolution
|
|
273
|
+
- Makes it easy for consumers to use the module
|
|
274
|
+
|
|
275
|
+
## Error Handling
|
|
276
|
+
|
|
277
|
+
The factory will throw a `BadRequestException` if an unsupported data type is provided:
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
try {
|
|
281
|
+
await this.eavService.create('unsupported_type', {...});
|
|
282
|
+
} catch (error) {
|
|
283
|
+
// BadRequestException: Unsupported data type: unsupported_type
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Best Practices
|
|
288
|
+
|
|
289
|
+
1. **Always specify the correct data type** - Use the appropriate type for your data
|
|
290
|
+
2. **Use upsert when appropriate** - Simplifies create-or-update logic
|
|
291
|
+
3. **Track modifications** - Pass `modifiedBy` to track who made changes
|
|
292
|
+
4. **Validate input** - The DTOs include validation decorators
|
|
293
|
+
5. **Handle errors** - Always wrap calls in try-catch for production code
|
|
294
|
+
|
|
295
|
+
## Example: Complete User Preferences System
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
@Injectable()
|
|
299
|
+
export class UserPreferencesService {
|
|
300
|
+
constructor(private readonly eavService: EavService) {}
|
|
301
|
+
|
|
302
|
+
async setPreference(userId: number, key: string, value: any, type: string) {
|
|
303
|
+
return await this.eavService.upsert(type, {
|
|
304
|
+
entity_type: 'user_preferences',
|
|
305
|
+
entity_id: userId,
|
|
306
|
+
key,
|
|
307
|
+
value,
|
|
308
|
+
}, userId);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async getPreference(userId: number, key: string, type: string) {
|
|
312
|
+
return await this.eavService.findOne(type, {
|
|
313
|
+
entity_type: 'user_preferences',
|
|
314
|
+
entity_id: userId,
|
|
315
|
+
key,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async getAllPreferences(userId: number) {
|
|
320
|
+
// Get preferences from different types
|
|
321
|
+
const varchars = await this.eavService.findAll('varchar', {
|
|
322
|
+
entity_type: 'user_preferences',
|
|
323
|
+
entity_id: userId,
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
const booleans = await this.eavService.findAll('boolean', {
|
|
327
|
+
entity_type: 'user_preferences',
|
|
328
|
+
entity_id: userId,
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
const jsons = await this.eavService.findAll('json', {
|
|
332
|
+
entity_type: 'user_preferences',
|
|
333
|
+
entity_id: userId,
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
strings: varchars,
|
|
338
|
+
flags: booleans,
|
|
339
|
+
objects: jsons,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async deletePreference(userId: number, key: string, type: string) {
|
|
344
|
+
return await this.eavService.delete(type, {
|
|
345
|
+
entity_type: 'user_preferences',
|
|
346
|
+
entity_id: userId,
|
|
347
|
+
key,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
```
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Controller,
|
|
3
|
+
Get,
|
|
4
|
+
Post,
|
|
5
|
+
Put,
|
|
6
|
+
Delete,
|
|
7
|
+
Body,
|
|
8
|
+
Param,
|
|
9
|
+
Query,
|
|
10
|
+
HttpCode,
|
|
11
|
+
HttpStatus,
|
|
12
|
+
} from '@nestjs/common';
|
|
13
|
+
import { EAVService } from '../service/eav.service';
|
|
14
|
+
import { CreateEAVDto, UpdateEAVDto, EAVQueryDto } from '../dto/eav-operation.dto';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Example EAV Controller
|
|
18
|
+
* Demonstrates how to use the EAV service for CRUD operations
|
|
19
|
+
*/
|
|
20
|
+
@Controller('eav')
|
|
21
|
+
export class EavController {
|
|
22
|
+
constructor(private readonly eavService: EAVService) { }
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Create a new EAV record
|
|
26
|
+
* POST /eav/:dataType
|
|
27
|
+
* Body: { entity_type, entity_id, key, value }
|
|
28
|
+
*/
|
|
29
|
+
@Post(':dataType')
|
|
30
|
+
@HttpCode(HttpStatus.CREATED)
|
|
31
|
+
async create(
|
|
32
|
+
@Param('dataType') dataType: string,
|
|
33
|
+
@Body() createDto: CreateEAVDto,
|
|
34
|
+
@Query('modifiedBy') modifiedBy?: number,
|
|
35
|
+
) {
|
|
36
|
+
return await this.eavService.create(dataType, createDto, modifiedBy);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Find a single EAV record
|
|
41
|
+
* GET /eav/:dataType/find-one?entity_type=xxx&entity_id=xxx&key=xxx
|
|
42
|
+
*/
|
|
43
|
+
@Get(':dataType/find-one')
|
|
44
|
+
async findOne(@Param('dataType') dataType: string, @Query() query: EAVQueryDto) {
|
|
45
|
+
return await this.eavService.findOne(dataType, query);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Find all EAV records matching the query
|
|
50
|
+
* GET /eav/:dataType?entity_type=xxx&entity_id=xxx
|
|
51
|
+
*/
|
|
52
|
+
@Get(':dataType')
|
|
53
|
+
async findAll(@Param('dataType') dataType: string, @Query() query: Partial<EAVQueryDto>) {
|
|
54
|
+
return await this.eavService.findAll(dataType, query);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Update an existing EAV record
|
|
59
|
+
* PUT /eav/:dataType?entity_type=xxx&entity_id=xxx&key=xxx
|
|
60
|
+
* Body: { value }
|
|
61
|
+
*/
|
|
62
|
+
@Put(':dataType')
|
|
63
|
+
async update(
|
|
64
|
+
@Param('dataType') dataType: string,
|
|
65
|
+
@Query() query: EAVQueryDto,
|
|
66
|
+
@Body() updateDto: UpdateEAVDto,
|
|
67
|
+
@Query('modifiedBy') modifiedBy?: number,
|
|
68
|
+
) {
|
|
69
|
+
return await this.eavService.update(dataType, query, updateDto, modifiedBy);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Delete an EAV record
|
|
74
|
+
* DELETE /eav/:dataType?entity_type=xxx&entity_id=xxx&key=xxx
|
|
75
|
+
*/
|
|
76
|
+
@Delete(':dataType')
|
|
77
|
+
@HttpCode(HttpStatus.NO_CONTENT)
|
|
78
|
+
async delete(@Param('dataType') dataType: string, @Query() query: EAVQueryDto) {
|
|
79
|
+
const deleted = await this.eavService.delete(dataType, query);
|
|
80
|
+
return { deleted };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Upsert (create or update) an EAV record
|
|
85
|
+
* POST /eav/:dataType/upsert
|
|
86
|
+
* Body: { entity_type, entity_id, key, value }
|
|
87
|
+
*/
|
|
88
|
+
@Post(':dataType/upsert')
|
|
89
|
+
async upsert(
|
|
90
|
+
@Param('dataType') dataType: string,
|
|
91
|
+
@Body() createDto: CreateEAVDto,
|
|
92
|
+
@Query('modifiedBy') modifiedBy?: number,
|
|
93
|
+
) {
|
|
94
|
+
return await this.eavService.upsert(dataType, createDto, modifiedBy);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get all supported data types
|
|
99
|
+
* GET /eav/meta/supported-types
|
|
100
|
+
*/
|
|
101
|
+
@Get('meta/supported-types')
|
|
102
|
+
getSupportedTypes() {
|
|
103
|
+
return {
|
|
104
|
+
supportedTypes: this.eavService.getSupportedTypes(),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Check if a data type is supported
|
|
110
|
+
* GET /eav/meta/is-supported/:dataType
|
|
111
|
+
*/
|
|
112
|
+
@Get('meta/is-supported/:dataType')
|
|
113
|
+
isTypeSupported(@Param('dataType') dataType: string) {
|
|
114
|
+
return {
|
|
115
|
+
dataType,
|
|
116
|
+
isSupported: this.eavService.isTypeSupported(dataType),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { IsNotEmpty, IsString, IsOptional, IsNumber } from 'class-validator';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DTO for creating EAV records
|
|
5
|
+
*/
|
|
6
|
+
export class CreateEAVDto {
|
|
7
|
+
@IsNotEmpty()
|
|
8
|
+
@IsString()
|
|
9
|
+
entity_type: string;
|
|
10
|
+
|
|
11
|
+
@IsNotEmpty()
|
|
12
|
+
entity_id: string | number;
|
|
13
|
+
|
|
14
|
+
@IsNotEmpty()
|
|
15
|
+
@IsString()
|
|
16
|
+
key: string;
|
|
17
|
+
|
|
18
|
+
@IsNotEmpty()
|
|
19
|
+
value: any;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* DTO for updating EAV records
|
|
24
|
+
*/
|
|
25
|
+
export class UpdateEAVDto {
|
|
26
|
+
@IsNotEmpty()
|
|
27
|
+
value: any;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* DTO for querying EAV records
|
|
32
|
+
*/
|
|
33
|
+
export class EAVQueryDto {
|
|
34
|
+
@IsNotEmpty()
|
|
35
|
+
@IsString()
|
|
36
|
+
entity_type: string;
|
|
37
|
+
|
|
38
|
+
@IsNotEmpty()
|
|
39
|
+
entity_id: string | number;
|
|
40
|
+
|
|
41
|
+
@IsNotEmpty()
|
|
42
|
+
@IsString()
|
|
43
|
+
key: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* DTO for EAV operations with data type
|
|
48
|
+
*/
|
|
49
|
+
export class EavOperationDto extends CreateEAVDto {
|
|
50
|
+
@IsNotEmpty()
|
|
51
|
+
@IsString()
|
|
52
|
+
data_type: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* DTO for EAV query with data type
|
|
57
|
+
*/
|
|
58
|
+
export class EavQueryWithTypeDto extends EAVQueryDto {
|
|
59
|
+
@IsNotEmpty()
|
|
60
|
+
@IsString()
|
|
61
|
+
data_type: string;
|
|
62
|
+
}
|