@flusys/nestjs-form-builder 5.4.0 → 5.5.0

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.
@@ -60,6 +60,7 @@ let CreateFormDto = class CreateFormDto {
60
60
  _define_property(this, "schema", void 0);
61
61
  _define_property(this, "accessType", void 0);
62
62
  _define_property(this, "actionGroups", void 0);
63
+ _define_property(this, "tags", void 0);
63
64
  _define_property(this, "companyId", void 0);
64
65
  _define_property(this, "isActive", void 0);
65
66
  }
@@ -135,6 +136,22 @@ _ts_decorate([
135
136
  (0, _classvalidator.IsOptional)(),
136
137
  _ts_metadata("design:type", Array)
137
138
  ], CreateFormDto.prototype, "actionGroups", void 0);
139
+ _ts_decorate([
140
+ (0, _swagger.ApiProperty)({
141
+ description: 'Tags used by consuming modules to fetch this form (e.g. survey, review)',
142
+ example: [
143
+ 'survey',
144
+ 'review'
145
+ ],
146
+ required: false
147
+ }),
148
+ (0, _classvalidator.IsArray)(),
149
+ (0, _classvalidator.IsString)({
150
+ each: true
151
+ }),
152
+ (0, _classvalidator.IsOptional)(),
153
+ _ts_metadata("design:type", Array)
154
+ ], CreateFormDto.prototype, "tags", void 0);
138
155
  _ts_decorate([
139
156
  (0, _swagger.ApiProperty)({
140
157
  description: 'Company ID - Only available when company feature is enabled',
@@ -179,7 +196,7 @@ _ts_decorate([
179
196
  ], UpdateFormDto.prototype, "schemaVersion", void 0);
180
197
  let FormResponseDto = class FormResponseDto extends _dtos.IdentityResponseDto {
181
198
  constructor(...args){
182
- super(...args), _define_property(this, "name", void 0), _define_property(this, "description", void 0), _define_property(this, "slug", void 0), _define_property(this, "schema", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "accessType", void 0), _define_property(this, "actionGroups", void 0), _define_property(this, "companyId", void 0), _define_property(this, "isActive", void 0);
199
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "description", void 0), _define_property(this, "slug", void 0), _define_property(this, "schema", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "accessType", void 0), _define_property(this, "actionGroups", void 0), _define_property(this, "tags", void 0), _define_property(this, "companyId", void 0), _define_property(this, "isActive", void 0);
183
200
  }
184
201
  };
185
202
  _ts_decorate([
@@ -219,6 +236,11 @@ _ts_decorate([
219
236
  (0, _swagger.ApiProperty)(),
220
237
  _ts_metadata("design:type", Object)
221
238
  ], FormResponseDto.prototype, "actionGroups", void 0);
239
+ _ts_decorate([
240
+ (0, _classtransformer.Expose)(),
241
+ (0, _swagger.ApiProperty)(),
242
+ _ts_metadata("design:type", Object)
243
+ ], FormResponseDto.prototype, "tags", void 0);
222
244
  _ts_decorate([
223
245
  (0, _classtransformer.Expose)(),
224
246
  (0, _swagger.ApiProperty)(),
@@ -36,7 +36,7 @@ function _ts_metadata(k, v) {
36
36
  }
37
37
  let Form = class Form extends _entities.Identity {
38
38
  constructor(...args){
39
- super(...args), _define_property(this, "name", void 0), _define_property(this, "description", void 0), _define_property(this, "slug", void 0), _define_property(this, "schema", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "accessType", void 0), _define_property(this, "actionGroups", void 0), _define_property(this, "isActive", void 0);
39
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "description", void 0), _define_property(this, "slug", void 0), _define_property(this, "schema", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "accessType", void 0), _define_property(this, "actionGroups", void 0), _define_property(this, "tags", void 0), _define_property(this, "isActive", void 0);
40
40
  }
41
41
  };
42
42
  _ts_decorate([
@@ -96,6 +96,13 @@ _ts_decorate([
96
96
  }),
97
97
  _ts_metadata("design:type", Object)
98
98
  ], Form.prototype, "actionGroups", void 0);
99
+ _ts_decorate([
100
+ (0, _typeorm.Column)({
101
+ type: (0, _nestjsshared.getJsonColumnType)(),
102
+ nullable: true
103
+ }),
104
+ _ts_metadata("design:type", Object)
105
+ ], Form.prototype, "tags", void 0);
99
106
  _ts_decorate([
100
107
  (0, _typeorm.Column)({
101
108
  type: 'boolean',
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "FormService", {
8
8
  return FormService;
9
9
  }
10
10
  });
11
+ const _nestjscore = require("@flusys/nestjs-core");
11
12
  const _classes = require("@flusys/nestjs-shared/classes");
12
13
  const _modules = require("@flusys/nestjs-shared/modules");
13
14
  const _utils = require("@flusys/nestjs-shared/utils");
@@ -109,6 +110,7 @@ let FormService = class FormService extends _classes.ApiService {
109
110
  'schemaVersion',
110
111
  'accessType',
111
112
  'actionGroups',
113
+ 'tags',
112
114
  'isActive',
113
115
  'createdAt',
114
116
  'updatedAt'
@@ -125,6 +127,38 @@ let FormService = class FormService extends _classes.ApiService {
125
127
  isRaw: false
126
128
  };
127
129
  }
130
+ // Supports filtering by one or more tags (array-contains-all) via the generic get-all filter,
131
+ // e.g. { filter: { tags: ['survey', 'review'] } }, since tags is a JSON array column.
132
+ async getFilterQuery(query, filter, user) {
133
+ const { tags, ...rest } = filter;
134
+ if (tags !== undefined && tags !== null) {
135
+ const tagList = (Array.isArray(tags) ? tags : [
136
+ tags
137
+ ]).map(String);
138
+ if (tagList.length > 0) {
139
+ this.applyTagFilter(query, tagList);
140
+ }
141
+ }
142
+ return super.getFilterQuery(query, rest, user);
143
+ }
144
+ applyTagFilter(query, tags) {
145
+ const driver = _nestjscore.envConfig.getTypeOrmConfig().type;
146
+ if (driver === 'postgres') {
147
+ query.andWhere(`${this.entityName}.tags @> :tagValues::jsonb`, {
148
+ tagValues: JSON.stringify(tags)
149
+ });
150
+ } else if (driver === 'mysql') {
151
+ query.andWhere(`JSON_CONTAINS(${this.entityName}.tags, :tagValues)`, {
152
+ tagValues: JSON.stringify(tags)
153
+ });
154
+ } else {
155
+ tags.forEach((tag, index)=>{
156
+ query.andWhere(`${this.entityName}.tags LIKE :tagValue${index}`, {
157
+ [`tagValue${index}`]: `%"${tag}"%`
158
+ });
159
+ });
160
+ }
161
+ }
128
162
  async getExtraManipulateQuery(query, filterDto, user) {
129
163
  const result = await super.getExtraManipulateQuery(query, filterDto, user);
130
164
  // Apply company filter using shared utility
@@ -146,6 +180,7 @@ let FormService = class FormService extends _classes.ApiService {
146
180
  schemaVersion: entity.schemaVersion,
147
181
  accessType: entity.accessType,
148
182
  actionGroups: entity.actionGroups,
183
+ tags: entity.tags,
149
184
  isActive: entity.isActive,
150
185
  companyId: entityWithCompany.companyId ?? null,
151
186
  createdAt: entity.createdAt,
@@ -7,6 +7,7 @@ export declare class CreateFormDto {
7
7
  schema: Record<string, unknown>;
8
8
  accessType?: FormAccessType;
9
9
  actionGroups?: string[];
10
+ tags?: string[];
10
11
  companyId?: string;
11
12
  isActive?: boolean;
12
13
  }
@@ -23,6 +24,7 @@ export declare class FormResponseDto extends IdentityResponseDto {
23
24
  schemaVersion: number;
24
25
  accessType: FormAccessType;
25
26
  actionGroups: string[] | null;
27
+ tags: string[] | null;
26
28
  companyId: string | null;
27
29
  isActive: boolean;
28
30
  }
@@ -8,5 +8,6 @@ export declare class Form extends Identity {
8
8
  schemaVersion: number;
9
9
  accessType: FormAccessType;
10
10
  actionGroups: string[] | null;
11
+ tags: string[] | null;
11
12
  isActive: boolean;
12
13
  }
@@ -33,6 +33,7 @@ export class CreateFormDto {
33
33
  _define_property(this, "schema", void 0);
34
34
  _define_property(this, "accessType", void 0);
35
35
  _define_property(this, "actionGroups", void 0);
36
+ _define_property(this, "tags", void 0);
36
37
  _define_property(this, "companyId", void 0);
37
38
  _define_property(this, "isActive", void 0);
38
39
  }
@@ -108,6 +109,22 @@ _ts_decorate([
108
109
  IsOptional(),
109
110
  _ts_metadata("design:type", Array)
110
111
  ], CreateFormDto.prototype, "actionGroups", void 0);
112
+ _ts_decorate([
113
+ ApiProperty({
114
+ description: 'Tags used by consuming modules to fetch this form (e.g. survey, review)',
115
+ example: [
116
+ 'survey',
117
+ 'review'
118
+ ],
119
+ required: false
120
+ }),
121
+ IsArray(),
122
+ IsString({
123
+ each: true
124
+ }),
125
+ IsOptional(),
126
+ _ts_metadata("design:type", Array)
127
+ ], CreateFormDto.prototype, "tags", void 0);
111
128
  _ts_decorate([
112
129
  ApiProperty({
113
130
  description: 'Company ID - Only available when company feature is enabled',
@@ -152,7 +169,7 @@ _ts_decorate([
152
169
  ], UpdateFormDto.prototype, "schemaVersion", void 0);
153
170
  export class FormResponseDto extends IdentityResponseDto {
154
171
  constructor(...args){
155
- super(...args), _define_property(this, "name", void 0), _define_property(this, "description", void 0), _define_property(this, "slug", void 0), _define_property(this, "schema", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "accessType", void 0), _define_property(this, "actionGroups", void 0), _define_property(this, "companyId", void 0), _define_property(this, "isActive", void 0);
172
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "description", void 0), _define_property(this, "slug", void 0), _define_property(this, "schema", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "accessType", void 0), _define_property(this, "actionGroups", void 0), _define_property(this, "tags", void 0), _define_property(this, "companyId", void 0), _define_property(this, "isActive", void 0);
156
173
  }
157
174
  }
158
175
  _ts_decorate([
@@ -192,6 +209,11 @@ _ts_decorate([
192
209
  ApiProperty(),
193
210
  _ts_metadata("design:type", Object)
194
211
  ], FormResponseDto.prototype, "actionGroups", void 0);
212
+ _ts_decorate([
213
+ Expose(),
214
+ ApiProperty(),
215
+ _ts_metadata("design:type", Object)
216
+ ], FormResponseDto.prototype, "tags", void 0);
195
217
  _ts_decorate([
196
218
  Expose(),
197
219
  ApiProperty(),
@@ -26,7 +26,7 @@ import { Column, Entity, Index } from 'typeorm';
26
26
  import { FormAccessType } from '../enums/form-access-type.enum';
27
27
  export class Form extends Identity {
28
28
  constructor(...args){
29
- super(...args), _define_property(this, "name", void 0), _define_property(this, "description", void 0), _define_property(this, "slug", void 0), _define_property(this, "schema", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "accessType", void 0), _define_property(this, "actionGroups", void 0), _define_property(this, "isActive", void 0);
29
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "description", void 0), _define_property(this, "slug", void 0), _define_property(this, "schema", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "accessType", void 0), _define_property(this, "actionGroups", void 0), _define_property(this, "tags", void 0), _define_property(this, "isActive", void 0);
30
30
  }
31
31
  }
32
32
  _ts_decorate([
@@ -86,6 +86,13 @@ _ts_decorate([
86
86
  }),
87
87
  _ts_metadata("design:type", Object)
88
88
  ], Form.prototype, "actionGroups", void 0);
89
+ _ts_decorate([
90
+ Column({
91
+ type: getJsonColumnType(),
92
+ nullable: true
93
+ }),
94
+ _ts_metadata("design:type", Object)
95
+ ], Form.prototype, "tags", void 0);
89
96
  _ts_decorate([
90
97
  Column({
91
98
  type: 'boolean',
@@ -25,6 +25,7 @@ function _ts_param(paramIndex, decorator) {
25
25
  decorator(target, key, paramIndex);
26
26
  };
27
27
  }
28
+ import { envConfig } from '@flusys/nestjs-core';
28
29
  import { HybridCache, ApiService } from '@flusys/nestjs-shared/classes';
29
30
  import { UtilsService } from '@flusys/nestjs-shared/modules';
30
31
  import { applyCompanyFilter } from '@flusys/nestjs-shared/utils';
@@ -99,6 +100,7 @@ export class FormService extends ApiService {
99
100
  'schemaVersion',
100
101
  'accessType',
101
102
  'actionGroups',
103
+ 'tags',
102
104
  'isActive',
103
105
  'createdAt',
104
106
  'updatedAt'
@@ -115,6 +117,38 @@ export class FormService extends ApiService {
115
117
  isRaw: false
116
118
  };
117
119
  }
120
+ // Supports filtering by one or more tags (array-contains-all) via the generic get-all filter,
121
+ // e.g. { filter: { tags: ['survey', 'review'] } }, since tags is a JSON array column.
122
+ async getFilterQuery(query, filter, user) {
123
+ const { tags, ...rest } = filter;
124
+ if (tags !== undefined && tags !== null) {
125
+ const tagList = (Array.isArray(tags) ? tags : [
126
+ tags
127
+ ]).map(String);
128
+ if (tagList.length > 0) {
129
+ this.applyTagFilter(query, tagList);
130
+ }
131
+ }
132
+ return super.getFilterQuery(query, rest, user);
133
+ }
134
+ applyTagFilter(query, tags) {
135
+ const driver = envConfig.getTypeOrmConfig().type;
136
+ if (driver === 'postgres') {
137
+ query.andWhere(`${this.entityName}.tags @> :tagValues::jsonb`, {
138
+ tagValues: JSON.stringify(tags)
139
+ });
140
+ } else if (driver === 'mysql') {
141
+ query.andWhere(`JSON_CONTAINS(${this.entityName}.tags, :tagValues)`, {
142
+ tagValues: JSON.stringify(tags)
143
+ });
144
+ } else {
145
+ tags.forEach((tag, index)=>{
146
+ query.andWhere(`${this.entityName}.tags LIKE :tagValue${index}`, {
147
+ [`tagValue${index}`]: `%"${tag}"%`
148
+ });
149
+ });
150
+ }
151
+ }
118
152
  async getExtraManipulateQuery(query, filterDto, user) {
119
153
  const result = await super.getExtraManipulateQuery(query, filterDto, user);
120
154
  // Apply company filter using shared utility
@@ -136,6 +170,7 @@ export class FormService extends ApiService {
136
170
  schemaVersion: entity.schemaVersion,
137
171
  accessType: entity.accessType,
138
172
  actionGroups: entity.actionGroups,
173
+ tags: entity.tags,
139
174
  isActive: entity.isActive,
140
175
  companyId: entityWithCompany.companyId ?? null,
141
176
  createdAt: entity.createdAt,
@@ -8,6 +8,7 @@ export interface IForm extends IIdentity {
8
8
  schemaVersion: number;
9
9
  accessType: FormAccessType;
10
10
  actionGroups: string[] | null;
11
+ tags: string[] | null;
11
12
  isActive: boolean;
12
13
  companyId: string | null;
13
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-form-builder",
3
- "version": "5.4.0",
3
+ "version": "5.5.0",
4
4
  "description": "Dynamic form builder module with schema versioning and access control",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -79,12 +79,12 @@
79
79
  "@nestjs/swagger": "^11.0.0",
80
80
  "@nestjs/typeorm": "^11.0.0",
81
81
  "class-transformer": "^0.5.1",
82
- "class-validator": "^0.14.0 || ^0.15.0",
82
+ "class-validator": "^0.15.0",
83
83
  "typeorm": "^0.3.0",
84
- "express": "^4.18.0 || ^5.0.0"
84
+ "express": "^5.0.0"
85
85
  },
86
86
  "dependencies": {
87
- "@flusys/nestjs-core": "5.4.0",
88
- "@flusys/nestjs-shared": "5.4.0"
87
+ "@flusys/nestjs-core": "5.5.0",
88
+ "@flusys/nestjs-shared": "5.5.0"
89
89
  }
90
90
  }
@@ -20,6 +20,11 @@ export declare class FormService extends ApiService<CreateFormDto, UpdateFormDto
20
20
  query: SelectQueryBuilder<Form>;
21
21
  isRaw: boolean;
22
22
  }>;
23
+ protected getFilterQuery(query: SelectQueryBuilder<Form>, filter: Record<string, unknown>, user: ILoggedUserInfo | null): Promise<{
24
+ query: SelectQueryBuilder<Form>;
25
+ isRaw: boolean;
26
+ }>;
27
+ private applyTagFilter;
23
28
  protected getExtraManipulateQuery(query: SelectQueryBuilder<Form>, filterDto: FilterAndPaginationDto, user: ILoggedUserInfo | null): Promise<{
24
29
  query: SelectQueryBuilder<Form>;
25
30
  isRaw: boolean;