@nest-extended/prisma 0.0.2-beta-15
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 +225 -0
- package/package.json +25 -0
- package/src/common/apply-filters.d.ts +13 -0
- package/src/common/apply-filters.js +68 -0
- package/src/common/apply-filters.js.map +1 -0
- package/src/common/query.utils.d.ts +38 -0
- package/src/common/query.utils.js +252 -0
- package/src/common/query.utils.js.map +1 -0
- package/src/filters/global-exception.filter.d.ts +4 -0
- package/src/filters/global-exception.filter.js +53 -0
- package/src/filters/global-exception.filter.js.map +1 -0
- package/src/filters/prisma-error.filter.d.ts +8 -0
- package/src/filters/prisma-error.filter.js +69 -0
- package/src/filters/prisma-error.filter.js.map +1 -0
- package/src/index.d.ts +6 -0
- package/src/index.js +10 -0
- package/src/index.js.map +1 -0
- package/src/lib/nest.service.d.ts +45 -0
- package/src/lib/nest.service.js +216 -0
- package/src/lib/nest.service.js.map +1 -0
- package/src/types/PrismaFilters.d.ts +12 -0
- package/src/types/PrismaFilters.js +3 -0
- package/src/types/PrismaFilters.js.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# @nest-extended/prisma
|
|
2
|
+
|
|
3
|
+
This package provides powerful Prisma integrations for the **NestExtended** ecosystem, offering a robust service layer with built-in pagination, filtering, soft delete capabilities, exception filters, and query utilities. Supports **PostgreSQL**, **MySQL**, and **SQLite**.
|
|
4
|
+
|
|
5
|
+
## Key Features
|
|
6
|
+
|
|
7
|
+
### NestService
|
|
8
|
+
|
|
9
|
+
A generic service class (`NestService<T>`) that provides:
|
|
10
|
+
|
|
11
|
+
- **CRUD Operations**: `_find`, `_get`, `_create`, `_patch`, `_remove`
|
|
12
|
+
- **FeathersJS-Style Querying**: Support for `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$like`, `$notLike`, `$iLike`, `$notILike`, `$or`, `$and`
|
|
13
|
+
- **Pagination**: Built-in pagination logic using `$skip` and `$limit` with configurable defaults (limit: 20, skip: 0)
|
|
14
|
+
- **Soft Delete**: Configurable soft delete support — marks records as deleted instead of removing, with user tracking via CLS context
|
|
15
|
+
- **Bulk Operations**: Optional multi-record create (enable with `multi: true`)
|
|
16
|
+
- **Count**: `getCount(filter)` for counting records matching a filter
|
|
17
|
+
- **Conditional Pagination**: `_find` accepts `{ pagination: false }` to return raw arrays instead of paginated responses
|
|
18
|
+
- **Relations**: `$include` for eager-loading relations (replaces Mongoose `$populate`)
|
|
19
|
+
|
|
20
|
+
**Constructor Options** (`NestServiceOptions`):
|
|
21
|
+
- `multi` (default: `false`) — allow bulk create with arrays
|
|
22
|
+
- `softDelete` (default: `true`) — enable soft delete behavior
|
|
23
|
+
- `pagination` (default: `true`) — enable paginated responses
|
|
24
|
+
|
|
25
|
+
### Query Operators
|
|
26
|
+
|
|
27
|
+
All operators follow FeathersJS-style syntax and are translated to Prisma `where` clauses:
|
|
28
|
+
|
|
29
|
+
| Operator | Description | Example | Prisma Translation |
|
|
30
|
+
|---|---|---|---|
|
|
31
|
+
| `$eq` | Equality | `{ age: { $eq: 25 } }` | `{ age: 25 }` |
|
|
32
|
+
| `$ne` | Not equal | `{ status: { $ne: 'draft' } }` | `{ status: { not: 'draft' } }` |
|
|
33
|
+
| `$gt` | Greater than | `{ age: { $gt: 18 } }` | `{ age: { gt: 18 } }` |
|
|
34
|
+
| `$gte` | Greater than or equal | `{ age: { $gte: 18 } }` | `{ age: { gte: 18 } }` |
|
|
35
|
+
| `$lt` | Less than | `{ age: { $lt: 65 } }` | `{ age: { lt: 65 } }` |
|
|
36
|
+
| `$lte` | Less than or equal | `{ age: { $lte: 65 } }` | `{ age: { lte: 65 } }` |
|
|
37
|
+
| `$in` | In array | `{ role: { $in: [1, 2] } }` | `{ role: { in: [1, 2] } }` |
|
|
38
|
+
| `$nin` | Not in array | `{ role: { $nin: [3] } }` | `{ role: { notIn: [3] } }` |
|
|
39
|
+
| `$like` | Contains (case-sensitive) | `{ name: { $like: 'john' } }` | `{ name: { contains: 'john' } }` |
|
|
40
|
+
| `$notLike` | Does not contain | `{ name: { $notLike: 'test' } }` | `{ name: { not: { contains: 'test' } } }` |
|
|
41
|
+
| `$iLike` | Contains (case-insensitive) | `{ name: { $iLike: 'john' } }` | `{ name: { contains: 'john', mode: 'insensitive' } }` |
|
|
42
|
+
| `$notILike` | Not contains (case-insensitive) | `{ name: { $notILike: 'test' } }` | `{ NOT: { name: { contains: 'test', mode: 'insensitive' } } }` |
|
|
43
|
+
| `$or` | OR condition | `{ $or: [{ a: 1 }, { b: 2 }] }` | `{ OR: [{ a: 1 }, { b: 2 }] }` |
|
|
44
|
+
| `$and` | AND condition | `{ $and: [{ a: 1 }, { b: 2 }] }` | `{ AND: [{ a: 1 }, { b: 2 }] }` |
|
|
45
|
+
|
|
46
|
+
> **Note**: `$iLike` and `$notILike` use PostgreSQL's `mode: 'insensitive'`. MySQL is case-insensitive by default (collation-dependent). SQLite does not support case-insensitive search natively.
|
|
47
|
+
|
|
48
|
+
### Special Parameters
|
|
49
|
+
|
|
50
|
+
| Param | Effect | Prisma Translation |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `$sort` | Sort order — `{ createdAt: -1 }` | `orderBy: { createdAt: 'desc' }` |
|
|
53
|
+
| `$limit` | Max records (default: 20) | `take: number` |
|
|
54
|
+
| `$skip` | Skip count (default: 0) | `skip: number` |
|
|
55
|
+
| `$select` | Field projection (array/string/object) | `select: { field1: true, field2: true }` |
|
|
56
|
+
| `$include` | Eager-load relations | `include: { posts: true }` |
|
|
57
|
+
|
|
58
|
+
### Query Utilities
|
|
59
|
+
|
|
60
|
+
- **`applyFilters(queryOptions, filters, options)`**: Applies `$select`, `$include`, `$sort`, `$limit`, `$skip` to a Prisma query options object
|
|
61
|
+
- **`rawQuery(query)`**: Converts FeathersJS-style query params to Prisma `where` clause
|
|
62
|
+
- **`assignFilters`**: Extracts known filter keys (`$sort`, `$limit`, `$skip`, `$select`, `$include`) from query params
|
|
63
|
+
- **`filterQuery`**: Full query parsing — separates filters from query and validates operators
|
|
64
|
+
- **`cleanQuery`**: Validates query operators and throws `BadRequestException` for invalid `$` params
|
|
65
|
+
|
|
66
|
+
### Exception Filters
|
|
67
|
+
|
|
68
|
+
- **`GlobalExceptionFilter`**: Catch-all exception filter that handles:
|
|
69
|
+
- `HttpException` — returns standard NestJS error response
|
|
70
|
+
- `PrismaClientKnownRequestError` — parses specific error codes with human-readable messages
|
|
71
|
+
- `PrismaClientValidationError` — wraps as `BadRequestException`
|
|
72
|
+
- `ZodError` — wraps as `BadRequestException`
|
|
73
|
+
- Unhandled errors — returns 500 with stack trace (stack hidden in production)
|
|
74
|
+
|
|
75
|
+
- **`handlePrismaError(exception)`**: Translates Prisma error codes to user-friendly messages:
|
|
76
|
+
- `P2002` — Unique constraint violation (duplicate key)
|
|
77
|
+
- `P2003` — Foreign key constraint violation
|
|
78
|
+
- `P2025` — Record not found
|
|
79
|
+
- `P2014` — Relation violation
|
|
80
|
+
- `P2000` — Value too long for column
|
|
81
|
+
- `P2006` — Invalid value provided
|
|
82
|
+
- `P2011` — Null constraint violation
|
|
83
|
+
- `P2024` — Connection pool timeout
|
|
84
|
+
- `P2021` — Table does not exist
|
|
85
|
+
- `P2022` — Column does not exist
|
|
86
|
+
|
|
87
|
+
### Types
|
|
88
|
+
|
|
89
|
+
- **`PrismaFilters`**: `$select`, `$include`, `$sort`, `$limit`, `$skip`
|
|
90
|
+
- **`PrismaFilterOptions`**: `defaultLimit`, `defaultSkip`, `defaultPagination`
|
|
91
|
+
|
|
92
|
+
## Usage
|
|
93
|
+
|
|
94
|
+
### NestService
|
|
95
|
+
|
|
96
|
+
Extend `NestService` to create a service with full CRUD capabilities.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { NestService } from '@nest-extended/prisma';
|
|
100
|
+
import { PrismaService } from 'src/prisma/prisma.service';
|
|
101
|
+
|
|
102
|
+
@Injectable()
|
|
103
|
+
export class CatsService extends NestService<any> {
|
|
104
|
+
constructor(private readonly prisma: PrismaService) {
|
|
105
|
+
super(prisma.cat);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
With custom options:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
super(prisma.cat, { multi: true, softDelete: false, pagination: false });
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Querying
|
|
117
|
+
|
|
118
|
+
You can use the `_find` method with FeathersJS-style query objects:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
const results = await this.catsService._find({
|
|
122
|
+
name: { $iLike: 'kitty' },
|
|
123
|
+
age: { $gt: 5 },
|
|
124
|
+
$sort: { createdAt: -1 },
|
|
125
|
+
$limit: 10
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Disable pagination for a single query:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
const allCats = await this.catsService._find({}, { pagination: false });
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Relations with $include
|
|
136
|
+
|
|
137
|
+
Use `$include` to eager-load related models:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
const results = await this.usersService._find({
|
|
141
|
+
$include: {
|
|
142
|
+
posts: true
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// With nested conditions
|
|
147
|
+
const results = await this.usersService._find({
|
|
148
|
+
$include: {
|
|
149
|
+
posts: {
|
|
150
|
+
where: { published: true }
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### GlobalExceptionFilter
|
|
157
|
+
|
|
158
|
+
Register globally in `app.module.ts`:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { GlobalExceptionFilter } from '@nest-extended/prisma';
|
|
162
|
+
import { APP_FILTER } from '@nestjs/core';
|
|
163
|
+
|
|
164
|
+
providers: [
|
|
165
|
+
{ provide: APP_FILTER, useClass: GlobalExceptionFilter },
|
|
166
|
+
]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### PrismaService Setup
|
|
170
|
+
|
|
171
|
+
Create a `PrismaService` wrapper in your project:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// src/prisma/prisma.service.ts
|
|
175
|
+
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
176
|
+
import { PrismaClient } from '@prisma/client';
|
|
177
|
+
|
|
178
|
+
@Injectable()
|
|
179
|
+
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
|
180
|
+
async onModuleInit() {
|
|
181
|
+
await this.$connect();
|
|
182
|
+
}
|
|
183
|
+
async onModuleDestroy() {
|
|
184
|
+
await this.$disconnect();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/prisma/prisma.module.ts
|
|
189
|
+
import { Global, Module } from '@nestjs/common';
|
|
190
|
+
import { PrismaService } from './prisma.service';
|
|
191
|
+
|
|
192
|
+
@Global()
|
|
193
|
+
@Module({
|
|
194
|
+
providers: [PrismaService],
|
|
195
|
+
exports: [PrismaService],
|
|
196
|
+
})
|
|
197
|
+
export class PrismaModule {}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
> **Tip**: The CLI command `nest-cli g app` and `nest-cli g service` will generate these files automatically when you select a Prisma-based database (PostgreSQL, MySQL, or SQLite).
|
|
201
|
+
|
|
202
|
+
## Supported Databases
|
|
203
|
+
|
|
204
|
+
| Database | `$iLike` Support | Connection URL Example |
|
|
205
|
+
|---|---|---|
|
|
206
|
+
| PostgreSQL | ✅ Full support | `postgresql://user:password@localhost:5432/mydb` |
|
|
207
|
+
| MySQL | ⚠️ Case-insensitive by default (collation) | `mysql://user:password@localhost:3306/mydb` |
|
|
208
|
+
| SQLite | ❌ No case-insensitive mode | `file:./dev.db` |
|
|
209
|
+
|
|
210
|
+
## Exported API
|
|
211
|
+
|
|
212
|
+
| Export | Type | Description |
|
|
213
|
+
|---|---|---|
|
|
214
|
+
| `NestService` | Class | Generic CRUD service with pagination & soft delete |
|
|
215
|
+
| `applyFilters` | Function | Apply filters/pagination to Prisma query options |
|
|
216
|
+
| `rawQuery` | Function | Convert FeathersJS-style query to Prisma where clause |
|
|
217
|
+
| `assignFilters` | Function | Extract filter params from query |
|
|
218
|
+
| `filterQuery` | Function | Full query parsing with operator validation |
|
|
219
|
+
| `cleanQuery` | Function | Validate query operators |
|
|
220
|
+
| `FILTERS` | Object | Filter converter definitions |
|
|
221
|
+
| `OPERATORS` | Array | Valid operator list |
|
|
222
|
+
| `GlobalExceptionFilter` | Filter | Catch-all exception handler |
|
|
223
|
+
| `handlePrismaError` | Function | Prisma error code translator |
|
|
224
|
+
| `PrismaFilters` | Interface | Filter type definition |
|
|
225
|
+
| `PrismaFilterOptions` | Interface | Options type definition |
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nest-extended/prisma",
|
|
3
|
+
"version": "0.0.2-beta-15",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"contributors": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Soubhik Kumar Gon",
|
|
9
|
+
"email": "soubhikgon2004@gmail.com",
|
|
10
|
+
"url": "https://github.com/zakhaev26"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "Santanu Prasad Sahoo",
|
|
14
|
+
"email": "sahoosantanu92@gmail.com",
|
|
15
|
+
"url": "https://github.com/santanup"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"main": "./src/index.js",
|
|
19
|
+
"types": "./src/index.d.ts",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"tslib": "^2.3.0",
|
|
22
|
+
"@nest-extended/core": "0.0.2-beta-15",
|
|
23
|
+
"zod": "^3.22.4"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PrismaFilters, PrismaFilterOptions } from '../types/PrismaFilters';
|
|
2
|
+
/**
|
|
3
|
+
* Applies filter parameters ($select, $include, $sort, $limit, $skip)
|
|
4
|
+
* to a Prisma query options object.
|
|
5
|
+
*
|
|
6
|
+
* This is the Prisma equivalent of the Mongoose `nestify()` function.
|
|
7
|
+
*
|
|
8
|
+
* @param queryOptions - The Prisma findMany/findFirst options object to modify
|
|
9
|
+
* @param filters - Extracted filter parameters
|
|
10
|
+
* @param options - Default pagination options
|
|
11
|
+
* @param isSingleOperation - If true, skip pagination (limit/skip)
|
|
12
|
+
*/
|
|
13
|
+
export declare function applyFilters(queryOptions: Record<string, any>, filters: PrismaFilters, options: PrismaFilterOptions, isSingleOperation?: boolean): void;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyFilters = applyFilters;
|
|
4
|
+
/**
|
|
5
|
+
* Applies filter parameters ($select, $include, $sort, $limit, $skip)
|
|
6
|
+
* to a Prisma query options object.
|
|
7
|
+
*
|
|
8
|
+
* This is the Prisma equivalent of the Mongoose `nestify()` function.
|
|
9
|
+
*
|
|
10
|
+
* @param queryOptions - The Prisma findMany/findFirst options object to modify
|
|
11
|
+
* @param filters - Extracted filter parameters
|
|
12
|
+
* @param options - Default pagination options
|
|
13
|
+
* @param isSingleOperation - If true, skip pagination (limit/skip)
|
|
14
|
+
*/
|
|
15
|
+
function applyFilters(queryOptions, filters, options, isSingleOperation = false) {
|
|
16
|
+
// Apply $select
|
|
17
|
+
if (filters.$select) {
|
|
18
|
+
if (Array.isArray(filters.$select)) {
|
|
19
|
+
const selectFields = filters.$select.reduce((res, key) => {
|
|
20
|
+
res[key] = true;
|
|
21
|
+
return res;
|
|
22
|
+
}, {});
|
|
23
|
+
queryOptions['select'] = selectFields;
|
|
24
|
+
}
|
|
25
|
+
else if (typeof filters.$select === 'object') {
|
|
26
|
+
queryOptions['select'] = filters.$select;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Apply $include (Prisma relations — replaces Mongoose $populate)
|
|
30
|
+
if (filters.$include && options.defaultPagination) {
|
|
31
|
+
// If both $select and $include are provided, Prisma doesn't allow both.
|
|
32
|
+
// In that case, move included relations into $select.
|
|
33
|
+
if (queryOptions['select']) {
|
|
34
|
+
const include = filters.$include;
|
|
35
|
+
for (const key in include) {
|
|
36
|
+
if (include.hasOwnProperty(key)) {
|
|
37
|
+
queryOptions['select'][key] = include[key];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
queryOptions['include'] = filters.$include;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Apply $sort → orderBy
|
|
46
|
+
if (filters.$sort) {
|
|
47
|
+
const sort = filters.$sort;
|
|
48
|
+
// Convert to Prisma orderBy format: [{ field: 'asc' }, { field2: 'desc' }]
|
|
49
|
+
const orderBy = Object.keys(sort).map(key => {
|
|
50
|
+
const val = sort[key];
|
|
51
|
+
const direction = val === -1 || val === '-1' || val === 'desc' ? 'desc' : 'asc';
|
|
52
|
+
return { [key]: direction };
|
|
53
|
+
});
|
|
54
|
+
queryOptions['orderBy'] = orderBy.length === 1 ? orderBy[0] : orderBy;
|
|
55
|
+
}
|
|
56
|
+
// Apply pagination: $limit and $skip
|
|
57
|
+
if (!isSingleOperation) {
|
|
58
|
+
const limit = Number(filters.$limit) || options.defaultLimit;
|
|
59
|
+
if (limit > 0) {
|
|
60
|
+
queryOptions['take'] = limit;
|
|
61
|
+
}
|
|
62
|
+
const skip = Number(filters.$skip) || options.defaultSkip;
|
|
63
|
+
if (skip > 0) {
|
|
64
|
+
queryOptions['skip'] = skip;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=apply-filters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-filters.js","sourceRoot":"","sources":["../../../../../packages/prisma/src/common/apply-filters.ts"],"names":[],"mappings":";;AAaA,oCA+DC;AA1ED;;;;;;;;;;GAUG;AACH,SAAgB,YAAY,CACxB,YAAiC,EACjC,OAAsB,EACtB,OAA4B,EAC5B,oBAA6B,KAAK;IAGlC,gBAAgB;IAChB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACjC,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CACvC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;gBACT,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;gBAChB,OAAO,GAAG,CAAC;YACf,CAAC,EACD,EAAE,CACL,CAAC;YACF,YAAY,CAAC,QAAQ,CAAC,GAAG,YAAY,CAAC;QAC1C,CAAC;aAAM,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC7C,YAAY,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QAC7C,CAAC;IACL,CAAC;IAED,kEAAkE;IAClE,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAChD,wEAAwE;QACxE,sDAAsD;QACtD,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,OAAO,CAAC,QAA4C,CAAC;YACrE,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;gBACxB,IAAI,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC9B,YAAY,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC/C,CAAC;YACL,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,YAAY,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC/C,CAAC;IACL,CAAC;IAED,wBAAwB;IACxB,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,OAAO,CAAC,KAA4B,CAAC;QAClD,2EAA2E;QAC3E,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;YACtB,MAAM,SAAS,GAAG,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;YAChF,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC;QAChC,CAAC,CAAC,CAAC;QACH,YAAY,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC1E,CAAC;IAED,qCAAqC;IACrC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,YAAY,CAAC;QAC7D,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACZ,YAAY,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;QACjC,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,WAAW,CAAC;QAC1D,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACX,YAAY,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;QAChC,CAAC;IACL,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare const FILTERS: {
|
|
2
|
+
$sort: (value: any) => Record<string, "asc" | "desc"> | undefined;
|
|
3
|
+
$limit: (value: any, options: any) => any;
|
|
4
|
+
$skip: (value: any) => number | undefined;
|
|
5
|
+
$select: (value: any) => Record<string, boolean> | undefined;
|
|
6
|
+
$include: (value: any) => any;
|
|
7
|
+
};
|
|
8
|
+
export declare function parse(number?: any): number | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Valid Prisma query operators (FeathersJS-style).
|
|
11
|
+
*/
|
|
12
|
+
export declare const OPERATORS: string[];
|
|
13
|
+
/**
|
|
14
|
+
* Converts a FeathersJS-style query object to a Prisma `where` clause.
|
|
15
|
+
*
|
|
16
|
+
* Examples:
|
|
17
|
+
* rawQuery({ name: 'John' })
|
|
18
|
+
* → { name: 'John' }
|
|
19
|
+
*
|
|
20
|
+
* rawQuery({ age: { $gt: 18 } })
|
|
21
|
+
* → { age: { gt: 18 } }
|
|
22
|
+
*
|
|
23
|
+
* rawQuery({ $or: [{ name: 'John' }, { name: 'Jane' }] })
|
|
24
|
+
* → { OR: [{ name: 'John' }, { name: 'Jane' }] }
|
|
25
|
+
*
|
|
26
|
+
* rawQuery({ name: { $like: 'John' } })
|
|
27
|
+
* → { name: { contains: 'John' } }
|
|
28
|
+
*
|
|
29
|
+
* rawQuery({ name: { $iLike: 'john' } })
|
|
30
|
+
* → { name: { contains: 'john', mode: 'insensitive' } }
|
|
31
|
+
*/
|
|
32
|
+
export declare const rawQuery: (query?: any) => Record<string, any>;
|
|
33
|
+
export declare const filterQuery: (query: any, options?: any) => {
|
|
34
|
+
filters: {};
|
|
35
|
+
query: {};
|
|
36
|
+
};
|
|
37
|
+
export declare const assignFilters: (object: any, query: any, filters: any, options: any) => any;
|
|
38
|
+
export declare const cleanQuery: (query: any, operators: any, filters: any) => any;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cleanQuery = exports.assignFilters = exports.filterQuery = exports.rawQuery = exports.OPERATORS = exports.FILTERS = void 0;
|
|
4
|
+
exports.parse = parse;
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const _ = require("lodash");
|
|
7
|
+
exports.FILTERS = {
|
|
8
|
+
$sort: (value) => convertSort(value),
|
|
9
|
+
$limit: (value, options) => getLimit(parse(value), options === null || options === void 0 ? void 0 : options.paginate),
|
|
10
|
+
$skip: (value) => parse(value),
|
|
11
|
+
$select: (value) => convertSelect(value),
|
|
12
|
+
$include: (value) => value,
|
|
13
|
+
};
|
|
14
|
+
function parse(number) {
|
|
15
|
+
if (typeof number !== 'undefined') {
|
|
16
|
+
return Math.abs(parseInt(number, 10));
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
function getLimit(limit, paginate) {
|
|
21
|
+
if (paginate && paginate.default) {
|
|
22
|
+
const lower = typeof limit === 'number' && !isNaN(limit) ? limit : paginate.default;
|
|
23
|
+
const upper = typeof paginate.max === 'number' ? paginate.max : Number.MAX_VALUE;
|
|
24
|
+
return Math.min(lower, upper);
|
|
25
|
+
}
|
|
26
|
+
return limit;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Converts $select to Prisma select format.
|
|
30
|
+
* Accepts: string[], Record<string, 1 | 0>, or string
|
|
31
|
+
* Returns: Record<string, boolean> for Prisma
|
|
32
|
+
*/
|
|
33
|
+
function convertSelect(value) {
|
|
34
|
+
if (!value)
|
|
35
|
+
return undefined;
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
return value.reduce((acc, key) => {
|
|
38
|
+
acc[key] = true;
|
|
39
|
+
return acc;
|
|
40
|
+
}, {});
|
|
41
|
+
}
|
|
42
|
+
if (typeof value === 'string') {
|
|
43
|
+
return value
|
|
44
|
+
.split(/[\s,]+/)
|
|
45
|
+
.filter(Boolean)
|
|
46
|
+
.reduce((acc, key) => {
|
|
47
|
+
acc[key] = true;
|
|
48
|
+
return acc;
|
|
49
|
+
}, {});
|
|
50
|
+
}
|
|
51
|
+
if (typeof value === 'object') {
|
|
52
|
+
return Object.keys(value).reduce((acc, key) => {
|
|
53
|
+
acc[key] = Boolean(value[key]);
|
|
54
|
+
return acc;
|
|
55
|
+
}, {});
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Converts sort object from FeathersJS format (1/-1) to Prisma format (asc/desc).
|
|
61
|
+
* Input: { createdAt: -1, name: 1 }
|
|
62
|
+
* Output: { createdAt: 'desc', name: 'asc' }
|
|
63
|
+
*/
|
|
64
|
+
function convertSort(sort) {
|
|
65
|
+
if (!sort || typeof sort !== 'object' || Array.isArray(sort)) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
return Object.keys(sort).reduce((result, key) => {
|
|
69
|
+
const val = parseInt(sort[key], 10);
|
|
70
|
+
result[key] = val === -1 ? 'desc' : 'asc';
|
|
71
|
+
return result;
|
|
72
|
+
}, {});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Valid Prisma query operators (FeathersJS-style).
|
|
76
|
+
*/
|
|
77
|
+
exports.OPERATORS = [
|
|
78
|
+
'$eq',
|
|
79
|
+
'$ne',
|
|
80
|
+
'$gte',
|
|
81
|
+
'$gt',
|
|
82
|
+
'$lte',
|
|
83
|
+
'$lt',
|
|
84
|
+
'$in',
|
|
85
|
+
'$nin',
|
|
86
|
+
'$like',
|
|
87
|
+
'$notLike',
|
|
88
|
+
'$iLike',
|
|
89
|
+
'$notILike',
|
|
90
|
+
'$or',
|
|
91
|
+
'$and',
|
|
92
|
+
];
|
|
93
|
+
/**
|
|
94
|
+
* Converts a single operator expression to Prisma where clause.
|
|
95
|
+
*/
|
|
96
|
+
function convertOperator(key, value) {
|
|
97
|
+
switch (key) {
|
|
98
|
+
case '$eq':
|
|
99
|
+
return value;
|
|
100
|
+
case '$ne':
|
|
101
|
+
return { not: value };
|
|
102
|
+
case '$gt':
|
|
103
|
+
return { gt: value };
|
|
104
|
+
case '$gte':
|
|
105
|
+
return { gte: value };
|
|
106
|
+
case '$lt':
|
|
107
|
+
return { lt: value };
|
|
108
|
+
case '$lte':
|
|
109
|
+
return { lte: value };
|
|
110
|
+
case '$in':
|
|
111
|
+
return { in: Array.isArray(value) ? value : [value] };
|
|
112
|
+
case '$nin':
|
|
113
|
+
return { notIn: Array.isArray(value) ? value : [value] };
|
|
114
|
+
case '$like':
|
|
115
|
+
return { contains: value };
|
|
116
|
+
case '$notLike':
|
|
117
|
+
return { not: { contains: value } };
|
|
118
|
+
case '$iLike':
|
|
119
|
+
return { contains: value, mode: 'insensitive' };
|
|
120
|
+
case '$notILike':
|
|
121
|
+
return { not: { contains: value, mode: 'insensitive' } };
|
|
122
|
+
default:
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Converts a FeathersJS-style query object to a Prisma `where` clause.
|
|
128
|
+
*
|
|
129
|
+
* Examples:
|
|
130
|
+
* rawQuery({ name: 'John' })
|
|
131
|
+
* → { name: 'John' }
|
|
132
|
+
*
|
|
133
|
+
* rawQuery({ age: { $gt: 18 } })
|
|
134
|
+
* → { age: { gt: 18 } }
|
|
135
|
+
*
|
|
136
|
+
* rawQuery({ $or: [{ name: 'John' }, { name: 'Jane' }] })
|
|
137
|
+
* → { OR: [{ name: 'John' }, { name: 'Jane' }] }
|
|
138
|
+
*
|
|
139
|
+
* rawQuery({ name: { $like: 'John' } })
|
|
140
|
+
* → { name: { contains: 'John' } }
|
|
141
|
+
*
|
|
142
|
+
* rawQuery({ name: { $iLike: 'john' } })
|
|
143
|
+
* → { name: { contains: 'john', mode: 'insensitive' } }
|
|
144
|
+
*/
|
|
145
|
+
const rawQuery = (query = {}) => {
|
|
146
|
+
const where = {};
|
|
147
|
+
for (const key in query) {
|
|
148
|
+
if (!query.hasOwnProperty(key))
|
|
149
|
+
continue;
|
|
150
|
+
if (key === '$or' && Array.isArray(query[key])) {
|
|
151
|
+
where['OR'] = query[key].map((subQuery) => (0, exports.rawQuery)(subQuery));
|
|
152
|
+
}
|
|
153
|
+
else if (key === '$and' && Array.isArray(query[key])) {
|
|
154
|
+
where['AND'] = query[key].map((subQuery) => (0, exports.rawQuery)(subQuery));
|
|
155
|
+
}
|
|
156
|
+
else if (key.startsWith('$')) {
|
|
157
|
+
// Skip filter keys — they are handled separately
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
else if (typeof query[key] === 'object' && query[key] !== null && !Array.isArray(query[key])) {
|
|
161
|
+
// Field-level operators: { age: { $gt: 18, $lt: 65 } }
|
|
162
|
+
const fieldConditions = {};
|
|
163
|
+
let hasOperators = false;
|
|
164
|
+
for (const opKey in query[key]) {
|
|
165
|
+
if (opKey.startsWith('$')) {
|
|
166
|
+
hasOperators = true;
|
|
167
|
+
const converted = convertOperator(opKey, query[key][opKey]);
|
|
168
|
+
if (typeof converted === 'object' && converted !== null && !Array.isArray(converted)) {
|
|
169
|
+
// Merge operator result into field conditions
|
|
170
|
+
// Handle $notLike / $notILike which produce { not: { contains: ... } }
|
|
171
|
+
Object.assign(fieldConditions, converted);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// Simple value replacement (e.g., $eq returns raw value)
|
|
175
|
+
where[key] = converted;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (hasOperators && Object.keys(fieldConditions).length > 0) {
|
|
180
|
+
where[key] = fieldConditions;
|
|
181
|
+
}
|
|
182
|
+
else if (!hasOperators) {
|
|
183
|
+
// Plain nested object (not operators)
|
|
184
|
+
where[key] = query[key];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
// Direct equality
|
|
189
|
+
where[key] = query[key];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return where;
|
|
193
|
+
};
|
|
194
|
+
exports.rawQuery = rawQuery;
|
|
195
|
+
const filterQuery = (query, options = {}) => {
|
|
196
|
+
const {
|
|
197
|
+
// @ts-ignore
|
|
198
|
+
filters: additionalFilters = {},
|
|
199
|
+
// @ts-ignore
|
|
200
|
+
operators: additionalOperators = [], } = options;
|
|
201
|
+
const result = {
|
|
202
|
+
filters: {},
|
|
203
|
+
query: {},
|
|
204
|
+
};
|
|
205
|
+
result.filters = (0, exports.assignFilters)({}, query, exports.FILTERS, options);
|
|
206
|
+
result.filters = (0, exports.assignFilters)(result.filters, query, additionalFilters, options);
|
|
207
|
+
result.query = (0, exports.cleanQuery)(query, exports.OPERATORS.concat(additionalOperators), result.filters);
|
|
208
|
+
return result;
|
|
209
|
+
};
|
|
210
|
+
exports.filterQuery = filterQuery;
|
|
211
|
+
const assignFilters = (object, query, filters, options) => {
|
|
212
|
+
if (Array.isArray(filters)) {
|
|
213
|
+
_.forEach(filters, (key) => {
|
|
214
|
+
if (query[key] !== undefined) {
|
|
215
|
+
object[key] = query[key];
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
_.forEach(filters, (converter, key) => {
|
|
221
|
+
const converted = converter(query[key], options);
|
|
222
|
+
if (converted !== undefined) {
|
|
223
|
+
object[key] = converted;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return object;
|
|
228
|
+
};
|
|
229
|
+
exports.assignFilters = assignFilters;
|
|
230
|
+
const cleanQuery = (query, operators, filters) => {
|
|
231
|
+
if (Array.isArray(query)) {
|
|
232
|
+
return query.map((value) => (0, exports.cleanQuery)(value, operators, filters));
|
|
233
|
+
}
|
|
234
|
+
else if (_.isPlainObject(query)) {
|
|
235
|
+
const result = {};
|
|
236
|
+
_.forEach(query, (value, key) => {
|
|
237
|
+
if (key.startsWith('$')) {
|
|
238
|
+
if (filters[key] === undefined && !operators.includes(key)) {
|
|
239
|
+
throw new common_1.BadRequestException(`Invalid query parameter: ${key}`, query);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
result[key] = (0, exports.cleanQuery)(value, operators, filters);
|
|
243
|
+
});
|
|
244
|
+
Object.getOwnPropertySymbols(query).forEach((symbol) => {
|
|
245
|
+
result[symbol] = query[symbol];
|
|
246
|
+
});
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
return query;
|
|
250
|
+
};
|
|
251
|
+
exports.cleanQuery = cleanQuery;
|
|
252
|
+
//# sourceMappingURL=query.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.utils.js","sourceRoot":"","sources":["../../../../../packages/prisma/src/common/query.utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GlobalExceptionFilter = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const http_exception_1 = require("@nestjs/common/exceptions/http.exception");
|
|
7
|
+
const zod_1 = require("zod");
|
|
8
|
+
const prisma_error_filter_1 = require("./prisma-error.filter");
|
|
9
|
+
let GlobalExceptionFilter = class GlobalExceptionFilter {
|
|
10
|
+
catch(exception, host) {
|
|
11
|
+
var _a, _b;
|
|
12
|
+
const ctx = host.switchToHttp();
|
|
13
|
+
const response = ctx.getResponse();
|
|
14
|
+
const request = ctx.getRequest();
|
|
15
|
+
if (exception instanceof http_exception_1.HttpException) {
|
|
16
|
+
return response
|
|
17
|
+
.status(exception.getStatus())
|
|
18
|
+
.json(exception.getResponse());
|
|
19
|
+
}
|
|
20
|
+
// Prisma known request errors (P2002, P2003, P2025, etc.)
|
|
21
|
+
if (((_a = exception.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'PrismaClientKnownRequestError') {
|
|
22
|
+
const error = new common_1.BadRequestException(exception);
|
|
23
|
+
return response
|
|
24
|
+
.status(error.getStatus())
|
|
25
|
+
.json((0, prisma_error_filter_1.handlePrismaError)(exception));
|
|
26
|
+
}
|
|
27
|
+
// Prisma validation errors
|
|
28
|
+
if (((_b = exception.constructor) === null || _b === void 0 ? void 0 : _b.name) === 'PrismaClientValidationError') {
|
|
29
|
+
const error = new common_1.BadRequestException(exception.message);
|
|
30
|
+
return response.status(error.getStatus()).json(error.getResponse());
|
|
31
|
+
}
|
|
32
|
+
if (exception instanceof zod_1.ZodError) {
|
|
33
|
+
const error = new common_1.BadRequestException(exception);
|
|
34
|
+
return response.status(error.getStatus()).json(error.getResponse());
|
|
35
|
+
}
|
|
36
|
+
response.status(500).json({
|
|
37
|
+
statusCode: 500,
|
|
38
|
+
timestamp: new Date().toISOString(),
|
|
39
|
+
error: {
|
|
40
|
+
name: exception.name,
|
|
41
|
+
message: exception.message || 'Internal Server Error',
|
|
42
|
+
// todo: remove stack in production
|
|
43
|
+
stack: process.env['NODE_ENV'] === 'production' ? undefined : exception.stack,
|
|
44
|
+
},
|
|
45
|
+
path: request.url,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
exports.GlobalExceptionFilter = GlobalExceptionFilter;
|
|
50
|
+
exports.GlobalExceptionFilter = GlobalExceptionFilter = tslib_1.__decorate([
|
|
51
|
+
(0, common_1.Catch)()
|
|
52
|
+
], GlobalExceptionFilter);
|
|
53
|
+
//# sourceMappingURL=global-exception.filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-exception.filter.js","sourceRoot":"","sources":["../../../../../packages/prisma/src/filters/global-exception.filter.ts"],"names":[],"mappings":";;;;AAAA,2CAKwB;AACxB,6EAAyE;AACzE,6BAA+B;AAC/B,+DAA0D;AAGnD,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAC9B,KAAK,CAAC,SAAc,EAAE,IAAmB;;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC;QAEjC,IAAI,SAAS,YAAY,8BAAa,EAAE,CAAC;YACrC,OAAO,QAAQ;iBACV,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;iBAC7B,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;QACvC,CAAC;QAED,0DAA0D;QAC1D,IAAI,CAAA,MAAA,SAAS,CAAC,WAAW,0CAAE,IAAI,MAAK,+BAA+B,EAAE,CAAC;YAClE,MAAM,KAAK,GAAG,IAAI,4BAAmB,CAAC,SAAS,CAAC,CAAC;YACjD,OAAO,QAAQ;iBACV,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;iBACzB,IAAI,CAAC,IAAA,uCAAiB,EAAC,SAAS,CAAC,CAAC,CAAC;QAC5C,CAAC;QAED,2BAA2B;QAC3B,IAAI,CAAA,MAAA,SAAS,CAAC,WAAW,0CAAE,IAAI,MAAK,6BAA6B,EAAE,CAAC;YAChE,MAAM,KAAK,GAAG,IAAI,4BAAmB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACzD,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,IAAI,SAAS,YAAY,cAAQ,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,IAAI,4BAAmB,CAAC,SAAS,CAAC,CAAC;YACjD,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACtB,UAAU,EAAE,GAAG;YACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,KAAK,EAAE;gBACH,IAAI,EAAE,SAAS,CAAC,IAAI;gBACpB,OAAO,EAAE,SAAS,CAAC,OAAO,IAAI,uBAAuB;gBACrD,mCAAmC;gBACnC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK;aAChF;YACD,IAAI,EAAE,OAAO,CAAC,GAAG;SACpB,CAAC,CAAC;IACP,CAAC;CACJ,CAAA;AA3CY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,cAAK,GAAE;GACK,qBAAqB,CA2CjC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handlePrismaError = handlePrismaError;
|
|
4
|
+
/**
|
|
5
|
+
* Translates Prisma error codes to human-readable messages.
|
|
6
|
+
* @see https://www.prisma.io/docs/reference/api-reference/error-reference
|
|
7
|
+
*/
|
|
8
|
+
function handlePrismaError(exception) {
|
|
9
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
10
|
+
let message = 'A database error occurred.';
|
|
11
|
+
const details = exception.message;
|
|
12
|
+
switch (exception.code) {
|
|
13
|
+
case 'P2002': {
|
|
14
|
+
const target = (_a = exception.meta) === null || _a === void 0 ? void 0 : _a.target;
|
|
15
|
+
const field = Array.isArray(target) ? target.join(', ') : target || 'unknown field';
|
|
16
|
+
message = `${field} must be unique. A record with this value already exists.`;
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
case 'P2003': {
|
|
20
|
+
const fieldName = ((_b = exception.meta) === null || _b === void 0 ? void 0 : _b.field_name) || 'unknown field';
|
|
21
|
+
message = `Foreign key constraint failed on field: ${fieldName}.`;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
case 'P2025':
|
|
25
|
+
message = 'Record not found. The requested resource does not exist or has been deleted.';
|
|
26
|
+
break;
|
|
27
|
+
case 'P2014': {
|
|
28
|
+
const relationName = ((_c = exception.meta) === null || _c === void 0 ? void 0 : _c.relation_name) || 'unknown';
|
|
29
|
+
message = `The change you are trying to make would violate the required relation '${relationName}'.`;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
case 'P2000': {
|
|
33
|
+
const column = ((_d = exception.meta) === null || _d === void 0 ? void 0 : _d.column_name) || 'unknown column';
|
|
34
|
+
message = `The provided value is too long for column '${column}'.`;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
case 'P2006': {
|
|
38
|
+
const fieldMeta = ((_e = exception.meta) === null || _e === void 0 ? void 0 : _e.field_name) || 'unknown field';
|
|
39
|
+
message = `The provided value for '${fieldMeta}' is invalid.`;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case 'P2011': {
|
|
43
|
+
const constraint = ((_f = exception.meta) === null || _f === void 0 ? void 0 : _f.constraint) || 'unknown field';
|
|
44
|
+
message = `Null constraint violation on '${constraint}'. This field cannot be null.`;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case 'P2024':
|
|
48
|
+
message = 'Connection pool timeout. The database connection could not be established in time. Please try again later.';
|
|
49
|
+
break;
|
|
50
|
+
case 'P2021': {
|
|
51
|
+
const table = ((_g = exception.meta) === null || _g === void 0 ? void 0 : _g.table) || 'unknown';
|
|
52
|
+
message = `The table '${table}' does not exist in the current database.`;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
case 'P2022': {
|
|
56
|
+
const col = ((_h = exception.meta) === null || _h === void 0 ? void 0 : _h.column) || 'unknown';
|
|
57
|
+
message = `The column '${col}' does not exist in the current database.`;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
default:
|
|
61
|
+
message =
|
|
62
|
+
'An unknown database error occurred. Please contact support if the issue persists.';
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
message,
|
|
66
|
+
details: process.env['NODE_ENV'] === 'production' ? undefined : details,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=prisma-error.filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-error.filter.js","sourceRoot":"","sources":["../../../../../packages/prisma/src/filters/prisma-error.filter.ts"],"names":[],"mappings":";;AAIA,8CA0EC;AA9ED;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,SAAc;;IAI5C,IAAI,OAAO,GAAG,4BAA4B,CAAC;IAC3C,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC;IAElC,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,OAAO,CAAC,CAAC,CAAC;YACX,MAAM,MAAM,GAAG,MAAA,SAAS,CAAC,IAAI,0CAAE,MAAM,CAAC;YACtC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,eAAe,CAAC;YACpF,OAAO,GAAG,GAAG,KAAK,2DAA2D,CAAC;YAC9E,MAAM;QACV,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACX,MAAM,SAAS,GAAG,CAAA,MAAA,SAAS,CAAC,IAAI,0CAAE,UAAU,KAAI,eAAe,CAAC;YAChE,OAAO,GAAG,2CAA2C,SAAS,GAAG,CAAC;YAClE,MAAM;QACV,CAAC;QAED,KAAK,OAAO;YACR,OAAO,GAAG,8EAA8E,CAAC;YACzF,MAAM;QAEV,KAAK,OAAO,CAAC,CAAC,CAAC;YACX,MAAM,YAAY,GAAG,CAAA,MAAA,SAAS,CAAC,IAAI,0CAAE,aAAa,KAAI,SAAS,CAAC;YAChE,OAAO,GAAG,0EAA0E,YAAY,IAAI,CAAC;YACrG,MAAM;QACV,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACX,MAAM,MAAM,GAAG,CAAA,MAAA,SAAS,CAAC,IAAI,0CAAE,WAAW,KAAI,gBAAgB,CAAC;YAC/D,OAAO,GAAG,8CAA8C,MAAM,IAAI,CAAC;YACnE,MAAM;QACV,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACX,MAAM,SAAS,GAAG,CAAA,MAAA,SAAS,CAAC,IAAI,0CAAE,UAAU,KAAI,eAAe,CAAC;YAChE,OAAO,GAAG,2BAA2B,SAAS,eAAe,CAAC;YAC9D,MAAM;QACV,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACX,MAAM,UAAU,GAAG,CAAA,MAAA,SAAS,CAAC,IAAI,0CAAE,UAAU,KAAI,eAAe,CAAC;YACjE,OAAO,GAAG,iCAAiC,UAAU,+BAA+B,CAAC;YACrF,MAAM;QACV,CAAC;QAED,KAAK,OAAO;YACR,OAAO,GAAG,4GAA4G,CAAC;YACvH,MAAM;QAEV,KAAK,OAAO,CAAC,CAAC,CAAC;YACX,MAAM,KAAK,GAAG,CAAA,MAAA,SAAS,CAAC,IAAI,0CAAE,KAAK,KAAI,SAAS,CAAC;YACjD,OAAO,GAAG,cAAc,KAAK,2CAA2C,CAAC;YACzE,MAAM;QACV,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACX,MAAM,GAAG,GAAG,CAAA,MAAA,SAAS,CAAC,IAAI,0CAAE,MAAM,KAAI,SAAS,CAAC;YAChD,OAAO,GAAG,eAAe,GAAG,2CAA2C,CAAC;YACxE,MAAM;QACV,CAAC;QAED;YACI,OAAO;gBACH,mFAAmF,CAAC;IAChG,CAAC;IAED,OAAO;QACH,OAAO;QACP,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;KAC1E,CAAC;AACN,CAAC"}
|
package/src/index.d.ts
ADDED
package/src/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./lib/nest.service"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./common/query.utils"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./common/apply-filters"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./types/PrismaFilters"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./filters/global-exception.filter"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./filters/prisma-error.filter"), exports);
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/prisma/src/index.ts"],"names":[],"mappings":";;;AAAA,6DAAmC;AACnC,+DAAqC;AACrC,iEAAuC;AACvC,gEAAsC;AACtC,4EAAkD;AAClD,wEAA8C"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { PaginatedResponse } from '@nest-extended/core';
|
|
2
|
+
import { NestServiceOptions } from '@nest-extended/core';
|
|
3
|
+
import { SoftDeleteConfig } from '@nest-extended/core';
|
|
4
|
+
/**
|
|
5
|
+
* Generic CRUD service for Prisma — same API surface as the Mongoose NestService.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* @Injectable()
|
|
10
|
+
* export class CatsService extends NestService<any> {
|
|
11
|
+
* constructor(private readonly prisma: PrismaService) {
|
|
12
|
+
* super(prisma.cat);
|
|
13
|
+
* }
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Supports:
|
|
18
|
+
* - Full CRUD: _find, _get, _create, _patch, _remove
|
|
19
|
+
* - FeathersJS-style query operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $like, $notLike, $iLike, $notILike, $or, $and
|
|
20
|
+
* - Pagination: $limit, $skip
|
|
21
|
+
* - Field selection: $select
|
|
22
|
+
* - Relations: $include (replaces Mongoose $populate)
|
|
23
|
+
* - Sorting: $sort
|
|
24
|
+
* - Soft delete: configurable via SoftDeleteConfig
|
|
25
|
+
* - Bulk operations: multi mode for createMany/updateMany
|
|
26
|
+
*/
|
|
27
|
+
export declare class NestService<T> {
|
|
28
|
+
private model;
|
|
29
|
+
private options;
|
|
30
|
+
private softDeleteConfig;
|
|
31
|
+
constructor(model: any, serviceOptions?: NestServiceOptions, softDeleteConfig?: SoftDeleteConfig);
|
|
32
|
+
/**
|
|
33
|
+
* Merge soft-delete filter into the where clause if soft delete is enabled.
|
|
34
|
+
*/
|
|
35
|
+
private applySoftDeleteFilter;
|
|
36
|
+
_find<P extends boolean = true>(query?: Record<string, any>, findOptions?: {
|
|
37
|
+
pagination?: P;
|
|
38
|
+
}): Promise<P extends true ? PaginatedResponse<T> : T[]>;
|
|
39
|
+
_create(data: Partial<T>): Promise<T>;
|
|
40
|
+
_create(data: Partial<T>[]): Promise<T[]>;
|
|
41
|
+
_patch(id: string | null, data: Record<any, any>, query?: Record<string, any>): Promise<T | T[] | null>;
|
|
42
|
+
_get(id: string, query?: Record<string, any>): Promise<T | null>;
|
|
43
|
+
_remove(id: string | null, query?: Record<string, any>, user?: any): Promise<T | T[] | null>;
|
|
44
|
+
getCount(filter?: Record<string, any>): Promise<any>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NestService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const query_utils_1 = require("../common/query.utils");
|
|
7
|
+
const core_1 = require("@nest-extended/core");
|
|
8
|
+
const apply_filters_1 = require("../common/apply-filters");
|
|
9
|
+
const core_2 = require("@nest-extended/core");
|
|
10
|
+
/**
|
|
11
|
+
* Default soft delete configuration for Prisma.
|
|
12
|
+
* Uses `deleted` boolean field instead of MongoDB-style `$ne` query.
|
|
13
|
+
*/
|
|
14
|
+
const defaultSoftDeleteConfig = {
|
|
15
|
+
getQuery: () => ({ [core_1.options.deleteKey || 'deleted']: { not: true } }),
|
|
16
|
+
getData: (user) => {
|
|
17
|
+
var _a;
|
|
18
|
+
return ({
|
|
19
|
+
deleted: true,
|
|
20
|
+
deletedBy: (_a = user === null || user === void 0 ? void 0 : user.id) !== null && _a !== void 0 ? _a : null,
|
|
21
|
+
deletedAt: new Date(),
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Generic CRUD service for Prisma — same API surface as the Mongoose NestService.
|
|
27
|
+
*
|
|
28
|
+
* Usage:
|
|
29
|
+
* ```typescript
|
|
30
|
+
* @Injectable()
|
|
31
|
+
* export class CatsService extends NestService<any> {
|
|
32
|
+
* constructor(private readonly prisma: PrismaService) {
|
|
33
|
+
* super(prisma.cat);
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* Supports:
|
|
39
|
+
* - Full CRUD: _find, _get, _create, _patch, _remove
|
|
40
|
+
* - FeathersJS-style query operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $like, $notLike, $iLike, $notILike, $or, $and
|
|
41
|
+
* - Pagination: $limit, $skip
|
|
42
|
+
* - Field selection: $select
|
|
43
|
+
* - Relations: $include (replaces Mongoose $populate)
|
|
44
|
+
* - Sorting: $sort
|
|
45
|
+
* - Soft delete: configurable via SoftDeleteConfig
|
|
46
|
+
* - Bulk operations: multi mode for createMany/updateMany
|
|
47
|
+
*/
|
|
48
|
+
class NestService {
|
|
49
|
+
constructor(model, serviceOptions = {}, softDeleteConfig) {
|
|
50
|
+
this.model = model;
|
|
51
|
+
this.options = Object.assign({ multi: false, softDelete: true, pagination: true }, serviceOptions);
|
|
52
|
+
this.softDeleteConfig = softDeleteConfig || defaultSoftDeleteConfig;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Merge soft-delete filter into the where clause if soft delete is enabled.
|
|
56
|
+
*/
|
|
57
|
+
applySoftDeleteFilter(where) {
|
|
58
|
+
if (this.options.softDelete) {
|
|
59
|
+
const softDeleteQuery = this.softDeleteConfig.getQuery();
|
|
60
|
+
// Convert NestExtended soft delete query to Prisma format
|
|
61
|
+
// { deleted: { $ne: true } } → { deleted: { not: true } }
|
|
62
|
+
for (const key in softDeleteQuery) {
|
|
63
|
+
if (softDeleteQuery.hasOwnProperty(key)) {
|
|
64
|
+
const val = softDeleteQuery[key];
|
|
65
|
+
if (typeof val === 'object' && val !== null && val['$ne'] !== undefined) {
|
|
66
|
+
where[key] = { not: val['$ne'] };
|
|
67
|
+
}
|
|
68
|
+
else if (typeof val === 'object' && val !== null && val['not'] !== undefined) {
|
|
69
|
+
where[key] = val;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
where[key] = val;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
_find() {
|
|
79
|
+
return tslib_1.__awaiter(this, arguments, void 0, function* (query = {}, findOptions = {
|
|
80
|
+
pagination: this.options.pagination,
|
|
81
|
+
}) {
|
|
82
|
+
var _a;
|
|
83
|
+
query = Object.assign({}, query);
|
|
84
|
+
const filters = (0, query_utils_1.assignFilters)({}, query, query_utils_1.FILTERS, {});
|
|
85
|
+
const where = (0, query_utils_1.rawQuery)(query);
|
|
86
|
+
// Apply soft delete filter
|
|
87
|
+
this.applySoftDeleteFilter(where);
|
|
88
|
+
const isPaginationEnabled = (_a = findOptions.pagination) !== null && _a !== void 0 ? _a : this.options.pagination;
|
|
89
|
+
// Build Prisma query options
|
|
90
|
+
const queryOptions = { where };
|
|
91
|
+
(0, apply_filters_1.applyFilters)(queryOptions, filters, core_1.options, !isPaginationEnabled);
|
|
92
|
+
if (!isPaginationEnabled) {
|
|
93
|
+
return (yield this.model.findMany(queryOptions));
|
|
94
|
+
}
|
|
95
|
+
const [data, total] = yield Promise.all([
|
|
96
|
+
this.model.findMany(queryOptions),
|
|
97
|
+
this.model.count({ where }),
|
|
98
|
+
]);
|
|
99
|
+
return {
|
|
100
|
+
total,
|
|
101
|
+
$limit: Number(filters.$limit) || core_1.options.defaultLimit,
|
|
102
|
+
$skip: Number(filters.$skip) || core_1.options.defaultSkip,
|
|
103
|
+
data,
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
_create(data) {
|
|
108
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
109
|
+
const multi = this.options.multi;
|
|
110
|
+
if (multi) {
|
|
111
|
+
if (Array.isArray(data)) {
|
|
112
|
+
// Prisma createMany doesn't return the created records
|
|
113
|
+
// We need to use a transaction for bulk create with return
|
|
114
|
+
const results = [];
|
|
115
|
+
for (const item of data) {
|
|
116
|
+
const created = yield this.model.create({ data: item });
|
|
117
|
+
results.push(created);
|
|
118
|
+
}
|
|
119
|
+
return results;
|
|
120
|
+
}
|
|
121
|
+
return this.model.create({ data });
|
|
122
|
+
}
|
|
123
|
+
// When multi is disabled, only accept single object
|
|
124
|
+
if (Array.isArray(data)) {
|
|
125
|
+
throw new common_1.BadRequestException('Bulk creation is not enabled. Set multi: true in service options to allow array input.');
|
|
126
|
+
}
|
|
127
|
+
return this.model.create({ data });
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
_patch(id_1, data_1) {
|
|
131
|
+
return tslib_1.__awaiter(this, arguments, void 0, function* (id, data, query = {}) {
|
|
132
|
+
query = Object.assign({}, query);
|
|
133
|
+
const where = (0, query_utils_1.rawQuery)(query);
|
|
134
|
+
this.applySoftDeleteFilter(where);
|
|
135
|
+
if (id) {
|
|
136
|
+
// Single record update by ID
|
|
137
|
+
const searchWhere = Object.assign({ id }, where);
|
|
138
|
+
const filters = (0, query_utils_1.assignFilters)({}, query, query_utils_1.FILTERS, {});
|
|
139
|
+
const queryOptions = {};
|
|
140
|
+
// Apply select/include if provided
|
|
141
|
+
if (filters.$select) {
|
|
142
|
+
queryOptions['select'] = filters.$select;
|
|
143
|
+
}
|
|
144
|
+
if (filters.$include) {
|
|
145
|
+
if (queryOptions['select']) {
|
|
146
|
+
const include = filters.$include;
|
|
147
|
+
for (const key in include) {
|
|
148
|
+
if (include.hasOwnProperty(key)) {
|
|
149
|
+
queryOptions['select'][key] = include[key];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
queryOptions['include'] = filters.$include;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return this.model.update(Object.assign({ where: searchWhere, data }, queryOptions));
|
|
158
|
+
}
|
|
159
|
+
// Bulk update (id is null)
|
|
160
|
+
const result = yield this.model.updateMany({
|
|
161
|
+
where,
|
|
162
|
+
data,
|
|
163
|
+
});
|
|
164
|
+
if (result.count > 0) {
|
|
165
|
+
return this.model.findMany({ where });
|
|
166
|
+
}
|
|
167
|
+
return [];
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
_get(id_1) {
|
|
171
|
+
return tslib_1.__awaiter(this, arguments, void 0, function* (id, query = {}) {
|
|
172
|
+
query = Object.assign({}, query);
|
|
173
|
+
const filters = (0, query_utils_1.assignFilters)({}, query, query_utils_1.FILTERS, {});
|
|
174
|
+
const where = (0, query_utils_1.rawQuery)(query);
|
|
175
|
+
this.applySoftDeleteFilter(where);
|
|
176
|
+
const searchWhere = Object.assign(Object.assign({}, where), { id });
|
|
177
|
+
const queryOptions = { where: searchWhere };
|
|
178
|
+
const isSingleOperation = true;
|
|
179
|
+
(0, apply_filters_1.applyFilters)(queryOptions, filters, core_1.options, isSingleOperation);
|
|
180
|
+
// Remove take/skip for single record fetch
|
|
181
|
+
delete queryOptions['take'];
|
|
182
|
+
delete queryOptions['skip'];
|
|
183
|
+
return (yield this.model.findFirst(queryOptions)) || null;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
_remove(id_1) {
|
|
187
|
+
return tslib_1.__awaiter(this, arguments, void 0, function* (id, query = {}, user) {
|
|
188
|
+
query = Object.assign({}, query);
|
|
189
|
+
const where = (0, query_utils_1.rawQuery)(query);
|
|
190
|
+
const data = id ? yield this._get(id, query) : null;
|
|
191
|
+
if (this.options.softDelete) {
|
|
192
|
+
// Get user from parameter or fallback to CLS context
|
|
193
|
+
const currentUser = user !== null && user !== void 0 ? user : (0, core_2.getCurrentUser)();
|
|
194
|
+
// Soft delete: mark as deleted using configured getData
|
|
195
|
+
const softDeleteData = this.softDeleteConfig.getData(currentUser);
|
|
196
|
+
yield this._patch(id, softDeleteData, where);
|
|
197
|
+
return data;
|
|
198
|
+
}
|
|
199
|
+
// Hard delete: actually remove from database
|
|
200
|
+
if (id) {
|
|
201
|
+
yield this.model.delete({ where: Object.assign({ id }, where) });
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
yield this.model.deleteMany({ where });
|
|
205
|
+
}
|
|
206
|
+
return data;
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
getCount() {
|
|
210
|
+
return tslib_1.__awaiter(this, arguments, void 0, function* (filter = {}) {
|
|
211
|
+
return this.model.count({ where: filter });
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
exports.NestService = NestService;
|
|
216
|
+
//# sourceMappingURL=nest.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nest.service.js","sourceRoot":"","sources":["../../../../../packages/prisma/src/lib/nest.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface PrismaFilterOptions {
|
|
2
|
+
defaultLimit: number;
|
|
3
|
+
defaultSkip: number;
|
|
4
|
+
defaultPagination: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface PrismaFilters {
|
|
7
|
+
$select?: Record<string, boolean> | string[];
|
|
8
|
+
$include?: Record<string, boolean | object>;
|
|
9
|
+
$sort?: Record<string, 'asc' | 'desc'> | Record<string, number>;
|
|
10
|
+
$limit?: number | string;
|
|
11
|
+
$skip?: number | string;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrismaFilters.js","sourceRoot":"","sources":["../../../../../packages/prisma/src/types/PrismaFilters.ts"],"names":[],"mappings":""}
|