@ackplus/nest-crud-request 0.1.51 → 1.1.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.
Files changed (41) hide show
  1. package/README.md +6 -130
  2. package/dist/index.d.ts +4 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/{src → dist}/lib/query-builder.d.ts +1 -0
  5. package/dist/lib/query-builder.d.ts.map +1 -0
  6. package/{src → dist}/lib/query-builder.js +23 -16
  7. package/{src → dist}/lib/relation-builder.d.ts +1 -0
  8. package/dist/lib/relation-builder.d.ts.map +1 -0
  9. package/{src → dist}/lib/relation-builder.js +2 -6
  10. package/dist/lib/types.d.ts +53 -0
  11. package/dist/lib/types.d.ts.map +1 -0
  12. package/dist/lib/types.js +31 -0
  13. package/{src → dist}/lib/utils.d.ts +1 -0
  14. package/dist/lib/utils.d.ts.map +1 -0
  15. package/dist/lib/utils.js +11 -0
  16. package/{src → dist}/lib/where-builder.d.ts +4 -0
  17. package/dist/lib/where-builder.d.ts.map +1 -0
  18. package/{src → dist}/lib/where-builder.js +30 -13
  19. package/eslint.config.mjs +22 -0
  20. package/jest.config.ts +10 -0
  21. package/package.json +2 -20
  22. package/project.json +46 -0
  23. package/src/index.ts +3 -0
  24. package/src/lib/query-builder.ts +189 -0
  25. package/src/lib/relation-builder.ts +68 -0
  26. package/src/lib/types.js +1 -0
  27. package/src/lib/types.js.map +1 -0
  28. package/src/lib/types.ts +61 -0
  29. package/src/lib/utils.ts +11 -0
  30. package/src/lib/where-builder.ts +159 -0
  31. package/src/test/query-builder-where.spec.ts +173 -0
  32. package/src/test/query-builder.spec.ts +140 -0
  33. package/src/test/relation-builder.spec.ts +32 -0
  34. package/src/test/where-builder-complex.spec.ts +173 -0
  35. package/tsconfig.json +17 -0
  36. package/tsconfig.lib.json +10 -0
  37. package/tsconfig.spec.json +15 -0
  38. package/src/index.js +0 -6
  39. package/src/lib/utils.js +0 -11
  40. package/tsconfig.tsbuildinfo +0 -1
  41. /package/{src/index.d.ts → dist/index.js} +0 -0
package/README.md CHANGED
@@ -1,135 +1,11 @@
1
- # @ackplus/nest-crud-request
1
+ # nest-crud-request
2
2
 
3
- A frontend utility package for building and formatting requests compatible with @ackplus/nest-crud backend. This package provides a type-safe way to construct CRUD requests with proper query parameters, filters, sorting, and pagination.
3
+ This library was generated with [Nx](https://nx.dev).
4
4
 
5
- ## Features
5
+ ## Building
6
6
 
7
- - Type-safe request builder
8
- - Query parameter construction
9
- - Filter builder
10
- - Sort builder
11
- - Search builder
12
- - Pagination builder
13
- - Request validation
14
- - Automatic URL parameter encoding
7
+ Run `nx build nest-crud-request` to build the library.
15
8
 
16
- ## Installation
9
+ ## Running unit tests
17
10
 
18
- ```bash
19
- npm install @ackplus/nest-crud-request
20
- # or
21
- yarn add @ackplus/nest-crud-request
22
- ```
23
-
24
- ## Quick Start
25
-
26
- 1. Import the request builder:
27
-
28
- ```typescript
29
- import { CrudRequestBuilder } from '@ackplus/nest-crud-request';
30
- ```
31
-
32
- 2. Create and use the request builder:
33
-
34
- ```typescript
35
- // Create a new request builder
36
- const request = new CrudRequestBuilder();
37
-
38
- // Add pagination
39
- request.paginate(1, 10);
40
-
41
- // Add sorting
42
- request.sort('name', 'asc');
43
-
44
- // Add filters
45
- request.filter('status', 'active');
46
-
47
- // Add search
48
- request.search('john');
49
-
50
- // Build the request
51
- const queryParams = request.build();
52
- // Result: ?page=1&limit=10&sort=name&order=asc&filter[status]=active&search=john
53
-
54
- // Use with your HTTP client
55
- const response = await axios.get(`/api/users${queryParams}`);
56
- ```
57
-
58
- ## API Documentation
59
-
60
- ### CrudRequestBuilder
61
-
62
- The main class for building CRUD requests.
63
-
64
- #### Methods
65
-
66
- - `paginate(page: number, limit: number)` - Set pagination parameters
67
- - `sort(field: string, order: 'asc' | 'desc')` - Add sort parameters
68
- - `filter(field: string, value: any)` - Add filter conditions
69
- - `search(term: string)` - Add search term
70
- - `build()` - Build the request and return query string
71
-
72
- ### Types
73
-
74
- - `CrudRequest` - Type definition for the request structure
75
- - `Filter` - Type for filter conditions
76
- - `Sort` - Type for sort conditions
77
- - `Pagination` - Type for pagination parameters
78
-
79
- ## Examples
80
-
81
- ### Basic Usage
82
-
83
- ```typescript
84
- const request = new CrudRequestBuilder()
85
- .paginate(1, 10)
86
- .sort('createdAt', 'desc')
87
- .filter('status', 'active')
88
- .search('john')
89
- .build();
90
-
91
- // Use with fetch
92
- const response = await fetch(`/api/users${request}`);
93
- ```
94
-
95
- ### Advanced Filtering
96
-
97
- ```typescript
98
- const request = new CrudRequestBuilder()
99
- .filter('age', { $gt: 18 })
100
- .filter('status', { $in: ['active', 'pending'] })
101
- .build();
102
-
103
- // Result: ?filter[age][$gt]=18&filter[status][$in]=active,pending
104
- ```
105
-
106
- ### Multiple Sorts
107
-
108
- ```typescript
109
- const request = new CrudRequestBuilder()
110
- .sort('name', 'asc')
111
- .sort('age', 'desc')
112
- .build();
113
-
114
- // Result: ?sort=name,age&order=asc,desc
115
- ```
116
-
117
- ### Complex Search
118
-
119
- ```typescript
120
- const request = new CrudRequestBuilder()
121
- .search('john doe')
122
- .filter('department', 'IT')
123
- .paginate(1, 20)
124
- .build();
125
-
126
- // Result: ?search=john%20doe&filter[department]=IT&page=1&limit=20
127
- ```
128
-
129
- ## Contributing
130
-
131
- Contributions are welcome! Please feel free to submit a Pull Request.
132
-
133
- ## License
134
-
135
- This project is licensed under the terms of the MIT license.
11
+ Run `nx test nest-crud-request` to execute the unit tests via [Jest](https://jestjs.io).
@@ -0,0 +1,4 @@
1
+ export * from './lib/query-builder';
2
+ export * from './lib/where-builder';
3
+ export * from './lib/types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC"}
@@ -34,3 +34,4 @@ export declare class QueryBuilder {
34
34
  };
35
35
  toJson(): string;
36
36
  }
37
+ //# sourceMappingURL=query-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-builder.d.ts","sourceRoot":"","sources":["../../src/lib/query-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElE,OAAO,EAAgB,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGtE,qBAAa,YAAY;IAErB,OAAO,CAAC,OAAO,CAA2B;IAE1C,OAAO,CAAC,YAAY,CAAoC;IAExD,OAAO,CAAC,eAAe,CAA0C;gBAErD,OAAO,CAAC,EAAE,mBAAmB;IAMzC,UAAU,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAO9C,YAAY,CAAC,OAAO,EAAE,mBAAmB,EAAE,IAAI,UAAQ,GAAG,IAAI;IAc9D,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IAa1C,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IAY7C,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAKnF,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKtC,KAAK,CAAC,GAAG,IAAI,EAAE,qBAAqB,GAAG,IAAI;IAK3C,QAAQ,CAAC,GAAG,IAAI,EAAE,qBAAqB,GAAG,IAAI;IAK9C,OAAO,CAAC,GAAG,IAAI,EAAE,qBAAqB,GAAG,IAAI;IAK7C,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAQ1D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOlC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK3B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK3B,cAAc,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI;IAK1C,cAAc,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI;IAK1C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAKlC,QAAQ,CAAC,uBAAuB,UAAQ;;;;;;;;;;;IAoDxC,MAAM;CAKT"}
@@ -1,36 +1,37 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QueryBuilder = void 0;
4
- const relation_builder_1 = require("./relation-builder");
5
- const utils_1 = require("./utils");
6
- const where_builder_1 = require("./where-builder");
7
- class QueryBuilder {
1
+ import { RelationBuilder } from './relation-builder';
2
+ import { deepMerge } from './utils';
3
+ import { WhereBuilder } from './where-builder';
4
+ export class QueryBuilder {
5
+ options = {};
6
+ whereBuilder = new WhereBuilder();
7
+ relationBuilder = new RelationBuilder();
8
8
  constructor(options) {
9
- this.options = {};
10
- this.whereBuilder = new where_builder_1.WhereBuilder();
11
- this.relationBuilder = new relation_builder_1.RelationBuilder();
12
9
  if (options) {
13
10
  this.setOptions(options);
14
11
  }
15
12
  }
16
13
  setOptions(options) {
17
14
  this.options = options;
18
- this.whereBuilder = new where_builder_1.WhereBuilder(options.where);
19
- this.relationBuilder = new relation_builder_1.RelationBuilder(options.relations);
15
+ this.whereBuilder = new WhereBuilder(options.where);
16
+ this.relationBuilder = new RelationBuilder(options.relations);
20
17
  return this;
21
18
  }
22
19
  mergeOptions(options, deep = false) {
23
20
  let updatedOptions = {};
24
21
  if (deep) {
25
- updatedOptions = (0, utils_1.deepMerge)(this.options, options);
22
+ updatedOptions = deepMerge(this.options, options);
26
23
  }
27
24
  else {
28
- updatedOptions = Object.assign(Object.assign({}, this.options), options);
25
+ updatedOptions = {
26
+ ...this.options,
27
+ ...options,
28
+ };
29
29
  }
30
30
  this.setOptions(updatedOptions);
31
31
  return this;
32
32
  }
33
33
  addSelect(fields) {
34
+ // Ensure select is always an array
34
35
  if (!this.options.select || typeof this.options.select === 'string') {
35
36
  this.options.select = [];
36
37
  }
@@ -43,6 +44,7 @@ class QueryBuilder {
43
44
  return this;
44
45
  }
45
46
  removeSelect(fields) {
47
+ // Ensure select is an array before filtering
46
48
  if (this.options.select && Array.isArray(this.options.select)) {
47
49
  if (Array.isArray(fields)) {
48
50
  this.options.select = this.options.select.filter(field => !fields.includes(field));
@@ -107,7 +109,10 @@ class QueryBuilder {
107
109
  return this;
108
110
  }
109
111
  toObject(constrainToNestedObject = false) {
110
- const options = Object.assign({}, this.options);
112
+ const options = {
113
+ ...this.options,
114
+ };
115
+ // Convert where conditions to JSON string
111
116
  if (this.whereBuilder.hasConditions()) {
112
117
  if (constrainToNestedObject) {
113
118
  options.where = this.whereBuilder.toObject();
@@ -119,6 +124,7 @@ class QueryBuilder {
119
124
  else {
120
125
  delete options.where;
121
126
  }
127
+ // Convert relations to JSON string
122
128
  if (this.relationBuilder.hasRelations()) {
123
129
  if (constrainToNestedObject) {
124
130
  options.relations = this.relationBuilder.toObject();
@@ -130,6 +136,7 @@ class QueryBuilder {
130
136
  else {
131
137
  delete options.relations;
132
138
  }
139
+ // Convert order to JSON string if it exists
133
140
  if (options.order && Object.keys(options.order).length > 0) {
134
141
  if (constrainToNestedObject) {
135
142
  options.order = options.order;
@@ -141,6 +148,7 @@ class QueryBuilder {
141
148
  else {
142
149
  delete options.order;
143
150
  }
151
+ // Convert select to JSON string if it exists
144
152
  if (options.select && options.select.length > 0) {
145
153
  if (constrainToNestedObject) {
146
154
  options.select = options.select;
@@ -159,4 +167,3 @@ class QueryBuilder {
159
167
  return JSON.stringify(obj);
160
168
  }
161
169
  }
162
- exports.QueryBuilder = QueryBuilder;
@@ -10,3 +10,4 @@ export declare class RelationBuilder {
10
10
  toObject(): RelationObject;
11
11
  toJson(): string;
12
12
  }
13
+ //# sourceMappingURL=relation-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relation-builder.d.ts","sourceRoot":"","sources":["../../src/lib/relation-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAuB,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/E,qBAAa,eAAe;IAExB,OAAO,CAAC,SAAS,CAAsB;gBAE3B,SAAS,CAAC,EAAE,eAAe,GAAG,MAAM;IAOhD,YAAY,CAAC,SAAS,EAAE,eAAe,GAAG,IAAI;IAe9C,KAAK,IAAI,IAAI;IAKb,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAgB3E,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK9B,YAAY,IAAI,OAAO;IAIvB,QAAQ,IAAI,cAAc;IAI1B,MAAM,IAAI,MAAM;CAInB"}
@@ -1,9 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RelationBuilder = void 0;
4
- class RelationBuilder {
1
+ export class RelationBuilder {
2
+ relations = {};
5
3
  constructor(relations) {
6
- this.relations = {};
7
4
  if (relations) {
8
5
  const relationOptions = typeof relations === 'string' ? JSON.parse(relations) : relations;
9
6
  this.setRelations(relationOptions);
@@ -59,4 +56,3 @@ class RelationBuilder {
59
56
  return JSON.stringify(this.relations);
60
57
  }
61
58
  }
62
- exports.RelationBuilder = RelationBuilder;
@@ -0,0 +1,53 @@
1
+ export interface QueryBuilderOptions {
2
+ [key: string]: any;
3
+ select?: string[] | string;
4
+ relations?: RelationOptions | string;
5
+ where?: WhereOptions | string;
6
+ order?: Record<string, OrderDirectionEnum> | string;
7
+ skip?: number;
8
+ take?: number;
9
+ withDeleted?: boolean;
10
+ onlyDeleted?: boolean;
11
+ }
12
+ export declare enum WhereLogicalOperatorEnum {
13
+ AND = "$and",
14
+ OR = "$or"
15
+ }
16
+ export declare enum WhereOperatorEnum {
17
+ EQ = "$eq",
18
+ NOT_EQ = "$ne",
19
+ GT = "$gt",
20
+ GT_OR_EQ = "$gte",
21
+ LT = "$lt",
22
+ LT_OR_EQ = "$lte",
23
+ IN = "$in",
24
+ NOT_IN = "$notIn",
25
+ LIKE = "$like",
26
+ NOT_LIKE = "$notLike",
27
+ ILIKE = "$iLike",
28
+ NOT_ILIKE = "$notIlike",
29
+ IS_NULL = "$isNull",
30
+ IS_NOT_NULL = "$isNotNull",
31
+ BETWEEN = "$between",
32
+ NOT_BETWEEN = "$notBetween",
33
+ IS_TRUE = "$isTrue",
34
+ IS_FALSE = "$isFalse"
35
+ }
36
+ export declare enum OrderDirectionEnum {
37
+ ASC = "ASC",
38
+ DESC = "DESC"
39
+ }
40
+ export type WhereObject = {
41
+ [key: string]: any;
42
+ $and?: WhereObject | WhereObject[];
43
+ $or?: WhereObject | WhereObject[];
44
+ };
45
+ export type WhereOptions = WhereObject | WhereObject[];
46
+ export type RelationObjectValue = {
47
+ select?: string[];
48
+ where?: WhereObject | WhereObject[];
49
+ joinType?: 'left' | 'inner';
50
+ };
51
+ export type RelationObject = Record<string, RelationObjectValue | boolean>;
52
+ export type RelationOptions = string | string[] | RelationObject;
53
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC;IACrC,KAAK,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,MAAM,CAAC;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,oBAAY,wBAAwB;IAChC,GAAG,SAAS;IACZ,EAAE,QAAQ;CACb;AAED,oBAAY,iBAAiB;IACzB,EAAE,QAAQ;IACV,MAAM,QAAQ;IACd,EAAE,QAAQ;IACV,QAAQ,SAAS;IACjB,EAAE,QAAQ;IACV,QAAQ,SAAS;IACjB,EAAE,QAAQ;IACV,MAAM,WAAW;IACjB,IAAI,UAAU;IACd,QAAQ,aAAa;IACrB,KAAK,WAAW;IAChB,SAAS,cAAc;IACvB,OAAO,YAAY;IACnB,WAAW,eAAe;IAC1B,OAAO,aAAa;IACpB,WAAW,gBAAgB;IAC3B,OAAO,YAAY;IACnB,QAAQ,aAAa;CACxB;AAED,oBAAY,kBAAkB;IAC1B,GAAG,QAAQ;IACX,IAAI,SAAS;CAChB;AAED,MAAM,MAAM,WAAW,GAAG;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,IAAI,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE,CAAC;IACnC,GAAG,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,WAAW,EAAE,CAAC;AAGvD,MAAM,MAAM,mBAAmB,GAAG;IAC9B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,CAAC;AAE3E,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,cAAc,CAAC"}
@@ -0,0 +1,31 @@
1
+ export var WhereLogicalOperatorEnum;
2
+ (function (WhereLogicalOperatorEnum) {
3
+ WhereLogicalOperatorEnum["AND"] = "$and";
4
+ WhereLogicalOperatorEnum["OR"] = "$or";
5
+ })(WhereLogicalOperatorEnum || (WhereLogicalOperatorEnum = {}));
6
+ export var WhereOperatorEnum;
7
+ (function (WhereOperatorEnum) {
8
+ WhereOperatorEnum["EQ"] = "$eq";
9
+ WhereOperatorEnum["NOT_EQ"] = "$ne";
10
+ WhereOperatorEnum["GT"] = "$gt";
11
+ WhereOperatorEnum["GT_OR_EQ"] = "$gte";
12
+ WhereOperatorEnum["LT"] = "$lt";
13
+ WhereOperatorEnum["LT_OR_EQ"] = "$lte";
14
+ WhereOperatorEnum["IN"] = "$in";
15
+ WhereOperatorEnum["NOT_IN"] = "$notIn";
16
+ WhereOperatorEnum["LIKE"] = "$like";
17
+ WhereOperatorEnum["NOT_LIKE"] = "$notLike";
18
+ WhereOperatorEnum["ILIKE"] = "$iLike";
19
+ WhereOperatorEnum["NOT_ILIKE"] = "$notIlike";
20
+ WhereOperatorEnum["IS_NULL"] = "$isNull";
21
+ WhereOperatorEnum["IS_NOT_NULL"] = "$isNotNull";
22
+ WhereOperatorEnum["BETWEEN"] = "$between";
23
+ WhereOperatorEnum["NOT_BETWEEN"] = "$notBetween";
24
+ WhereOperatorEnum["IS_TRUE"] = "$isTrue";
25
+ WhereOperatorEnum["IS_FALSE"] = "$isFalse";
26
+ })(WhereOperatorEnum || (WhereOperatorEnum = {}));
27
+ export var OrderDirectionEnum;
28
+ (function (OrderDirectionEnum) {
29
+ OrderDirectionEnum["ASC"] = "ASC";
30
+ OrderDirectionEnum["DESC"] = "DESC";
31
+ })(OrderDirectionEnum || (OrderDirectionEnum = {}));
@@ -1 +1,2 @@
1
1
  export declare function deepMerge(target: any, source: any): any;
2
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,GAAG,CAUvD"}
@@ -0,0 +1,11 @@
1
+ export function deepMerge(target, source) {
2
+ for (const key in source) {
3
+ if (source[key] instanceof Object && key in target) {
4
+ Object.assign(source[key], deepMerge(target[key], source[key]));
5
+ }
6
+ }
7
+ return {
8
+ ...target,
9
+ ...source,
10
+ };
11
+ }
@@ -14,5 +14,9 @@ export declare class WhereBuilder {
14
14
  toJson(): string;
15
15
  private parseCondition;
16
16
  private updateCondition;
17
+ /**
18
+ * Intelligently merge two condition objects, handling logical operators properly
19
+ */
17
20
  private mergeConditions;
18
21
  }
22
+ //# sourceMappingURL=where-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"where-builder.d.ts","sourceRoot":"","sources":["../../src/lib/where-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAGtE,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC,CAAC;AAEjJ,qBAAa,YAAY;IAErB,OAAO,CAAC,WAAW,CAA2B;gBAElC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM;IAIhD,OAAO,CAAC,UAAU;IAIlB,KAAK,IAAI,IAAI;IAKb,KAAK,CAAC,GAAG,IAAI,EAAE,qBAAqB,GAAG,IAAI;IAK3C,QAAQ,CAAC,GAAG,IAAI,EAAE,qBAAqB,GAAG,IAAI;IAK9C,OAAO,CAAC,GAAG,IAAI,EAAE,qBAAqB,GAAG,IAAI;IAK7C,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAehC,aAAa,IAAI,OAAO;IAIxB,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAI/B,MAAM,IAAI,MAAM;IAIhB,OAAO,CAAC,cAAc;IAuDtB,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACH,OAAO,CAAC,eAAe;CA0B1B"}
@@ -1,10 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WhereBuilder = void 0;
4
- const types_1 = require("./types");
5
- class WhereBuilder {
1
+ import { WhereLogicalOperatorEnum, WhereOperatorEnum } from './types';
2
+ export class WhereBuilder {
3
+ whereObject = {};
6
4
  constructor(where) {
7
- this.whereObject = {};
8
5
  this.whereObject = typeof where === 'string' ? JSON.parse(where) : where || {};
9
6
  }
10
7
  isOperator(value) {
@@ -19,11 +16,11 @@ class WhereBuilder {
19
16
  return this;
20
17
  }
21
18
  andWhere(...args) {
22
- this.parseCondition(types_1.WhereLogicalOperatorEnum.AND, ...args);
19
+ this.parseCondition(WhereLogicalOperatorEnum.AND, ...args);
23
20
  return this;
24
21
  }
25
22
  orWhere(...args) {
26
- this.parseCondition(types_1.WhereLogicalOperatorEnum.OR, ...args);
23
+ this.parseCondition(WhereLogicalOperatorEnum.OR, ...args);
27
24
  return this;
28
25
  }
29
26
  removeWhere(field) {
@@ -31,7 +28,7 @@ class WhereBuilder {
31
28
  let current = this.whereObject;
32
29
  for (let i = 0; i < keys.length - 1; i++) {
33
30
  if (!current[keys[i]]) {
34
- return this;
31
+ return this; // If the path doesn't exist, do nothing
35
32
  }
36
33
  current = current[keys[i]];
37
34
  }
@@ -52,42 +49,49 @@ class WhereBuilder {
52
49
  let operator;
53
50
  let value;
54
51
  if (args.length === 0) {
52
+ // Do nothing
55
53
  }
56
54
  else if (args.length === 1) {
57
55
  const condition = args[0];
58
56
  if (typeof condition === 'function') {
57
+ // If the condition is a function, create a new WhereBuilder and call the function with it
59
58
  const builder = new WhereBuilder();
60
59
  condition(builder);
61
60
  this.updateCondition(builder.toObject(), type);
62
61
  }
63
62
  else if (condition instanceof WhereBuilder) {
63
+ // If the condition is a WhereBuilder
64
64
  this.updateCondition(condition.toObject(), type);
65
65
  }
66
66
  else {
67
+ // If the condition is a simple object
67
68
  this.updateCondition(condition, type);
68
69
  }
69
70
  }
70
71
  else if (args.length === 2 || args.length === 3) {
71
72
  if (args.length === 2) {
73
+ // if there are only two arguments, the operator is EQ
72
74
  field = args[0];
73
75
  value = args[1];
74
76
  if (typeof value === 'object') {
75
77
  const firstKey = Object.keys(value)[0];
78
+ // if the first key is a operator, update the value with the operator
76
79
  if (firstKey.startsWith('$')) {
77
80
  this.updateCondition({ [field]: value }, type);
78
81
  }
79
82
  else {
80
- this.updateCondition({ [field]: { [types_1.WhereOperatorEnum.EQ]: value } }, type);
83
+ this.updateCondition({ [field]: { [WhereOperatorEnum.EQ]: value } }, type);
81
84
  }
82
85
  }
83
86
  else if (this.isOperator(value)) {
84
87
  this.updateCondition({ [field]: { [value]: true } }, type);
85
88
  }
86
89
  else {
87
- this.updateCondition({ [field]: { [types_1.WhereOperatorEnum.EQ]: value } }, type);
90
+ this.updateCondition({ [field]: { [WhereOperatorEnum.EQ]: value } }, type);
88
91
  }
89
92
  }
90
93
  else {
94
+ // if there are three arguments, the operator is the second argument
91
95
  field = args[0];
92
96
  operator = args[1];
93
97
  value = args[2];
@@ -96,34 +100,47 @@ class WhereBuilder {
96
100
  }
97
101
  return this;
98
102
  }
103
+ // private updateCondition(condition: Record<string, any>, type: '$and' | '$or'): void {
104
+ // this.whereObject[type] = [...(this.whereObject[type] || []), condition].filter(Boolean);
105
+ // }
99
106
  updateCondition(condition, type) {
100
107
  if (type === null) {
108
+ // For direct where conditions, we need to merge intelligently
101
109
  this.mergeConditions(this.whereObject, condition);
102
110
  }
103
111
  else {
112
+ // For logical operators ($and, $or), add to the array
104
113
  this.whereObject[type] = [...(this.whereObject[type] || []), condition].filter(Boolean);
105
114
  }
106
115
  }
116
+ /**
117
+ * Intelligently merge two condition objects, handling logical operators properly
118
+ */
107
119
  mergeConditions(target, source) {
108
120
  for (const key in source) {
109
121
  const sourceValue = source[key];
110
122
  if (key === '$and' || key === '$or') {
123
+ // Handle logical operators - merge arrays
111
124
  if (target[key]) {
125
+ // If target already has this logical operator, merge the arrays
112
126
  target[key] = [...(target[key] || []), ...(Array.isArray(sourceValue) ? sourceValue : [sourceValue])];
113
127
  }
114
128
  else {
129
+ // If target doesn't have this logical operator, set it
115
130
  target[key] = Array.isArray(sourceValue) ? sourceValue : [sourceValue];
116
131
  }
117
132
  }
118
133
  else {
134
+ // Handle regular field conditions
119
135
  if (target[key] && typeof target[key] === 'object' && typeof sourceValue === 'object') {
120
- target[key] = Object.assign(Object.assign({}, target[key]), sourceValue);
136
+ // If both target and source have the same field with object values, merge them
137
+ target[key] = { ...target[key], ...sourceValue };
121
138
  }
122
139
  else {
140
+ // Otherwise, simply assign the value
123
141
  target[key] = sourceValue;
124
142
  }
125
143
  }
126
144
  }
127
145
  }
128
146
  }
129
- exports.WhereBuilder = WhereBuilder;
@@ -0,0 +1,22 @@
1
+ import baseConfig from '../../eslint.base.config';
2
+
3
+ export default [
4
+ ...baseConfig,
5
+ {
6
+ files: ['**/*.json'],
7
+ rules: {
8
+ '@nx/dependency-checks': [
9
+ 'error',
10
+ {
11
+ ignoredFiles: ['{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}'],
12
+ },
13
+ ],
14
+ },
15
+ languageOptions: {
16
+ parser: await import('jsonc-eslint-parser'),
17
+ },
18
+ },
19
+ {
20
+ ignores: ['**/out-tsc'],
21
+ },
22
+ ];
package/jest.config.ts ADDED
@@ -0,0 +1,10 @@
1
+ export default {
2
+ displayName: 'nest-crud-request',
3
+ preset: '../../jest.preset.js',
4
+ testEnvironment: 'node',
5
+ transform: {
6
+ '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
7
+ },
8
+ moduleFileExtensions: ['ts', 'js', 'html'],
9
+ coverageDirectory: '../../coverage/packages/nest-crud-request',
10
+ };
package/package.json CHANGED
@@ -1,28 +1,10 @@
1
1
  {
2
2
  "name": "@ackplus/nest-crud-request",
3
- "version": "0.1.51",
3
+ "version": "1.1.0",
4
4
  "type": "commonjs",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
7
- "license": "MIT",
8
- "description": "Request parsing and query building utilities for @ackplus/nest-crud",
9
- "keywords": [
10
- "nestjs",
11
- "crud",
12
- "query",
13
- "request",
14
- "parser",
15
- "builder"
16
- ],
17
- "repository": {
18
- "type": "git",
19
- "url": "https://github.com/ack-solutions/packages.git"
20
- },
21
- "homepage": "https://github.com/ack-solutions/packages.git#readme",
22
- "publishConfig": {
23
- "access": "public"
24
- },
25
7
  "dependencies": {
26
8
  "tslib": "^2.3.0"
27
9
  }
28
- }
10
+ }
package/project.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "nest-crud-request",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "packages/nest-crud-request/src",
5
+ "projectType": "library",
6
+ "release": {
7
+ "version": {
8
+ "manifestRootsToUpdate": [
9
+ "dist/{projectRoot}"
10
+ ],
11
+ "currentVersionResolver": "git-tag",
12
+ "fallbackCurrentVersionResolver": "disk"
13
+ }
14
+ },
15
+ "tags": [],
16
+ "targets": {
17
+ "build": {
18
+ "executor": "@nx/js:tsc",
19
+ "outputs": [
20
+ "{options.outputPath}"
21
+ ],
22
+ "options": {
23
+ "outputPath": "dist/packages/nest-crud-request",
24
+ "main": "packages/nest-crud-request/src/index.ts",
25
+ "tsConfig": "packages/nest-crud-request/tsconfig.lib.json",
26
+ "assets": [
27
+ "packages/nest-crud-request/*.md"
28
+ ]
29
+ }
30
+ },
31
+ "nx-release-publish": {
32
+ "options": {
33
+ "packageRoot": "dist/{projectRoot}"
34
+ }
35
+ },
36
+ "test": {
37
+ "executor": "@nx/jest:jest",
38
+ "outputs": [
39
+ "{workspaceRoot}/coverage/{projectRoot}"
40
+ ],
41
+ "options": {
42
+ "jestConfig": "packages/nest-crud-request/jest.config.ts"
43
+ }
44
+ }
45
+ }
46
+ }