@decaf-ts/core 0.8.51 → 0.8.52
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 +206 -93
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/lib/esm/fs/FilesystemAdapter.d.ts +67 -0
- package/lib/esm/fs/FilesystemAdapter.js +430 -0
- package/lib/esm/fs/FilesystemAdapter.js.map +1 -0
- package/lib/esm/fs/FsDispatch.d.ts +7 -0
- package/lib/esm/fs/FsDispatch.js +20 -0
- package/lib/esm/fs/FsDispatch.js.map +1 -0
- package/lib/esm/fs/helpers.d.ts +17 -0
- package/lib/esm/fs/helpers.js +64 -0
- package/lib/esm/fs/helpers.js.map +1 -0
- package/lib/esm/fs/index.d.ts +4 -0
- package/lib/esm/fs/index.js +5 -0
- package/lib/esm/fs/index.js.map +1 -0
- package/lib/esm/fs/indexStore.d.ts +28 -0
- package/lib/esm/fs/indexStore.js +173 -0
- package/lib/esm/fs/indexStore.js.map +1 -0
- package/lib/esm/fs/locks/FilesystemLock.d.ts +13 -0
- package/lib/esm/fs/locks/FilesystemLock.js +49 -0
- package/lib/esm/fs/locks/FilesystemLock.js.map +1 -0
- package/lib/esm/fs/locks/FilesystemMultiLock.d.ts +8 -0
- package/lib/esm/fs/locks/FilesystemMultiLock.js +23 -0
- package/lib/esm/fs/locks/FilesystemMultiLock.js.map +1 -0
- package/lib/esm/fs/types.d.ts +34 -0
- package/lib/esm/fs/types.js +2 -0
- package/lib/esm/fs/types.js.map +1 -0
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/ram/RamAdapter.d.ts +1 -1
- package/lib/esm/ram/types.d.ts +2 -1
- package/lib/esm/tasks/TaskEngine.d.ts +30 -1
- package/lib/esm/tasks/TaskEngine.js +361 -16
- package/lib/esm/tasks/TaskEngine.js.map +1 -1
- package/lib/esm/tasks/TaskService.js +3 -0
- package/lib/esm/tasks/TaskService.js.map +1 -1
- package/lib/esm/tasks/builder.js +1 -1
- package/lib/esm/tasks/builder.js.map +1 -1
- package/lib/esm/tasks/constants.js +1 -0
- package/lib/esm/tasks/constants.js.map +1 -1
- package/lib/esm/tasks/types.d.ts +12 -0
- package/lib/esm/tasks/workers/WorkThreadEnvironment.d.ts +32 -0
- package/lib/esm/tasks/workers/WorkThreadEnvironment.js +28 -0
- package/lib/esm/tasks/workers/WorkThreadEnvironment.js.map +1 -0
- package/lib/esm/tasks/workers/messages.d.ts +69 -0
- package/lib/esm/tasks/workers/messages.js +2 -0
- package/lib/esm/tasks/workers/messages.js.map +1 -0
- package/lib/esm/tasks/workers/workerThread.d.ts +1 -0
- package/lib/esm/tasks/workers/workerThread.js +185 -0
- package/lib/esm/tasks/workers/workerThread.js.map +1 -0
- package/lib/fs/FilesystemAdapter.cjs +437 -0
- package/lib/fs/FilesystemAdapter.d.ts +67 -0
- package/lib/fs/FilesystemAdapter.js.map +1 -0
- package/lib/fs/FsDispatch.cjs +24 -0
- package/lib/fs/FsDispatch.d.ts +7 -0
- package/lib/fs/FsDispatch.js.map +1 -0
- package/lib/fs/helpers.cjs +76 -0
- package/lib/fs/helpers.d.ts +17 -0
- package/lib/fs/helpers.js.map +1 -0
- package/lib/fs/index.cjs +21 -0
- package/lib/fs/index.d.ts +4 -0
- package/lib/fs/index.js.map +1 -0
- package/lib/fs/indexStore.cjs +181 -0
- package/lib/fs/indexStore.d.ts +28 -0
- package/lib/fs/indexStore.js.map +1 -0
- package/lib/fs/locks/FilesystemLock.cjs +56 -0
- package/lib/fs/locks/FilesystemLock.d.ts +13 -0
- package/lib/fs/locks/FilesystemLock.js.map +1 -0
- package/lib/fs/locks/FilesystemMultiLock.cjs +30 -0
- package/lib/fs/locks/FilesystemMultiLock.d.ts +8 -0
- package/lib/fs/locks/FilesystemMultiLock.js.map +1 -0
- package/lib/fs/types.cjs +3 -0
- package/lib/fs/types.d.ts +34 -0
- package/lib/fs/types.js.map +1 -0
- package/lib/index.cjs +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/ram/RamAdapter.d.ts +1 -1
- package/lib/ram/types.d.ts +2 -1
- package/lib/tasks/TaskEngine.cjs +360 -15
- package/lib/tasks/TaskEngine.d.ts +30 -1
- package/lib/tasks/TaskEngine.js.map +1 -1
- package/lib/tasks/TaskService.cjs +3 -0
- package/lib/tasks/TaskService.js.map +1 -1
- package/lib/tasks/builder.cjs +1 -1
- package/lib/tasks/builder.js.map +1 -1
- package/lib/tasks/constants.cjs +1 -0
- package/lib/tasks/constants.js.map +1 -1
- package/lib/tasks/types.d.ts +12 -0
- package/lib/tasks/workers/WorkThreadEnvironment.cjs +31 -0
- package/lib/tasks/workers/WorkThreadEnvironment.d.ts +32 -0
- package/lib/tasks/workers/WorkThreadEnvironment.js.map +1 -0
- package/lib/tasks/workers/messages.cjs +3 -0
- package/lib/tasks/workers/messages.d.ts +69 -0
- package/lib/tasks/workers/messages.js.map +1 -0
- package/lib/tasks/workers/workerThread.cjs +220 -0
- package/lib/tasks/workers/workerThread.d.ts +1 -0
- package/lib/tasks/workers/workerThread.js.map +1 -0
- package/package.json +19 -8
package/README.md
CHANGED
|
@@ -39,108 +39,94 @@ Decaf Core provides the foundational building blocks for the Decaf TypeScript ec
|
|
|
39
39
|
|
|
40
40
|
Documentation [here](https://decaf-ts.github.io/injectable-decorators/), Test results [here](https://decaf-ts.github.io/injectable-decorators/workdocs/reports/html/test-report.html) and Coverage [here](https://decaf-ts.github.io/injectable-decorators/workdocs/reports/coverage/lcov-report/index.html)
|
|
41
41
|
|
|
42
|
-
Minimal size:
|
|
42
|
+
Minimal size: 39.4 KB kb gzipped
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
# Core Package — Detailed Description
|
|
46
46
|
|
|
47
|
-
The Decaf Core package provides a cohesive set of primitives for building strongly-typed data-access layers in TypeScript. It centers around:
|
|
47
|
+
The Decaf Core package provides a cohesive set of primitives for building strongly-typed data-access layers and managing background tasks in TypeScript. It centers around:
|
|
48
48
|
|
|
49
|
-
- Models (from @decaf-ts/decorator-validation) enhanced with identity and persistence metadata
|
|
50
|
-
- A Repository abstraction that encapsulates CRUD, querying, and observation
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
49
|
+
- Models (from @decaf-ts/decorator-validation) enhanced with identity and persistence metadata.
|
|
50
|
+
- A Repository abstraction that encapsulates CRUD, querying, and observation.
|
|
51
|
+
- A powerful Task Engine for defining, scheduling, and executing background jobs with support for worker threads.
|
|
52
|
+
- Adapters that bridge repositories to underlying storage (in-memory, HTTP, TypeORM, etc.).
|
|
53
|
+
- A fluent Query DSL (Statement/Condition) with pagination.
|
|
54
|
+
- Lightweight dependency injection utilities to auto-resolve repositories.
|
|
54
55
|
|
|
55
56
|
Below is an overview of the main modules and their public APIs exposed by core.
|
|
56
57
|
|
|
57
|
-
1
|
|
58
|
-
- Repository<M
|
|
59
|
-
- Constructor: new Repository(adapter: Adapter, clazz: Constructor<M>, ...)
|
|
60
|
-
- CRUD: create
|
|
61
|
-
- Bulk ops: createAll
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
## 1. Repository Module
|
|
59
|
+
- **`Repository<M>`**
|
|
60
|
+
- Constructor: `new Repository(adapter: Adapter, clazz: Constructor<M>, ...)`
|
|
61
|
+
- CRUD: `create`, `read`, `update`, `delete`
|
|
62
|
+
- Bulk ops: `createAll`, `readAll`, `updateAll`, `deleteAll`
|
|
63
|
+
- Querying:
|
|
64
|
+
- `select(...selectors?)`: Start a fluent query chain.
|
|
65
|
+
- `query(condition?, orderBy?, order?, limit?, skip?)`: Execute a simple query.
|
|
66
|
+
- **New High-Level Queries:** A set of methods, often used with the `@prepared` decorator, for common query patterns:
|
|
67
|
+
- `find(value, order?)`: Searches default attributes of a model for partial matches (starts-with).
|
|
68
|
+
- `findBy(key, value)`: Finds records by a specific attribute-value pair.
|
|
69
|
+
- `findOneBy(key, value)`: Finds a single record or throws a `NotFoundError`.
|
|
70
|
+
- `listBy(key, order)`: Lists all records ordered by a specific key.
|
|
71
|
+
- `countOf(key?)`: Counts records, optionally for a specific attribute.
|
|
72
|
+
- `maxOf(key)`, `minOf(key)`, `avgOf(key)`, `sumOf(key)`: Perform aggregate calculations.
|
|
73
|
+
- `distinctOf(key)`: Retrieves distinct values for an attribute.
|
|
74
|
+
- `groupOf(key)`: Groups records by a given attribute.
|
|
75
|
+
- `page(value, direction?, ref?)`: Paginates through records matching a default partial-match query.
|
|
76
|
+
- `paginateBy(key, order, ref?)`: Paginates records ordered by a specific key.
|
|
77
|
+
- Observation: `observe(observer, filter?)`, `unObserve(observer)`, `updateObservers(...)`, `refresh(...)`
|
|
78
|
+
- **Statement Execution**:
|
|
79
|
+
- `statement(name, ...args)`: Executes a custom method on the repository decorated with `@prepared`.
|
|
65
80
|
- Repository registry helpers:
|
|
66
|
-
- static for(config, ...args)
|
|
67
|
-
- static forModel(model, alias?, ...args)
|
|
68
|
-
- static
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
-
|
|
104
|
-
|
|
105
|
-
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
- group(cond1, GroupOperator, cond2)
|
|
116
|
-
- builder(): ConditionBuilder
|
|
117
|
-
- ConditionBuilder methods: eq, dif, gt, lt, gte, lte, in, regexp, build
|
|
118
|
-
- Paginator<M>
|
|
119
|
-
- Abstract pagination helper returned by Statement.paginate(size)
|
|
120
|
-
- Properties: current, total, count, size
|
|
121
|
-
- Methods: page(n?), next(), previous(); requires an Adapter-specific concrete implementation
|
|
122
|
-
|
|
123
|
-
4) Interfaces module
|
|
124
|
-
- Observable<T>, Observer<T>: basic observer pattern primitives
|
|
125
|
-
- Executor, RawExecutor: contracts for query execution
|
|
126
|
-
- Queriable: minimal interface for types that can return a Statement
|
|
127
|
-
- Paginatable: marks types that can paginate
|
|
128
|
-
- SequenceOptions and defaults: sequence/generator configuration presets
|
|
129
|
-
|
|
130
|
-
5) Model & Identity modules
|
|
131
|
-
- BaseModel and supporting types: base class all models extend from
|
|
132
|
-
- identity/decorators and identity/utils: helpers to derive table names, etc.
|
|
133
|
-
- model/decorators: e.g., @model and other persistence-related metadata (provided by @decaf-ts/decorator-validation and enriched here)
|
|
134
|
-
|
|
135
|
-
6) RAM runtime (core/src/ram)
|
|
136
|
-
- RamAdapter, RamRepository, RamStatement, RamPaginator (in-memory implementations used by tests and examples)
|
|
137
|
-
- Useful for local testing and reference behavior of the core abstractions.
|
|
138
|
-
|
|
139
|
-
Design intent
|
|
140
|
-
- Provide a consistent, typed data access layer decoupled from any particular storage or framework
|
|
141
|
-
- Allow adapters to plug into multiple backends while preserving a uniform repository and query API
|
|
142
|
-
- Make querying expressive but type-safe through fluent builders and model metadata
|
|
143
|
-
- Enable DI and decorators for ergonomic repository wiring and testing
|
|
81
|
+
- `static for(config, ...args)`: Proxy factory for building repositories with specific adapter config.
|
|
82
|
+
- `static forModel(model, alias?, ...args)`: Returns a Repository instance for a model.
|
|
83
|
+
- `static register(model, repoCtor, alias?)`: Registers a repository for a model.
|
|
84
|
+
|
|
85
|
+
- **Decorators (`repository/decorators`)**
|
|
86
|
+
- `@repository(modelCtor, flavour?)`: Injects a repository instance or registers a repository class.
|
|
87
|
+
- `@prepared()`: Marks a repository method as an executable "prepared statement", allowing it to be called via `repository.statement()`.
|
|
88
|
+
|
|
89
|
+
## 2. Task Engine Module
|
|
90
|
+
A robust system for managing background jobs.
|
|
91
|
+
- **`TaskEngine<A>`**: The core engine that polls for and executes tasks. Manages the task lifecycle, concurrency, and worker threads.
|
|
92
|
+
- **`TaskService<A>`**: A high-level service providing a clean API for interacting with the `TaskEngine`. It's the recommended entry point for managing tasks.
|
|
93
|
+
- `push(task, track?)`: Submits a new task for execution.
|
|
94
|
+
- `schedule(task, track?).for(date)`: Schedules a task to run at a specific time.
|
|
95
|
+
- `track(id)`: Returns a `TaskTracker` to monitor an existing task.
|
|
96
|
+
- **Models**:
|
|
97
|
+
- `TaskModel`: Represents a task, its status (`PENDING`, `RUNNING`, `SUCCEEDED`, `FAILED`), input, and configuration (e.g., `maxAttempts`, `backoff`). Can be `ATOMIC` or `COMPOSITE`.
|
|
98
|
+
- `TaskEventModel`: Logs status changes and progress for a task.
|
|
99
|
+
- **Builders**:
|
|
100
|
+
- `TaskBuilder`: A fluent API for constructing `TaskModel` instances.
|
|
101
|
+
- `CompositeTaskBuilder`: A builder for creating multi-step (`COMPOSITE`) tasks.
|
|
102
|
+
- **Handlers & Tracking**:
|
|
103
|
+
- `ITaskHandler`: The interface to implement for defining the logic of a task. Handlers are registered with the `TaskHandlerRegistry`.
|
|
104
|
+
- `TaskTracker`: An object returned when tracking a task, allowing you to await its completion and receive progress updates.
|
|
105
|
+
- **Worker Threads**: The engine can be configured to run tasks in Node.js `worker_threads`, providing true parallelism and non-blocking execution for CPU-intensive jobs. Configuration is done via the `workerPool` and `workerAdapter` properties in the `TaskEngineConfig`.
|
|
106
|
+
|
|
107
|
+
## 3. Persistence Module
|
|
108
|
+
- **`Adapter<N, Q, R, Ctx>`**: The bridge between a repository and the back-end storage.
|
|
109
|
+
- Handles CRUD operations, raw queries, and model/record transformation (`prepare`/`revert`).
|
|
110
|
+
- Manages different storage "flavours" (e.g., 'ram', 'fs', 'typeorm').
|
|
111
|
+
- **`Sequence`**: Provides identity/sequence generation.
|
|
112
|
+
- **`ObserverHandler`**: Manages observer notifications.
|
|
113
|
+
|
|
114
|
+
## 4. Query Module
|
|
115
|
+
- **`Statement<M>`**: A fluent DSL for building and executing queries.
|
|
116
|
+
- Methods: `select`, `from`, `where`, `orderBy`, `groupBy`, `limit`, `offset`, `execute`, `paginate`.
|
|
117
|
+
- Now includes enhanced logic to "squash" simple queries into efficient prepared statements.
|
|
118
|
+
- **`Condition<M>`**: A composable condition tree for building `where` clauses.
|
|
119
|
+
- **`Paginator<M>`**: An abstract pagination helper.
|
|
120
|
+
- Now includes `serialize()` and `deserialize()` methods to easily pass pagination state.
|
|
121
|
+
|
|
122
|
+
## 5. Model & Identity Modules
|
|
123
|
+
- **`BaseModel`**: The base class all models extend from.
|
|
124
|
+
- Decorators like `@table`, `@pk`, `@column`, `@index`, and relation decorators (`@oneToOne`, `@oneToMany`, `@manyToOne`) are used to define persistence metadata.
|
|
125
|
+
- Includes updated logic for handling complex relations, including `oneToManyOnCreateUpdate` and initial support for `manyToMany`.
|
|
126
|
+
|
|
127
|
+
## 6. RAM & Filesystem Runtimes
|
|
128
|
+
- **`RamAdapter`**: An in-memory adapter, perfect for tests and quick prototyping.
|
|
129
|
+
- **`FilesystemAdapter`**: A `RamAdapter`-compatible adapter that persists data to the local filesystem, enabling data to survive process restarts. Ideal for local development and testing.
|
|
144
130
|
|
|
145
131
|
|
|
146
132
|
# How to Use
|
|
@@ -190,6 +176,47 @@ sequenceDiagram
|
|
|
190
176
|
7. **`createSuffix`**: The `Repository`'s `createSuffix` method is called. This is where you can add logic to be executed after the main `create` operation.
|
|
191
177
|
8. **Decorators (AFTER)**: Any decorators configured to run `AFTER` the `CREATE` operation are executed.
|
|
192
178
|
|
|
179
|
+
### FilesystemAdapter Setup
|
|
180
|
+
|
|
181
|
+
`FilesystemAdapter` (found under `core/src/fs`) extends `RamAdapter` but writes every dataset to disk so repositories survive restarts. You can swap it anywhere you would use `RamAdapter`.
|
|
182
|
+
|
|
183
|
+
**Configuration highlights**
|
|
184
|
+
|
|
185
|
+
- `rootDir`: Base directory where databases live. Each adapter alias becomes its own sub-folder.
|
|
186
|
+
- `jsonSpacing`: Optional pretty-print spacing for the JSON payloads (handy while debugging).
|
|
187
|
+
- `fs`: Custom `fs/promises` implementation — forward your own for tests or sandboxes.
|
|
188
|
+
- `onHydrated(info)`: Callback executed after a table is read from disk; great for metrics or warm-up logs.
|
|
189
|
+
|
|
190
|
+
**Directory layout**
|
|
191
|
+
|
|
192
|
+
- Records -> `{rootDir}/{alias}/{table}/{encodedPk}.json` storing `{ id, record }`.
|
|
193
|
+
- Indexes -> `{rootDir}/{alias}/{table}/indexes/{indexName}.json`, mirroring `@index` metadata so range/aggregate queries stay fast.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import path from "node:path";
|
|
197
|
+
import { FilesystemAdapter, Repository } from "@decaf-ts/core";
|
|
198
|
+
import { User } from "./models/User";
|
|
199
|
+
|
|
200
|
+
const adapter = new FilesystemAdapter(
|
|
201
|
+
{
|
|
202
|
+
rootDir: path.join(process.cwd(), ".decaf-data"),
|
|
203
|
+
jsonSpacing: 2,
|
|
204
|
+
onHydrated: ({ table, records }) => {
|
|
205
|
+
console.info(`Hydrated ${records} ${table} records from disk`);
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
"local-fs"
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
const repo = new Repository(adapter, User);
|
|
212
|
+
await repo.create(new User({ id: "user-1", name: "Persistent" }));
|
|
213
|
+
const reloaded = await repo.read("user-1"); // survives process restarts
|
|
214
|
+
|
|
215
|
+
await adapter.shutdown(); // closes open file handles when the app exits
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
For tests, point `rootDir` at a temporary folder (see `tests/fs/__helpers__/tempFs.ts`) and clean it up after each suite.
|
|
219
|
+
|
|
193
220
|
## Core Decorators
|
|
194
221
|
|
|
195
222
|
The library provides a set of powerful decorators for defining models and their behavior.
|
|
@@ -368,6 +395,92 @@ console.log('Task result:', result);
|
|
|
368
395
|
taskEngine.schedule(task).for(new Date(Date.now() + 5000)); // 5 seconds from now
|
|
369
396
|
```
|
|
370
397
|
|
|
398
|
+
### Worker Threads
|
|
399
|
+
|
|
400
|
+
The Task Engine can be configured to execute tasks in separate worker threads, enabling true parallelism.
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
import { TaskEngine, TaskHandlerRegistry } from '@decaf-ts/core';
|
|
404
|
+
import path from 'path';
|
|
405
|
+
|
|
406
|
+
const taskEngine = new TaskEngine({
|
|
407
|
+
adapter,
|
|
408
|
+
registry,
|
|
409
|
+
workerPool: {
|
|
410
|
+
entry: path.resolve(__dirname, './worker-entry.ts'), // Path to your worker entry file
|
|
411
|
+
size: 4, // Number of worker threads
|
|
412
|
+
},
|
|
413
|
+
workerAdapter: {
|
|
414
|
+
adapterModule: '@decaf-ts/core/fs', // Module to load the adapter from
|
|
415
|
+
adapterClass: 'FilesystemAdapter', // Adapter class name
|
|
416
|
+
adapterArgs: [{ rootDir: './data' }, 'fs-worker'], // Arguments for the adapter constructor
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
await taskEngine.start();
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Advanced Repository Features
|
|
424
|
+
|
|
425
|
+
The `Repository` class now includes several high-level methods for common query patterns, simplifying data access.
|
|
426
|
+
|
|
427
|
+
### Finding Records
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
// Find records by a specific attribute
|
|
431
|
+
const users = await userRepo.findBy('email', 'test@example.com');
|
|
432
|
+
|
|
433
|
+
// Find a single record (throws NotFoundError if not found)
|
|
434
|
+
const user = await userRepo.findOneBy('username', 'jdoe');
|
|
435
|
+
|
|
436
|
+
// List records ordered by a key
|
|
437
|
+
const sortedUsers = await userRepo.listBy('createdAt', OrderDirection.DESC);
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Partial Match Search
|
|
441
|
+
|
|
442
|
+
The `find` and `page` methods support partial matching (starts-with) on default query attributes.
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
// Assuming 'name' and 'email' are default query attributes for User
|
|
446
|
+
// This will find users where name OR email starts with "john"
|
|
447
|
+
const users = await userRepo.find('john');
|
|
448
|
+
|
|
449
|
+
// You can also specify the sort order
|
|
450
|
+
const sortedUsers = await userRepo.find('john', OrderDirection.DESC);
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Aggregations
|
|
454
|
+
|
|
455
|
+
Perform calculations directly on your data:
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
const totalUsers = await userRepo.countOf();
|
|
459
|
+
const activeUsersCount = await userRepo.countOf('isActive'); // Counts where isActive is truthy
|
|
460
|
+
|
|
461
|
+
const maxAge = await userRepo.maxOf('age');
|
|
462
|
+
const minAge = await userRepo.minOf('age');
|
|
463
|
+
const avgAge = await userRepo.avgOf('age');
|
|
464
|
+
const totalAge = await userRepo.sumOf('age');
|
|
465
|
+
|
|
466
|
+
const distinctCities = await userRepo.distinctOf('city');
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Pagination
|
|
470
|
+
|
|
471
|
+
Easily paginate through your data, including partial match searches:
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
// Paginate based on a default query (e.g., all users)
|
|
475
|
+
// This searches for users matching "search term" (partial match) and paginates the results
|
|
476
|
+
const page1 = await userRepo.page('search term', OrderDirection.ASC, { limit: 10, offset: 1 });
|
|
477
|
+
|
|
478
|
+
// Paginate ordered by a specific key without filtering
|
|
479
|
+
const page2 = await userRepo.paginateBy('createdAt', OrderDirection.DESC, { limit: 20, offset: 2 });
|
|
480
|
+
|
|
481
|
+
console.log(`Page ${page1.current} of ${page1.total}`);
|
|
482
|
+
```
|
|
483
|
+
|
|
371
484
|
|
|
372
485
|
### Related
|
|
373
486
|
|