vsrepo 2.2.1 β 2.4.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 +147 -145
- package/README.pt-BR.md +183 -181
- package/dist/VSRepository.d.ts +3 -2
- package/dist/VSRepository.js +3 -2
- package/dist/VSRepository.js.map +1 -1
- package/dist/decorators/query-method.decorator.d.ts +7 -4
- package/dist/decorators/query-method.decorator.js +7 -4
- package/dist/decorators/query-method.decorator.js.map +1 -1
- package/dist/internal/enums/adapter-error-code.enum.d.ts +4 -0
- package/dist/internal/enums/adapter-error-code.enum.js +4 -0
- package/dist/internal/enums/adapter-error-code.enum.js.map +1 -1
- package/dist/internal/utils/vs-logger.util.d.ts +2 -2
- package/dist/internal/utils/vs-logger.util.js +7 -4
- package/dist/internal/utils/vs-logger.util.js.map +1 -1
- package/dist/internal/validators/vsrepo.validator.js +1 -1
- package/dist/internal/validators/vsrepo.validator.js.map +1 -1
- package/dist/types/utils/query-method-arg.type.d.ts +4 -2
- package/dist/types/vsrepo/vsrepo-options.type.d.ts +4 -1
- package/dist/types/vsrepo/vsrepo-query-options.type.d.ts +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -13,16 +13,14 @@
|
|
|
13
13
|
|
|
14
14
|
πΊπΈ You're reading the English version. [π§π· Ler em portuguΓͺs](./README.pt-BR.md)
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
**ORM-agnostic** repository pattern library, with full **TypeScript** support and automatic **type inference**. VSRepository v2 is a rewrite of the [v1](https://github.com/jaobrabo123/VSRepository/tree/v1) library: instead of talking to Prisma directly, the core now delegates every operation to a pluggable **adapter**, so the same repository API can work against Prisma, TypeORM, or any other ORM/database that implements the adapter contract.
|
|
16
|
+
**ORM-agnostic** repository pattern library, with full **TypeScript** support and automatic **type inference**. VSRepository v2 is a rewrite of the [v1](https://github.com/jaobrabo123/VSRepository/tree/v1) library: instead of talking to Prisma directly, the core now delegates every operation to a pluggable **adapter**, so the same repository API can work against Prisma, Drizzle, or any other ORM/database that implements the adapter contract.
|
|
19
17
|
|
|
20
18
|
VSRepository lets you create strongly-typed repositories with:
|
|
21
19
|
|
|
22
20
|
- Automatic **base methods**: `get`, `getOrThrow`, `getList`, `save`, `saveList`, `remove`, `removeList`, `patch`, `merge`, `getAll`, `total`, `has`
|
|
23
21
|
- **Native soft-delete**: `softRemove`, `softRemoveList`, `restore`, `restoreList`
|
|
24
22
|
- **Dynamic methods** inferred from a `declare` field name via the `@DynamicMethod` decorator: `findByEmail`, `findManyByStatusPaginated`, `updateById`
|
|
25
|
-
- **Raw SQL query methods** via the
|
|
23
|
+
- **Raw SQL query methods** via the `@QueryMethod` decorator, bypassing the name-parsing engine entirely
|
|
26
24
|
- Ad-hoc **`select`/`relations`** per call β no more pre-declared named projections
|
|
27
25
|
- **Type safety** across 100% of operations
|
|
28
26
|
- Native ORM **transactions**, shared across repositories
|
|
@@ -71,16 +69,16 @@ If you're coming from the [v1](https://github.com/jaobrabo123/VSRepository/tree/
|
|
|
71
69
|
|
|
72
70
|
| Area | v1 | v2 |
|
|
73
71
|
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
74
|
-
| Database access | Talks to **Prisma** directly, bundled in the core package | Talks to a **`VSRepoAdapter`**; ORM support ships as separate packages (`@vsrepo/prisma7-adapter`, `@vsrepo/
|
|
72
|
+
| Database access | Talks to **Prisma** directly, bundled in the core package | Talks to a **`VSRepoAdapter`**; ORM support ships as separate packages (`@vsrepo/prisma7-adapter`, `@vsrepo/drizzle-adapter`, ...) instead of being bundled in the core `vsrepo` package |
|
|
75
73
|
| Defining a repository | Functional `setupVSRepo<T, M>()({...}).build(prisma)`, **or** a `DynamicRepository` class | A single **class-based** API: `extends VSRepository<Entity, PKType, OrmTypes>` |
|
|
76
74
|
| Dynamic methods | `methods: { findByEmail: { map: true } }` config object | `@DynamicMethod()` decorator on a `declare` field |
|
|
77
75
|
| Data projections | Named, reusable `selectModels` + `defaultSelectModel` | Ad-hoc `select`/`relations` passed per call (no named models) |
|
|
78
76
|
| Eager loading | `include`/`includeModels` (Prisma-specific) | ORM-agnostic `relations` option |
|
|
79
|
-
| Global filters | `requiredWhere`
|
|
77
|
+
| Global filters | `requiredWhere` and `pushWhere` | **Removed**; Now it only accepts `softRemoveKey` + `see: "active" \| "removed" \| "all"` |
|
|
80
78
|
| Case-insensitive filter suffix | `Insensitive` | `IgnoreCase` |
|
|
81
79
|
| Inline ordering in method name | Not supported (`order` had to be passed as an argument via `Ordered`/`Paginated`) | `OrderBy<Field>Asc`/`OrderBy<Field>Desc` chains baked directly into the method name |
|
|
82
80
|
| Duplicate handling on `createMany` | `SkipDuplicates` suffix | `IgnoreConflicts` suffix |
|
|
83
|
-
| `aggregate` / `groupBy` | Supported (Prisma-native passthrough) | **
|
|
81
|
+
| `aggregate` / `groupBy` | Supported (Prisma-native passthrough) | `groupBy` is **not planned** for v2. `aggregate` as a prefix is also unlikely: the most common operations are already covered by dedicated base methods (`sum`, `average`, `min`, `max`, `increment`, `decrement`, `multiply`, `divide`) β see [Atomic and aggregate methods](#atomic-and-aggregate-methods). For anything more complex, use `@QueryMethod`. |
|
|
84
82
|
| Error types | `VSRepoError` + subclasses (`VSRepoConfigError`, `VSRepoBuildError`, `VSRepoExtendError`, `VSRepoRuntimeError`) | A base `VSRepoError` class with a `type: VSRepoErrorType` field (`DECORATOR`, `RESOLVER`, `DYNAMIC`, `VALIDATOR`, `BASE`, `ADAPTER`), plus a `VSRepoAdapterError` subclass carrying an `AdapterErrorCode` and the original ORM error |
|
|
85
83
|
| Debug logging | `showWorking: true` boolean | `logLevel: VSLogLevel` (`DEBUG`/`INFO`/`WARN`/`ERROR`) + `logSlowThresholdMs` for slow-query warnings |
|
|
86
84
|
| `vsrepo generate` CLI (type generation step) | Required before use | Not part of the v2 core β types come directly from your entity/ORM types |
|
|
@@ -97,16 +95,16 @@ VSRepository v2 is **ORM-agnostic by design**. The core package (`vsrepo`) only
|
|
|
97
95
|
- `@vsrepo/typeorm-adapter`
|
|
98
96
|
- `@vsrepo/drizzle-adapter`
|
|
99
97
|
|
|
100
|
-
The Prisma 7 adapter has now been published to npm as `@vsrepo/prisma7-adapter
|
|
98
|
+
The Prisma 7 adapter has now been published to npm as `@vsrepo/prisma7-adapter`. The Drizzle adapter is available as an **alpha** release β install it with `@vsrepo/drizzle-adapter@alpha`. Adapters for other ORMs are **planned** but not published yet. Until an official `@vsrepo/*-adapter` package exists for your ORM, you're welcome to write your own for your project, and if you'd like, publish it and open a PR to help grow the ecosystem β contributions here are very welcome.
|
|
101
99
|
|
|
102
|
-
| Adapter
|
|
103
|
-
|
|
|
104
|
-
| Prisma 7 (`@vsrepo/prisma7-adapter`)
|
|
105
|
-
|
|
|
106
|
-
| Other ORMs (Prisma 8,
|
|
107
|
-
| Custom adapters
|
|
100
|
+
| Adapter | Status |
|
|
101
|
+
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
102
|
+
| Prisma 7 (`@vsrepo/prisma7-adapter`) | π’ **Released** β published to npm, implements the `VSRepoAdapter` contract (CRUD, relations, transactions, `merge`, logging) with tests; see [`VSRepoPrisma7Adapter`](https://github.com/jaobrabo123/VSRepoPrisma7Adapter) for source and docs. **Note:** the atomic/aggregate methods (`incrementOne`, `decrementOne`, `multiplyOne`, `divideOne`, `sum`, `average`, `min`, `max` β see [Atomic and aggregate methods](#atomic-and-aggregate-methods)) were added to the `VSRepoAdapter` contract after this adapter's last release; confirm its changelog/version implements them before relying on `increment`/`sum`/etc. against Prisma 7. |
|
|
103
|
+
| Drizzle (`@vsrepo/drizzle-adapter`) | π΅ **Alpha** β an early release is available on npm; install it with `npm i @vsrepo/drizzle-adapter@alpha`. The API may still change before the stable release. Check the [`DrizzleAdapter`](https://github.com/jaobrabo123/VSRepoDrizzleAdapter) repository for the current status and known limitations, and feel free to contribute. |
|
|
104
|
+
| Other ORMs (Prisma 8, TypeORM, etc.) | π‘ **Planned, not published yet.** No official package exists yet β write your own adapter for now (see [Writing your own adapter](#writing-your-own-adapter)), and consider publishing/contributing it back. |
|
|
105
|
+
| Custom adapters | π’ Fully supported today β implement the [`VSRepoAdapter`](#writing-your-own-adapter) abstract class yourself for any ORM/database you need, in your own project or package, following the same shape as `@vsrepo/*-adapter` is expected to have. |
|
|
108
106
|
|
|
109
|
-
In short: the repository class, the `@DynamicMethod`/`@QueryMethod` decorators, the name-parsing engine, error handling and logging are all working end-to-end, and Prisma 7 support is now a released, published adapter. Official adapters for the remaining ORMs are on the roadmap and will ship as separate `@vsrepo/*-adapter` packages rather than as part of the core `vsrepo` package β but you don't have to wait for that: writing (and optionally publishing) your own adapter in the meantime is a fully supported way to use v2 today and to contribute back to the project.
|
|
107
|
+
In short: the repository class, the `@DynamicMethod`/`@QueryMethod` decorators, the name-parsing engine, error handling and logging are all working end-to-end, and Prisma 7 support is now a released, published adapter. The Drizzle adapter is available in alpha. Official adapters for the remaining ORMs are on the roadmap and will ship as separate `@vsrepo/*-adapter` packages rather than as part of the core `vsrepo` package β but you don't have to wait for that: writing (and optionally publishing) your own adapter in the meantime is a fully supported way to use v2 today and to contribute back to the project.
|
|
110
108
|
|
|
111
109
|
---
|
|
112
110
|
|
|
@@ -172,6 +170,7 @@ export default new UserRepository();
|
|
|
172
170
|
> The core API (`VSRepository`, `VSRepoAdapter`, `DynamicMethod`, `QueryMethod`, `VSRepoError`, enums and types) is imported from the single `vsrepo` entry point. The concrete adapter comes from a **separate** package (`@vsrepo/*-adapter`). On Prisma 7, install the published [`@vsrepo/prisma7-adapter`](https://github.com/jaobrabo123/VSRepoPrisma7Adapter) (its constructor takes a config object β `tableName`, `pkName`, optional `relations`/`logLevel` β as shown above). Official adapters for other ORMs are planned but not published yet; until they are, you can implement the `VSRepoAdapter` contract yourself (see [Writing your own adapter](#writing-your-own-adapter)) β and publishing it to help the project is very welcome.
|
|
173
171
|
|
|
174
172
|
> **The third generic parameter (`OrmTypes`):** `VSRepository<Entity, PKType, OrmTypes>` accepts an optional third type parameter describing your ORM's client/transaction types, via `VSRepoOrmTypes` (`{ dbClient; dbTransaction }`). Supplying it gives you a correctly-typed `getDbClient()`, `transaction()` callback, and `db` option on every method, instead of `any`:
|
|
173
|
+
>
|
|
175
174
|
> ```typescript
|
|
176
175
|
> type PrismaOrmTypes = { dbClient: PrismaClient; dbTransaction: Prisma.TransactionClient };
|
|
177
176
|
>
|
|
@@ -179,6 +178,7 @@ export default new UserRepository();
|
|
|
179
178
|
> // getDbClient() now returns PrismaClient, and transaction(fn) types `tx` as Prisma.TransactionClient
|
|
180
179
|
> }
|
|
181
180
|
> ```
|
|
181
|
+
>
|
|
182
182
|
> If omitted, it defaults to `VSRepoOrmTypes` (`dbClient`/`dbTransaction` both `any`).
|
|
183
183
|
|
|
184
184
|
### Using the repository
|
|
@@ -206,14 +206,14 @@ await userRepository.remove(user.id);
|
|
|
206
206
|
|
|
207
207
|
`VSRepoOptions<T, K>`, passed to `super(...)` inside your repository's constructor:
|
|
208
208
|
|
|
209
|
-
| Option | Type
|
|
210
|
-
| -------------------- |
|
|
211
|
-
| `adapter` | `VSRepoAdapter<T>`
|
|
212
|
-
| `pkName` | `keyof T`
|
|
213
|
-
| `softRemoveKey` | `keyof T`
|
|
214
|
-
| `defaultOrdering` | `Ordering<T>`
|
|
215
|
-
| `logLevel` | `VSLogLevel`
|
|
216
|
-
| `logSlowThresholdMs` | `number`
|
|
209
|
+
| Option | Type | Description |
|
|
210
|
+
| -------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
211
|
+
| `adapter` | `VSRepoAdapter<T>` | **Required.** The adapter instance that translates repository calls into calls against the underlying ORM/database. |
|
|
212
|
+
| `pkName` | `keyof T` | **Required.** Name of the field that represents the entity's primary key. |
|
|
213
|
+
| `softRemoveKey` | `keyof T` | Optional. When set, enables `softRemove`, `softRemoveList`, `restore` and `restoreList`. |
|
|
214
|
+
| `defaultOrdering` | `Ordering<T>` | Optional. Default ordering applied automatically to queries that accept `order`, unless overridden per call. |
|
|
215
|
+
| `logLevel` | `VSLogLevel` | Optional. Minimum severity printed by the internal logger. Defaults to `VSLogLevel.WARN`. |
|
|
216
|
+
| `logSlowThresholdMs` | `number \| boolean` | Optional. Duration (ms) above which a finished operation is logged as `WARN`. Defaults to 300ms. Pass `false` to disable slow-operation warnings entirely; pass `true` to use the 300ms default explicitly. |
|
|
217
217
|
|
|
218
218
|
---
|
|
219
219
|
|
|
@@ -221,31 +221,31 @@ await userRepository.remove(user.id);
|
|
|
221
221
|
|
|
222
222
|
Available automatically on every `VSRepository` subclass:
|
|
223
223
|
|
|
224
|
-
| Method
|
|
225
|
-
|
|
|
226
|
-
| `get(pk, options?)`
|
|
227
|
-
| `getOrThrow(pk, options?)`
|
|
228
|
-
| `getList(pks, options?)`
|
|
229
|
-
| `getAll(options?)`
|
|
230
|
-
| `save(obj, options?)`
|
|
231
|
-
| `saveList(objs, options?)`
|
|
232
|
-
| `patch(pk, obj, options?)`
|
|
233
|
-
| `merge(pk, obj, options?)`
|
|
234
|
-
| `remove(pk, options?)`
|
|
235
|
-
| `removeList(pks, options?)`
|
|
236
|
-
| `total(options?)`
|
|
237
|
-
| `has(pk, options?)`
|
|
238
|
-
| `increment(pk, field, value, options?)` | Atomically adds `value` to a numeric field. See [Atomic and aggregate methods](#atomic-and-aggregate-methods).
|
|
239
|
-
| `decrement(pk, field, value, options?)` | Atomically subtracts `value` from a numeric field.
|
|
240
|
-
| `multiply(pk, field, value, options?)` | Atomically multiplies a numeric field by `value`.
|
|
241
|
-
| `divide(pk, field, value, options?)` | Atomically divides a numeric field by `value`.
|
|
242
|
-
| `sum(field, where?, options?)` | Sums a numeric field across every matching record; `null` if none match.
|
|
243
|
-
| `average(field, where?, options?)` | Arithmetic mean of a numeric field across every matching record; `null` if none match.
|
|
244
|
-
| `min(field, where?, options?)` | Minimum value of a numeric field across every matching record; `null` if none match.
|
|
245
|
-
| `max(field, where?, options?)` | Maximum value of a numeric field across every matching record; `null` if none match.
|
|
246
|
-
| `transaction(fn, options?)`
|
|
247
|
-
| `getDbClient()`
|
|
248
|
-
| `query<T>(query, options?)`
|
|
224
|
+
| Method | Description |
|
|
225
|
+
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
226
|
+
| `get(pk, options?)` | Fetches a record by primary key. |
|
|
227
|
+
| `getOrThrow(pk, options?)` | Fetches a record by primary key, throwing if not found. |
|
|
228
|
+
| `getList(pks, options?)` | Fetches multiple records by a list of primary keys. |
|
|
229
|
+
| `getAll(options?)` | Fetches all records; accepts `pagination` and `order` in `options`. |
|
|
230
|
+
| `save(obj, options?)` | Creates or updates (upsert) a single record. |
|
|
231
|
+
| `saveList(objs, options?)` | Creates or updates (upsert) multiple records in one call. |
|
|
232
|
+
| `patch(pk, obj, options?)` | Partially updates a record by primary key. |
|
|
233
|
+
| `merge(pk, obj, options?)` | Fetches a record and returns it deep-merged, in memory, with the given object β does **not** persist anything. |
|
|
234
|
+
| `remove(pk, options?)` | Deletes a record by primary key. |
|
|
235
|
+
| `removeList(pks, options?)` | Deletes multiple records by primary key, returning `{ count }`. |
|
|
236
|
+
| `total(options?)` | Returns the total number of records. |
|
|
237
|
+
| `has(pk, options?)` | Checks whether a record exists, returning `boolean`. |
|
|
238
|
+
| `increment(pk, field, value, options?)` | Atomically adds `value` to a numeric field. See [Atomic and aggregate methods](#atomic-and-aggregate-methods). |
|
|
239
|
+
| `decrement(pk, field, value, options?)` | Atomically subtracts `value` from a numeric field. |
|
|
240
|
+
| `multiply(pk, field, value, options?)` | Atomically multiplies a numeric field by `value`. |
|
|
241
|
+
| `divide(pk, field, value, options?)` | Atomically divides a numeric field by `value`. |
|
|
242
|
+
| `sum(field, where?, options?)` | Sums a numeric field across every matching record; `null` if none match. |
|
|
243
|
+
| `average(field, where?, options?)` | Arithmetic mean of a numeric field across every matching record; `null` if none match. |
|
|
244
|
+
| `min(field, where?, options?)` | Minimum value of a numeric field across every matching record; `null` if none match. |
|
|
245
|
+
| `max(field, where?, options?)` | Maximum value of a numeric field across every matching record; `null` if none match. |
|
|
246
|
+
| `transaction(fn, options?)` | Runs `fn` inside a native transaction of the underlying ORM. |
|
|
247
|
+
| `getDbClient()` | Returns the ORM client instance. |
|
|
248
|
+
| `query<T>(query, options?)` | Executes a raw SQL statement directly against the database. See [Ad-hoc raw queries with `query()`](#ad-hoc-raw-queries-with-query). |
|
|
249
249
|
|
|
250
250
|
Most of the above accept a `MethodOptions<Entity, OrmTypes>` object as their last argument (`select`, `relations`, `see`, `db`). A few β `total`, `has`, `removeList`, `sum`, `average`, `min`, `max`, and the soft-delete batch methods (`softRemoveList`/`restoreList`) β don't return/shape an `Entity`, so they accept the narrower `RestrictMethodOptions<Entity, OrmTypes>` instead (`see`, `db` only; no `select`/`relations`). `transaction`, `query`, and `getDbClient` accept their own options or none at all.
|
|
251
251
|
|
|
@@ -253,7 +253,7 @@ Most of the above accept a `MethodOptions<Entity, OrmTypes>` object as their las
|
|
|
253
253
|
|
|
254
254
|
## Soft-delete
|
|
255
255
|
|
|
256
|
-
Soft-delete is
|
|
256
|
+
Soft-delete is a **first-class, built-in concept**. Configure `softRemoveKey` once on the repository:
|
|
257
257
|
|
|
258
258
|
```typescript
|
|
259
259
|
super({
|
|
@@ -286,7 +286,7 @@ await userRepository.getAll({ see: "all" }); // everything, ignoring soft-delete
|
|
|
286
286
|
|
|
287
287
|
Every `VSRepository` subclass gets 8 extra methods for working with numeric fields, split into two groups:
|
|
288
288
|
|
|
289
|
-
**Atomic updates** β evaluated server-side against the row's
|
|
289
|
+
**Atomic updates** β evaluated server-side against the row's _current_ value (`UPDATE ... SET field = field + value`), not a client-side read-modify-write:
|
|
290
290
|
|
|
291
291
|
```typescript
|
|
292
292
|
await userRepository.increment("user-1", "balance", 50); // balance = balance + 50
|
|
@@ -334,7 +334,7 @@ Note that several ORMs (Drizzle, MikroORM, TypeORM) represent `decimal`/`numeric
|
|
|
334
334
|
|
|
335
335
|
### Writing an adapter
|
|
336
336
|
|
|
337
|
-
`VSRepoAdapter` mirrors the same 8 operations (`incrementOne`, `decrementOne`, `multiplyOne`, `divideOne`, `sum`, `average`, `min`, `max` β see [Writing your own adapter](#writing-your-own-adapter)). Each adapter translates them into whatever its ORM/database considers "native": Prisma has a built-in `{ field: { increment: value } }` update shape and an `aggregate()` call; other ORMs typically need a `QueryBuilder`/raw-`sql` expression (e.g. `SET field = field * :value`, `SELECT SUM(field) ...`) instead. The atomic methods must return the record reflecting the state
|
|
337
|
+
`VSRepoAdapter` mirrors the same 8 operations (`incrementOne`, `decrementOne`, `multiplyOne`, `divideOne`, `sum`, `average`, `min`, `max` β see [Writing your own adapter](#writing-your-own-adapter)). Each adapter translates them into whatever its ORM/database considers "native": Prisma has a built-in `{ field: { increment: value } }` update shape and an `aggregate()` call; other ORMs typically need a `QueryBuilder`/raw-`sql` expression (e.g. `SET field = field * :value`, `SELECT SUM(field) ...`) instead. The atomic methods must return the record reflecting the state _after_ the write β if the ORM's atomic-update API only returns an affected-row count, issue a follow-up read rather than returning a stale in-memory copy.
|
|
338
338
|
|
|
339
339
|
---
|
|
340
340
|
|
|
@@ -360,14 +360,6 @@ const userWithAddress = await userRepository.get(id, {
|
|
|
360
360
|
>
|
|
361
361
|
> The core only forwards `MethodOptions.select` and `MethodOptions.relations` to the adapter β each adapter decides how to translate them to the underlying ORM:
|
|
362
362
|
>
|
|
363
|
-
> - **TypeORM (`@vsrepo/typeorm-adapter`)** β `relations` is **required** to load any relation, even when you only want a nested projection via `select`. TypeORM will not JOIN/emit the relation unless it is listed in `relations`:
|
|
364
|
-
> ```typescript
|
|
365
|
-
> // TypeORM: select alone is NOT enough
|
|
366
|
-
> await userRepository.get(id, {
|
|
367
|
-
> select: { id: true, address: { city: true } },
|
|
368
|
-
> relations: { address: true }, // β required in TypeORM
|
|
369
|
-
> });
|
|
370
|
-
> ```
|
|
371
363
|
> - **Prisma 7 (`@vsrepo/prisma7-adapter` / `VSRepoPrisma7Adapter`)** β `relations` is converted to Prisma `include` (`parsePrismaInclude`). **If `select` is present, `relations` is ignored** because Prisma does not allow `select` + `include` in the same query:
|
|
372
364
|
> ```typescript
|
|
373
365
|
> // Prisma7: relations is ignored when select exists
|
|
@@ -388,7 +380,7 @@ Dynamic methods are declared as a `declare` field annotated with `@DynamicMethod
|
|
|
388
380
|
```typescript
|
|
389
381
|
class UserRepository extends VSRepository<User, string> {
|
|
390
382
|
@DynamicMethod()
|
|
391
|
-
declare findByEmail: (email: string) => Promise<User[]>;
|
|
383
|
+
declare findByEmail: (email: string, options?: MethodOptions<User>) => Promise<User[]>;
|
|
392
384
|
|
|
393
385
|
@DynamicMethod()
|
|
394
386
|
declare findOneByEmail: (email: string) => Promise<User | null>;
|
|
@@ -404,12 +396,11 @@ class UserRepository extends VSRepository<User, string> {
|
|
|
404
396
|
options?: MethodOptions<User>,
|
|
405
397
|
) => Promise<User[]>;
|
|
406
398
|
|
|
407
|
-
//
|
|
399
|
+
// field filters, then pagination, then MethodOptions
|
|
408
400
|
@DynamicMethod()
|
|
409
401
|
declare findByNameIgnoreCaseOrAgeBetweenOrderByCreatedAtAscPaginated: (
|
|
410
402
|
name: string,
|
|
411
403
|
age: [number, number],
|
|
412
|
-
order: Ordering<User>,
|
|
413
404
|
pagination: Pagination,
|
|
414
405
|
options?: MethodOptions<User>,
|
|
415
406
|
) => Promise<User[]>;
|
|
@@ -418,40 +409,40 @@ class UserRepository extends VSRepository<User, string> {
|
|
|
418
409
|
|
|
419
410
|
### Available prefixes
|
|
420
411
|
|
|
421
|
-
| Prefix | Adapter method | Notes
|
|
422
|
-
| -------------------------- | --------------------- |
|
|
423
|
-
| `findBy` | `findMany` | Field filters follow the prefix.
|
|
424
|
-
| `findOneBy` | `findOne` | Field filters follow the prefix; single result.
|
|
425
|
-
| `findOneOrThrowBy` | `findOneOrThrow` | Throws if no record is found.
|
|
426
|
-
| `findOneOrThrow` | `findOneOrThrow` | No field filters; applies only soft-delete/`see`.
|
|
427
|
-
| `findOneOrThrowWhere` | `findOneOrThrow` | Receives a `VSRepoWhere<T>` as the first argument.
|
|
428
|
-
| `findWhere` | `findMany` | Receives a `VSRepoWhere<T>` as the first argument.
|
|
429
|
-
| `findOneWhere` | `findOne` | Receives a `VSRepoWhere<T>` as the first argument.
|
|
430
|
-
| `findOne` | `findOne` | No field filters; applies only soft-delete/`see`.
|
|
431
|
-
| `countBy` | `count` | Field filters follow the prefix.
|
|
432
|
-
| `countWhere` | `count` | Receives a `VSRepoWhere<T>` as the first argument.
|
|
433
|
-
| `count` | `count` | No field filters.
|
|
434
|
-
| `existsBy` | `exists` | Returns `boolean`.
|
|
435
|
-
| `existsWhere` | `exists` | Receives a `VSRepoWhere<T>` as the first argument.
|
|
436
|
-
| `create` | `create` | Receives `
|
|
437
|
-
| `createMany` | `createMany` | Receives `
|
|
438
|
-
| `createManyReturning` | `createManyReturning` | Receives `
|
|
439
|
-
| `updateBy` | `update` | Field filters + `
|
|
440
|
-
| `updateWhere` | `update` | Receives a `VSRepoWhere<T>` as the first argument, then `
|
|
441
|
-
| `updateManyBy` | `updateMany` | Field filters + `
|
|
442
|
-
| `updateManyWhere` | `updateMany` | Receives a `VSRepoWhere<T>` as the first argument, then `
|
|
443
|
-
| `updateManyReturningBy` | `updateManyReturning` | Field filters + `
|
|
444
|
-
| `updateManyReturningWhere` | `updateManyReturning` | Receives a `VSRepoWhere<T>` as the first argument, then `
|
|
445
|
-
| `upsertBy` | `upsert` | Field filters + `create`/`update` payloads.
|
|
446
|
-
| `upsertWhere` | `upsert` | Receives a `VSRepoWhere<T>` as the first argument, then `create`/`update` payloads.
|
|
447
|
-
| `deleteBy` | `delete` | Field filters follow the prefix.
|
|
448
|
-
| `deleteWhere` | `delete` | Receives a `VSRepoWhere<T>` as the first argument.
|
|
449
|
-
| `deleteManyBy` | `deleteMany` | Field filters follow the prefix.
|
|
450
|
-
| `deleteManyWhere` | `deleteMany` | Receives a `VSRepoWhere<T>` as the first argument.
|
|
451
|
-
| `deleteManyReturningBy` | `deleteManyReturning` | Field filters follow the prefix; returns deleted records.
|
|
452
|
-
| `deleteManyReturningWhere` | `deleteManyReturning` | Receives a `VSRepoWhere<T>` as the first argument; returns deleted records.
|
|
453
|
-
|
|
454
|
-
> `
|
|
412
|
+
| Prefix | Adapter method | Notes |
|
|
413
|
+
| -------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
414
|
+
| `findBy` | `findMany` | Field filters follow the prefix. |
|
|
415
|
+
| `findOneBy` | `findOne` | Field filters follow the prefix; single result. |
|
|
416
|
+
| `findOneOrThrowBy` | `findOneOrThrow` | Throws if no record is found. |
|
|
417
|
+
| `findOneOrThrow` | `findOneOrThrow` | No field filters; applies only soft-delete/`see`. |
|
|
418
|
+
| `findOneOrThrowWhere` | `findOneOrThrow` | Receives a `VSRepoWhere<T>` as the first argument. |
|
|
419
|
+
| `findWhere` | `findMany` | Receives a `VSRepoWhere<T>` as the first argument. |
|
|
420
|
+
| `findOneWhere` | `findOne` | Receives a `VSRepoWhere<T>` as the first argument. |
|
|
421
|
+
| `findOne` | `findOne` | No field filters; applies only soft-delete/`see`. |
|
|
422
|
+
| `countBy` | `count` | Field filters follow the prefix. |
|
|
423
|
+
| `countWhere` | `count` | Receives a `VSRepoWhere<T>` as the first argument. |
|
|
424
|
+
| `count` | `count` | No field filters. |
|
|
425
|
+
| `existsBy` | `exists` | Returns `boolean`. |
|
|
426
|
+
| `existsWhere` | `exists` | Receives a `VSRepoWhere<T>` as the first argument. |
|
|
427
|
+
| `create` | `create` | Receives `DeepPartial<Entity>` as argument. |
|
|
428
|
+
| `createMany` | `createMany` | Receives `DeepPartial<Entity>[]` as argument; supports `IgnoreConflicts`. |
|
|
429
|
+
| `createManyReturning` | `createManyReturning` | Receives `DeepPartial<Entity>[]` as argument; supports `IgnoreConflicts`; returns the created records (`T[]`) instead of `CountResult`. |
|
|
430
|
+
| `updateBy` | `update` | Field filters + `DeepPartial<Entity>` as argument. |
|
|
431
|
+
| `updateWhere` | `update` | Receives a `VSRepoWhere<T>` as the first argument, then `DeepPartial<Entity>`. |
|
|
432
|
+
| `updateManyBy` | `updateMany` | Field filters + `DeepPartial<Entity>`. |
|
|
433
|
+
| `updateManyWhere` | `updateMany` | Receives a `VSRepoWhere<T>` as the first argument, then `DeepPartial<Entity>`. |
|
|
434
|
+
| `updateManyReturningBy` | `updateManyReturning` | Field filters + `DeepPartial<Entity>`; returns updated records. |
|
|
435
|
+
| `updateManyReturningWhere` | `updateManyReturning` | Receives a `VSRepoWhere<T>` as the first argument, then `DeepPartial<Entity>`; returns updated records. |
|
|
436
|
+
| `upsertBy` | `upsert` | Field filters + `create`/`update` payloads. |
|
|
437
|
+
| `upsertWhere` | `upsert` | Receives a `VSRepoWhere<T>` as the first argument, then `create`/`update` payloads. |
|
|
438
|
+
| `deleteBy` | `delete` | Field filters follow the prefix. |
|
|
439
|
+
| `deleteWhere` | `delete` | Receives a `VSRepoWhere<T>` as the first argument. |
|
|
440
|
+
| `deleteManyBy` | `deleteMany` | Field filters follow the prefix. |
|
|
441
|
+
| `deleteManyWhere` | `deleteMany` | Receives a `VSRepoWhere<T>` as the first argument. |
|
|
442
|
+
| `deleteManyReturningBy` | `deleteManyReturning` | Field filters follow the prefix; returns deleted records. |
|
|
443
|
+
| `deleteManyReturningWhere` | `deleteManyReturning` | Receives a `VSRepoWhere<T>` as the first argument; returns deleted records. |
|
|
444
|
+
|
|
445
|
+
> `groupBy` is **not planned** for v2 β it doesn't map cleanly onto the ORM-agnostic contract. `aggregate` as a separate prefix is also unlikely to be implemented: the most common aggregate operations (`sum`, `average`, `min`, `max`, `increment`, `decrement`, `multiply`, `divide`) are already available as dedicated base methods β see [Atomic and aggregate methods](#atomic-and-aggregate-methods). For anything more complex, use a `@QueryMethod` with raw SQL.
|
|
455
446
|
|
|
456
447
|
### Field filters
|
|
457
448
|
|
|
@@ -582,6 +573,11 @@ declare findOne: (options?: MethodOptions<User>) => Promise<User | null>;
|
|
|
582
573
|
| `injectOrdering` | `Ordering<T>` | Fixed ordering automatically injected, overriding the repository's `defaultOrdering`. |
|
|
583
574
|
|
|
584
575
|
```typescript
|
|
576
|
+
// proxyTo: gives the method a custom name while reusing an existing pattern
|
|
577
|
+
@DynamicMethod<User>({ proxyTo: "findByEmail" })
|
|
578
|
+
declare buscarPorEmail: (email: string, options?: MethodOptions<User>) => Promise<User[]>;
|
|
579
|
+
|
|
580
|
+
// injectOrdering: always sorts by createdAt desc, overriding defaultOrdering
|
|
585
581
|
@DynamicMethod<User>({ injectOrdering: { createdAt: "desc" } })
|
|
586
582
|
declare findByStatus: (status: string) => Promise<User[]>;
|
|
587
583
|
```
|
|
@@ -590,7 +586,7 @@ declare findByStatus: (status: string) => Promise<User[]>;
|
|
|
590
586
|
|
|
591
587
|
## Query methods (raw SQL)
|
|
592
588
|
|
|
593
|
-
`@QueryMethod` bypasses the name-parsing engine entirely and executes a raw SQL statement through the adapter's `query()` method. Use
|
|
589
|
+
`@QueryMethod` bypasses the name-parsing engine entirely and executes a raw SQL statement through the adapter's `query()` method. Use placeholders for the values passed via `args` β never interpolate values directly into the SQL string. **The placeholder syntax depends on the database/driver behind your adapter:** the `$1`, `$2`, ... style used in the examples below is the PostgreSQL convention β MySQL, for instance, uses `?`. Check your adapter's documentation for the exact syntax.
|
|
594
590
|
|
|
595
591
|
```typescript
|
|
596
592
|
class UserRepository extends VSRepository<User, string> {
|
|
@@ -607,9 +603,9 @@ class UserRepository extends VSRepository<User, string> {
|
|
|
607
603
|
}
|
|
608
604
|
```
|
|
609
605
|
|
|
610
|
-
| Option | Type | Default | Description
|
|
611
|
-
| -------------- | --------- | ------- |
|
|
612
|
-
| `modifying` | `boolean` | `false` | When `true`,
|
|
606
|
+
| Option | Type | Default | Description |
|
|
607
|
+
| -------------- | --------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
608
|
+
| `modifying` | `boolean` | `false` | When `true`, the method resolves to the number of affected rows. When `false`, runs as a read query and resolves to the declared return type. |
|
|
613
609
|
| `singleResult` | `boolean` | `false` | When `true`, collapses an array result into its first element (`null` if empty), so you can declare the return type as a single object instead of an array. Has no effect on non-array results (e.g. a `modifying` query's affected-row count). |
|
|
614
610
|
|
|
615
611
|
Query methods accept `{ args, db? }` at the call site β `db` lets them participate in a `transaction()` block just like base and dynamic methods.
|
|
@@ -626,6 +622,10 @@ class UserRepository extends VSRepository<User, string> {
|
|
|
626
622
|
declare findByEmailAndType: (
|
|
627
623
|
...args: QueryArgs<[email: string, userType: string]>
|
|
628
624
|
) => Promise<User[]>;
|
|
625
|
+
|
|
626
|
+
// Instead of using `QueryArgs`, you can also simply set `DbArg` as the last parameter
|
|
627
|
+
@QueryMethod('SELECT * FROM "user" WHERE id = $1', { spreadArgs: true })
|
|
628
|
+
declare findById: (id: string, db?: DbArg) => Promise<User[]>;
|
|
629
629
|
}
|
|
630
630
|
|
|
631
631
|
const admins = await userRepository.findByEmailAndType("joao@email.com", "admin");
|
|
@@ -634,7 +634,7 @@ const admins = await userRepository.findByEmailAndType("joao@email.com", "admin"
|
|
|
634
634
|
To run the query against a specific client or transaction instead of the repository's default one, pass `withDb(tx)` as the trailing argument β it wraps `tx` in a `DbArg`, which the resolver recognizes with `instanceof`, so it's never confused with a regular positional argument even if that argument happens to be an object:
|
|
635
635
|
|
|
636
636
|
```typescript
|
|
637
|
-
await userRepository.transaction(async
|
|
637
|
+
await userRepository.transaction(async tx => {
|
|
638
638
|
await userRepository.findByEmailAndType("joao@email.com", "admin", withDb(tx));
|
|
639
639
|
});
|
|
640
640
|
```
|
|
@@ -661,18 +661,18 @@ const affectedRows = await userRepository.query<number>(
|
|
|
661
661
|
|
|
662
662
|
// Only one row is ever expected here, so `singleResult` collapses the
|
|
663
663
|
// array into a single object (or `null` when no row matches).
|
|
664
|
-
const user = await userRepository.query<User | null>(
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
);
|
|
664
|
+
const user = await userRepository.query<User | null>('SELECT * FROM "user" WHERE id = $1 LIMIT 1', {
|
|
665
|
+
args: ["123"],
|
|
666
|
+
singleResult: true,
|
|
667
|
+
});
|
|
668
668
|
```
|
|
669
669
|
|
|
670
|
-
| Option | Type | Default | Description
|
|
671
|
-
| -------------- | --------- |
|
|
672
|
-
| `args` | `any[]` | `undefined`
|
|
673
|
-
| `db` | `any` | Repository's default client
|
|
674
|
-
| `modifying` | `boolean` | `false`
|
|
675
|
-
| `singleResult` | `boolean` | `false`
|
|
670
|
+
| Option | Type | Default | Description |
|
|
671
|
+
| -------------- | --------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
672
|
+
| `args` | `any[]` | `undefined` | Positional parameters injected into the SQL placeholders β the placeholder syntax depends on the database/driver behind your adapter. Never interpolate values directly into the SQL string. |
|
|
673
|
+
| `db` | `any` | Repository's default client | Database client or transaction to run this query in. |
|
|
674
|
+
| `modifying` | `boolean` | `false` | When `true`, returns the number of affected rows. |
|
|
675
|
+
| `singleResult` | `boolean` | `false` | When `true`, collapses an array result into its first element (`null` if empty). Has no effect on non-array results (e.g. a `modifying` query's affected-row count). |
|
|
676
676
|
|
|
677
677
|
Just like base, dynamic and query methods, `query()` accepts `db` in `options` to participate in a `transaction()` block.
|
|
678
678
|
|
|
@@ -708,10 +708,10 @@ await userRepository.transaction(
|
|
|
708
708
|
);
|
|
709
709
|
```
|
|
710
710
|
|
|
711
|
-
| Option | Type
|
|
712
|
-
|
|
|
711
|
+
| Option | Type | Description |
|
|
712
|
+
| ---------------- | --------------------------- | ------------------------------------------------------------------------------------- |
|
|
713
713
|
| `isolationLevel` | `TransactionIsolationLevel` | Isolation level to use for the transaction. Defaults to the underlying ORM's default. |
|
|
714
|
-
| `timeoutMs`
|
|
714
|
+
| `timeoutMs` | `number` | Maximum time (in ms) the transaction is allowed to run before being aborted. |
|
|
715
715
|
|
|
716
716
|
`TransactionIsolationLevel` mirrors the standard SQL isolation levels: `READ_UNCOMMITTED`, `READ_COMMITTED`, `REPEATABLE_READ`, `SERIALIZABLE`. Support for a given level depends on the adapter/underlying ORM and database.
|
|
717
717
|
|
|
@@ -746,26 +746,26 @@ import type {
|
|
|
746
746
|
} from "vsrepo";
|
|
747
747
|
```
|
|
748
748
|
|
|
749
|
-
| Type | Description
|
|
750
|
-
| --------------------------------------------------- |
|
|
751
|
-
| `MethodOptions<T, K>` | Options accepted as the last argument
|
|
752
|
-
| `RestrictMethodOptions<T, K>`
|
|
753
|
-
| `Pagination` | `{ limit?, offset? }` accepted by `getAll` and by `Paginated` dynamic methods.
|
|
754
|
-
| `Ordering<T>` / `OrderByField<T>` / `SortDirection` | Ordering shape accepted by `getAll`, `defaultOrdering` and `injectOrdering`, and by `Ordered` dynamic methods. A single object or a chained array; nested objects order to-one relations.
|
|
755
|
-
| `SeeMode` | `"active" \| "removed" \| "all"` β controls visibility of soft-deleted records.
|
|
756
|
-
| `DeepPartial<T>` | Recursively makes every property of `T` optional, including nested objects and array elements.
|
|
757
|
-
| `CountResult` | `{ count: number }` β the shape returned by batch operations.
|
|
758
|
-
| `QueryMethodArg<T>` | `{ args?: T, db? }` β positional SQL parameters (`$1`, `$2`, ...) and transaction client for `@QueryMethod`.
|
|
759
|
-
| `QueryArgs<T, O>` | Types the spread parameter list of a `@QueryMethod` declared with `{ spreadArgs: true }`: `T`'s values in order, followed by an optional trailing `DbArg<O>` built via `withDb()`.
|
|
760
|
-
| `KeysOfType<T, K>` | Extracts the keys of `T` whose value type is assignable to `K`.
|
|
761
|
-
| `NumericKeys<T>` | Extracts the keys of `T` whose (non-nullable) value type is assignable to `NumericLike`. Nullable numeric fields (`number \| null`) are included.
|
|
762
|
-
| `NumericLike` | `number \| bigint \| DecimalLike`.
|
|
763
|
-
| `DecimalLike` | Structural shape of an arbitrary-precision decimal value (`{ toNumber(): number; decimalPlaces(): number }`), matching e.g. Prisma's `Prisma.Decimal` without importing it directly.
|
|
764
|
-
| `Primitive` | Union of scalar types (`string \| number \| boolean \| bigint \| symbol \| undefined \| null \| Date`) treated as leaves β not relations β when walking an entity's shape.
|
|
765
|
-
| `VSRepoWhere<T>` | ORM-agnostic filter type accepted by `*Where` dynamic methods (e.g. `findWhere`, `findOneWhere`, `updateWhere`). Supports field filters, logical operators (`AND`/`OR`/`NOT`), and relation filters.
|
|
749
|
+
| Type | Description | Used by |
|
|
750
|
+
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
751
|
+
| `MethodOptions<T, K>` | Options accepted as the last argument by all dynamic methods and most base methods: `select`, `relations`, `see`, `db`. | [Base methods](#base-methods), [Dynamic methods](#dynamic-methods). |
|
|
752
|
+
| `RestrictMethodOptions<T, K>` | Narrowed `MethodOptions<T, K>` exposing only `see`/`db` β used by methods that don't shape/return an `Entity` (`total`, `has`, `sum`, `average`, `min`, `max`, `removeList`, `softRemoveList`, `restoreList`). | [Base methods](#base-methods), [Atomic and aggregate methods](#atomic-and-aggregate-methods). |
|
|
753
|
+
| `Pagination` | `{ limit?, offset? }` accepted by `getAll` and by `Paginated` dynamic methods. | [Base methods](#base-methods), [Ordering, pagination and distinct](#ordering-pagination-and-distinct). |
|
|
754
|
+
| `Ordering<T>` / `OrderByField<T>` / `SortDirection` | Ordering shape accepted by `getAll`, `defaultOrdering` and `injectOrdering`, and by `Ordered` dynamic methods. A single object or a chained array; nested objects order to-one relations. | [Constructor options](#constructor-options), [Decorator options](#decorator-options), [Ordering, pagination and distinct](#ordering-pagination-and-distinct). |
|
|
755
|
+
| `SeeMode` | `"active" \| "removed" \| "all"` β controls visibility of soft-deleted records. | [Soft-delete](#soft-delete). |
|
|
756
|
+
| `DeepPartial<T>` | Recursively makes every property of `T` optional, including nested objects and array elements. | `save`, `saveList`, `patch`, `merge`, and all the dynamic writing methods. |
|
|
757
|
+
| `CountResult` | `{ count: number }` β the shape returned by batch operations. | `removeList`, `softRemoveList`, `restoreList`, `createManyIgnoreConflicts`. |
|
|
758
|
+
| `QueryMethodArg<T>` | `{ args?: T, db? }` β positional SQL parameters (the placeholder syntax depends on the database/driver behind your adapter: `$1`, `$2`, ... for PostgreSQL, `?` for MySQL) and transaction client for `@QueryMethod`. | [Query methods (raw SQL)](#query-methods-raw-sql). |
|
|
759
|
+
| `QueryArgs<T, O>` | Types the spread parameter list of a `@QueryMethod` declared with `{ spreadArgs: true }`: `T`'s values in order, followed by an optional trailing `DbArg<O>` built via `withDb()`. | [Spread arguments with `spreadArgs`](#spread-arguments-with-spreadargs). |
|
|
760
|
+
| `KeysOfType<T, K>` | Extracts the keys of `T` whose value type is assignable to `K`. | Constrains `pkName` in [Constructor options](#constructor-options) to fields of the entity matching the configured primary-key type. |
|
|
761
|
+
| `NumericKeys<T>` | Extracts the keys of `T` whose (non-nullable) value type is assignable to `NumericLike`. Nullable numeric fields (`number \| null`) are included. | Constrains `field` in [Atomic and aggregate methods](#atomic-and-aggregate-methods) (`increment`, `sum`, etc). |
|
|
762
|
+
| `NumericLike` | `number \| bigint \| DecimalLike`. | [Atomic and aggregate methods](#atomic-and-aggregate-methods). |
|
|
763
|
+
| `DecimalLike` | Structural shape of an arbitrary-precision decimal value (`{ toNumber(): number; decimalPlaces(): number }`), matching e.g. Prisma's `Prisma.Decimal` without importing it directly. | [Which fields are eligible](#which-fields-are-eligible). |
|
|
764
|
+
| `Primitive` | Union of scalar types (`string \| number \| boolean \| bigint \| symbol \| undefined \| null \| Date \| DecimalLike`) treated as leaves β not relations β when walking an entity's shape. | Used by `Ordering<T>` to tell scalar fields apart from relation fields. |
|
|
765
|
+
| `VSRepoWhere<T>` | ORM-agnostic filter type accepted by `*Where` dynamic methods (e.g. `findWhere`, `findOneWhere`, `updateWhere`). Supports field filters, logical operators (`AND`/`OR`/`NOT`), and relation filters. | [`findWhere`, `findOneWhere` and other `*Where` prefixes](#available-prefixes). |
|
|
766
766
|
| `VSRepoOrmTypes` | `{ dbClient; dbTransaction }` β describes your ORM's client/transaction types. Passed as the third generic to `VSRepository<Entity, PKType, OrmTypes>` to type `getDbClient()`, `transaction()` and the `db` option instead of `any`. | [Creating a repository](#creating-a-repository). |
|
|
767
|
-
| `VSRepoTransactionOptions` | `{ isolationLevel?, timeoutMs? }` β options accepted as the second argument of `transaction()`.
|
|
768
|
-
| `TransactionIsolationLevel` | Enum of standard SQL isolation levels (`READ_UNCOMMITTED`, `READ_COMMITTED`, `REPEATABLE_READ`, `SERIALIZABLE`) accepted by `VSRepoTransactionOptions.isolationLevel`.
|
|
767
|
+
| `VSRepoTransactionOptions` | `{ isolationLevel?, timeoutMs? }` β options accepted as the second argument of `transaction()`. | [Transactions](#transactions). |
|
|
768
|
+
| `TransactionIsolationLevel` | Enum of standard SQL isolation levels (`READ_UNCOMMITTED`, `READ_COMMITTED`, `REPEATABLE_READ`, `SERIALIZABLE`) accepted by `VSRepoTransactionOptions.isolationLevel`. | [Transactions](#transactions). |
|
|
769
769
|
|
|
770
770
|
### `DeepPartial<T>`
|
|
771
771
|
|
|
@@ -944,13 +944,13 @@ export class MyOrmAdapter<T> extends VSRepoAdapter<T> {
|
|
|
944
944
|
}
|
|
945
945
|
```
|
|
946
946
|
|
|
947
|
-
| Method
|
|
948
|
-
|
|
|
949
|
-
| `new VSLogger(logLevel, name, slowThresholdMs?)`
|
|
950
|
-
| `logDebug/logInfo/logWarn(text, obj?)`
|
|
951
|
-
| `logError(text, err?)`
|
|
952
|
-
| `startPerformLog(operation)` / `endPerformLog(data)` | Bracket a block to log its duration, escalating to `WARN` if it exceeds `slowThresholdMs`.
|
|
953
|
-
| `getLogLevel()`
|
|
947
|
+
| Method | Description |
|
|
948
|
+
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
949
|
+
| `new VSLogger(logLevel, name, slowThresholdMs?)` | Creates a logger; `name` prefixes every line. `slowThresholdMs` controls the slow-operation threshold: a `number` sets it in ms (default 300), `false` disables slow-operation warnings entirely, `true` or omitted uses the 300ms default. |
|
|
950
|
+
| `logDebug/logInfo/logWarn(text, obj?)` | Logs at the given level if `logLevel` allows it; `obj` is appended as pretty-printed JSON. |
|
|
951
|
+
| `logError(text, err?)` | Logs at `ERROR`; if `err` is an `Error`, only `name`/`message`/`stack`/`cause` are logged. |
|
|
952
|
+
| `startPerformLog(operation)` / `endPerformLog(data)` | Bracket a block to log its duration, escalating to `WARN` if it exceeds `slowThresholdMs`. |
|
|
953
|
+
| `getLogLevel()` | Returns the logger's configured `VSLogLevel`. |
|
|
954
954
|
|
|
955
955
|
This is purely a convenience for adapter authors β nothing in the core requires your adapter to use it.
|
|
956
956
|
|
|
@@ -976,7 +976,7 @@ try {
|
|
|
976
976
|
| ----------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
977
977
|
| `DECORATOR` | Invalid arguments were passed to `@DynamicMethod` or `@QueryMethod`. |
|
|
978
978
|
| `RESOLVER` | The library failed to resolve a dynamic/query method's configuration into a callable method (e.g. an unknown method name). |
|
|
979
|
-
| `DYNAMIC` | A resolved dynamic/query method failed at runtime (e.g. missing arguments).
|
|
979
|
+
| `DYNAMIC` | A resolved dynamic/query method failed at runtime (e.g. missing arguments). |
|
|
980
980
|
| `VALIDATOR` | Invalid method options or arguments were detected during validation. |
|
|
981
981
|
| `BASE` | Invalid usage of a base method (`get`, `save`, `remove`, etc). |
|
|
982
982
|
| `ADAPTER` | A `VSRepoAdapter` failed while talking to the underlying ORM/database β always thrown as `VSRepoAdapterError`. |
|
|
@@ -1034,6 +1034,7 @@ console.log(AdapterErrorCode.UNIQUE_CONSTRAINT_VIOLATION); // "UNIQUE_CONSTRAINT
|
|
|
1034
1034
|
| Code | Meaning |
|
|
1035
1035
|
| ----------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
1036
1036
|
| `UNKNOWN` | Unclassified/unknown error; the fallback when no more specific code matches. |
|
|
1037
|
+
| `TRANSACTION_ROLLED_BACK` | Some adapters might use this code for forced transaction rollbacks (like Drizzle's `tx.rollback()`) |
|
|
1037
1038
|
| `MISSING_DB_CLIENT` | Database client (or connection pool) not provided or could not be resolved. |
|
|
1038
1039
|
| `CONNECTION_FAILED` | Could not reach/connect to the database, or an established connection was lost/terminated. |
|
|
1039
1040
|
| `CONNECTION_POOL_EXHAUSTED` | Connection pool exhausted/depleted β no connection available, all busy or the limit was reached. |
|
|
@@ -1084,7 +1085,8 @@ super({
|
|
|
1084
1085
|
pkName: "id",
|
|
1085
1086
|
adapter,
|
|
1086
1087
|
logLevel: VSLogLevel.DEBUG,
|
|
1087
|
-
logSlowThresholdMs: 200,
|
|
1088
|
+
logSlowThresholdMs: 200, // warn if any operation takes > 200ms
|
|
1089
|
+
// logSlowThresholdMs: false, // disable slow-operation warnings entirely
|
|
1088
1090
|
});
|
|
1089
1091
|
```
|
|
1090
1092
|
|
|
@@ -1146,11 +1148,11 @@ Notes:
|
|
|
1146
1148
|
|
|
1147
1149
|
## Contributing
|
|
1148
1150
|
|
|
1149
|
-
Contributions are welcome, especially
|
|
1151
|
+
Contributions are welcome, especially for improving the Prisma adapter and finishing the Drizzle one! (**[GitHub repository](https://github.com/jaobrabo123/VSRepository)**):
|
|
1150
1152
|
|
|
1151
1153
|
1. **Fork** the project.
|
|
1152
|
-
2. Create a branch
|
|
1154
|
+
2. Create a branch for your change: `git checkout -b v2-my-change`.
|
|
1153
1155
|
3. Push your branch: `git push origin v2-my-change`.
|
|
1154
|
-
4. Open a **Pull Request
|
|
1156
|
+
4. Open a **Pull Request**.
|
|
1155
1157
|
|
|
1156
1158
|
To report issues or suggest features, open an **Issue**.
|