nestjs-paginate 12.10.1 → 13.0.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.
package/README.md CHANGED
@@ -516,6 +516,48 @@ const config: PaginateConfig<CatEntity> = {
516
516
  const result = await paginate<CatEntity>(query, catRepo, config)
517
517
  ```
518
518
 
519
+ ## Usage with to-many relationships
520
+
521
+ You can filter parents by conditions on their to-many relations (one-to-many or many-to-many) using quantifiers.
522
+ Quantifiers define how many related rows must satisfy the condition:
523
+
524
+ - `$any` (default): at least one related row matches the condition
525
+ - `$all`: all related rows match the condition
526
+ - `$none`: no related rows match the condition
527
+
528
+ ### Examples
529
+ Assume `CatEntity` has a one‑to‑many relation `toys: CatToyEntity[]` where `CatToyEntity` has a string column `name`.
530
+
531
+ - At least one toy named exactly "Ball":
532
+
533
+ ```url
534
+ GET /cats?filter.toys.name=$any:$eq:Ball
535
+ ```
536
+
537
+ - At least one toy whose name contains "red" (case-insensitive):
538
+
539
+ ```url
540
+ GET /cats?filter.toys.name=$any:$ilike:red
541
+ ```
542
+
543
+ - All toys must have names that start with "Chew":
544
+
545
+ ```url
546
+ GET /cats?filter.toys.name=$all:$sw:Chew
547
+ ```
548
+
549
+ - No toys named "Squeaky", including cats without any toys:
550
+
551
+ ```url
552
+ GET /cats?filter.toys.name=$none:$eq:Squeaky
553
+ ```
554
+
555
+ - One or more toys not named "Squeaky":
556
+
557
+ ```url
558
+ GET /cats?filter.toys.name=$any:$not:$eq:Squeaky
559
+ ```
560
+
519
561
  ## Usage with Eager Loading
520
562
 
521
563
  Eager loading should work with TypeORM's eager property out of the box:
@@ -589,18 +631,27 @@ const config: PaginateConfig<CatEntity> = {
589
631
 
590
632
  `?filter.roles=$contains:moderator,admin` where column `roles` is an array and contains the values `moderator` and `admin`
591
633
 
592
- ## JSONB Filters
634
+ ## JSONB Support
593
635
 
594
- You can filter on JSONB columns using dot notation to access nested fields.
636
+ You can sort, search, and filter on JSONB columns using dot notation to access nested fields.
595
637
 
596
- ### Supported operators
638
+ ### Database support matrix
639
+
640
+ | Feature | PostgreSQL / CockroachDB | MySQL / MariaDB | SQLite |
641
+ |---------|---|---|---|
642
+ | **Sorting** (`sortableColumns`) | Yes (`#>>`) | Yes (`JSON_UNQUOTE(JSON_EXTRACT(...))`) | Yes (`json_extract`) |
643
+ | **Searching** (`searchableColumns`) | Yes | Yes | Yes |
644
+ | **Filtering** (`$eq`, `$in`, `$contains`) | Yes (`@>` containment) | No | No |
645
+
646
+ > **Note:** Sorting and searching on JSONB paths is supported across all database engines — the library automatically uses the correct JSON extraction function for your DB. Filtering via `$eq`, `$in`, and `$contains` uses PostgreSQL's `@>` containment operator (via TypeORM's `JsonContains`) and is only supported on **PostgreSQL** and **CockroachDB**.
647
+
648
+ ### Filtering operators (PostgreSQL / CockroachDB only)
597
649
 
598
650
  | Operator | Description |
599
651
  |----------|-------------|
600
- | `$eq` | Exact match (`column @> '{"key":"value"}'`) |
601
- | `$in` | Match any of a comma-separated list of values |
602
-
603
- > **Note:** JSONB filtering is implemented using PostgreSQL's `@>` (containment) operator and is only supported by **PostgreSQL**.
652
+ | `$eq` | Exact match via containment (`col @> '{"key":"value"}'`) |
653
+ | `$in` | Match any of a comma-separated list of values |
654
+ | `$contains` | Match if a JSON array contains the value |
604
655
 
605
656
  ### Direct JSONB column
606
657
 
@@ -6,4 +6,5 @@ export declare class CatHomePillowEntity {
6
6
  color: string;
7
7
  brand: CatHomePillowBrandEntity;
8
8
  createdAt: string;
9
+ deletedAt: string;
9
10
  }
@@ -37,6 +37,10 @@ __decorate([
37
37
  (0, typeorm_1.CreateDateColumn)(column_option_1.DateColumnNotNull),
38
38
  __metadata("design:type", String)
39
39
  ], CatHomePillowEntity.prototype, "createdAt", void 0);
40
+ __decorate([
41
+ (0, typeorm_1.DeleteDateColumn)(column_option_1.DateColumnNotNull),
42
+ __metadata("design:type", String)
43
+ ], CatHomePillowEntity.prototype, "deletedAt", void 0);
40
44
  exports.CatHomePillowEntity = CatHomePillowEntity = __decorate([
41
45
  (0, typeorm_1.Entity)()
42
46
  ], CatHomePillowEntity);
@@ -1 +1 @@
1
- {"version":3,"file":"cat-home-pillow.entity.js","sourceRoot":"","sources":["../../src/__tests__/cat-home-pillow.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAA6F;AAC7F,iFAAyE;AACzE,uDAAiD;AACjD,mDAAmD;AAG5C,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;CAe/B,CAAA;AAfY,kDAAmB;AAE5B;IADC,IAAA,gCAAsB,GAAE;;+CACf;AAGV;IADC,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,+BAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;8BACjD,+BAAa;iDAAA;AAGnB;IADC,IAAA,gBAAM,GAAE;;kDACI;AAGb;IADC,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,uDAAwB,CAAC;8BACnC,uDAAwB;kDAAA;AAG/B;IADC,IAAA,0BAAgB,EAAC,iCAAiB,CAAC;;sDACnB;8BAdR,mBAAmB;IAD/B,IAAA,gBAAM,GAAE;GACI,mBAAmB,CAe/B"}
1
+ {"version":3,"file":"cat-home-pillow.entity.js","sourceRoot":"","sources":["../../src/__tests__/cat-home-pillow.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAA+G;AAC/G,iFAAyE;AACzE,uDAAiD;AACjD,mDAAmD;AAG5C,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;CAkB/B,CAAA;AAlBY,kDAAmB;AAE5B;IADC,IAAA,gCAAsB,GAAE;;+CACf;AAGV;IADC,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,+BAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;8BACjD,+BAAa;iDAAA;AAGnB;IADC,IAAA,gBAAM,GAAE;;kDACI;AAGb;IADC,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,uDAAwB,CAAC;8BACnC,uDAAwB;kDAAA;AAG/B;IADC,IAAA,0BAAgB,EAAC,iCAAiB,CAAC;;sDACnB;AAGjB;IADC,IAAA,0BAAgB,EAAC,iCAAiB,CAAC;;sDACnB;8BAjBR,mBAAmB;IAD/B,IAAA,gBAAM,GAAE;GACI,mBAAmB,CAkB/B"}
package/lib/filter.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- import { FindOperator, SelectQueryBuilder } from 'typeorm';
1
+ import { EntityMetadata, FindOperator, SelectQueryBuilder } from 'typeorm';
2
2
  import { WherePredicateOperator } from 'typeorm/query-builder/WhereClause';
3
3
  import { PaginateQuery } from './decorator';
4
4
  import { JoinMethod } from './helper';
5
+ import { EmbeddedMetadata } from 'typeorm/metadata/EmbeddedMetadata';
6
+ import { RelationMetadata } from 'typeorm/metadata/RelationMetadata';
5
7
  export declare enum FilterOperator {
6
8
  EQ = "$eq",
7
9
  GT = "$gt",
@@ -20,6 +22,12 @@ export declare enum FilterSuffix {
20
22
  NOT = "$not"
21
23
  }
22
24
  export declare function isSuffix(value: unknown): value is FilterSuffix;
25
+ export declare enum FilterQuantifier {
26
+ ALL = "$all",
27
+ ANY = "$any",
28
+ NONE = "$none"
29
+ }
30
+ export declare function isQuantifier(value: unknown): value is FilterQuantifier;
23
31
  export declare enum FilterComparator {
24
32
  AND = "$and",
25
33
  OR = "$or"
@@ -27,6 +35,7 @@ export declare enum FilterComparator {
27
35
  export declare function isComparator(value: unknown): value is FilterComparator;
28
36
  export declare const OperatorSymbolToFunction: Map<FilterOperator | FilterSuffix, (...args: any[]) => FindOperator<string>>;
29
37
  type Filter = {
38
+ quantifier: FilterQuantifier;
30
39
  comparator: FilterComparator;
31
40
  findOperator: FindOperator<string>;
32
41
  };
@@ -37,6 +46,7 @@ type ColumnJoinMethods = {
37
46
  [columnName: string]: JoinMethod;
38
47
  };
39
48
  export interface FilterToken {
49
+ quantifier: FilterQuantifier;
40
50
  comparator: FilterComparator;
41
51
  suffix?: FilterSuffix;
42
52
  operator: FilterOperator;
@@ -51,9 +61,35 @@ export declare function generatePredicateCondition(qb: SelectQueryBuilder<unknow
51
61
  export declare function addWhereCondition<T>(qb: SelectQueryBuilder<T>, column: string, filter: ColumnFilters): void;
52
62
  export declare function parseFilterToken(raw?: string): FilterToken | null;
53
63
  export declare function parseFilter<T>(query: PaginateQuery, filterableColumns?: {
54
- [column: string]: (FilterOperator | FilterSuffix)[] | true;
64
+ [column: string]: (FilterOperator | FilterSuffix | FilterQuantifier)[] | true;
55
65
  }, qb?: SelectQueryBuilder<T>): ColumnFilters;
66
+ /**
67
+ * Retrieves the relation path for a given column name within the provided metadata.
68
+ *
69
+ * This method analyzes the column name's segments to identify corresponding relations or embedded entities
70
+ * within the hierarchy described by the given metadata and returns a structured path.
71
+ *
72
+ * @param {string} columnName - The dot-delimited name of the column whose relation path is to be determined.
73
+ * @param {EntityMetadata | EmbeddedMetadata} metadata - The metadata of the entity or embedded component
74
+ * which holds the relations or embedded items.
75
+ * @return {[string, RelationMetadata | EmbeddedMetadata][]} The ordered array describing the path,
76
+ * where each element contains a field name and its corresponding relation or embedded metadata.
77
+ * Throws an error if no matching relation or embedded metadata is found.
78
+ */
79
+ export declare function getRelationPath(columnName: string, metadata: EntityMetadata | EmbeddedMetadata): [string, RelationMetadata | EmbeddedMetadata][];
56
80
  export declare function addFilter<T>(qb: SelectQueryBuilder<T>, query: PaginateQuery, filterableColumns?: {
57
- [column: string]: (FilterOperator | FilterSuffix)[] | true;
81
+ [column: string]: (FilterOperator | FilterSuffix | FilterQuantifier)[] | true;
58
82
  }): ColumnJoinMethods;
83
+ export declare function addDirectFilters<T>(qb: SelectQueryBuilder<T>, filter: ColumnFilters): void;
84
+ export declare function addToManySubFilters<T>(qb: SelectQueryBuilder<T>, filter: ColumnFilters, query: PaginateQuery, filterableColumns?: {
85
+ [column: string]: (FilterOperator | FilterSuffix | FilterQuantifier)[] | true;
86
+ }): void;
87
+ export declare function createSubFilter(query: PaginateQuery, filterableColumns: {
88
+ [column: string]: (FilterOperator | FilterSuffix | FilterQuantifier)[] | true;
89
+ }, column: string): {
90
+ subQuery: PaginateQuery;
91
+ subFilterableColumns: {
92
+ [column: string]: true | (FilterOperator | FilterSuffix | FilterQuantifier)[];
93
+ };
94
+ };
59
95
  export {};