@elysiumjs/mnemosyne 0.1.0 → 0.1.2

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/dist/index.d.ts DELETED
@@ -1,17 +0,0 @@
1
- import type { TenancyConfig } from './tenancy';
2
- export type { ColumnMetadata, DatabaseCacheConfig, DatabaseCacheStrategy, DatabaseDriver, IdType, ModelAdapter, ModelClass, RepositoryClass, RepositoryInterface, TenancyStrategy } from './interfaces';
3
- export { AbstractDatabase, createDatabaseCacheStorage } from './database';
4
- export { createSchemaFromModel, AbstractModel } from './model';
5
- export { AbstractRepository } from './repository';
6
- export { getConfig as getTenancyConfig, getCurrentTenant, withTenant, registerTenancyStrategy, getTenancyStrategy, TenantMiddleware, SimpleTenantMiddleware, StrictTenantMiddleware } from './tenancy';
7
- export type { TenancyConfig, TenancyMode, ModelTenancyConfig } from './tenancy';
8
- export { Cache } from './cache';
9
- export type { CacheInterface } from './cache';
10
- export { KeyvRedis } from './keyv-redis';
11
- export interface MnemosyneConfig<TConnectionConfig = unknown> {
12
- database?: {
13
- default: string;
14
- connections: Record<string, TConnectionConfig>;
15
- };
16
- tenancy?: TenancyConfig;
17
- }
package/dist/index.js DELETED
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{Application as P,Service as G}from"@elysiumjs/core";import{createCache as E}from"cache-manager";import{KeyvCacheableMemory as N}from"cacheable";import{Keyv as F}from"keyv";import{alphabetical as A}from"radash";import{EventEmitter as K}from"events";import{Event as C,Redis as w}from"@elysiumjs/core";class J extends K{#D;#g;#L="::";#I=1000;#R=!0;#O=!1;#W;constructor(g){super();C.once("elysium:app:launched",()=>{this.#D=w.getConnection(g.connection)}),this.#W=g.connection,this.#g=g.namespace,this.#L=g.keyPrefixSeparator??"::",this.#I=g.clearBatchSize??1000,this.#R=g.useUnlink??!0,this.#O=g.noNamespaceAffectsAll??!1,this.on("error",(L)=>{C.emit("elysium:error",L)})}get client(){return this.#D}get opts(){return{namespace:this.#g,keyPrefixSeparator:this.#L,clearBatchSize:this.#I,noNamespaceAffectsAll:this.#O,dialect:"redis",url:this.#W}}get namespace(){return this.#g}set namespace(g){this.#g=g}async get(g){g=this.createKeyPrefix(g,this.#g);let L=await this.client.get(g);return L===null?void 0:L}async set(g,L,D){if(g=this.createKeyPrefix(g,this.#g),D)await this.client.set(g,L,"PX",D);else await this.client.set(g,L)}async setMany(g){let L=[];for(let{key:D,value:O,ttl:R}of g){let I=this.createKeyPrefix(D,this.#g);if(R)L.push(this.client.set(I,O,"PX",R));else L.push(this.client.set(I,O))}await Promise.all(L)}async delete(g){return g=this.createKeyPrefix(g,this.#g),await(this.#R?this.client.send("UNLINK",[g]):this.client.del(g))>0}async clear(){try{if(!this.#g&&this.#O){await this.client.send("FLUSHDB",[]);return}let g="0",L=this.#I,D=this.#g?`${this.#g}${this.#L}*`:"*",O=[];do{let R=await this.client.send("SCAN",[g,"MATCH",D,"COUNT",L.toString(),"TYPE","string"]),[I,Y]=R;if(g=I.toString(),Y.length===0)continue;if(!this.#g)Y=Y.filter((q)=>!q.includes(this.#L));O.push(Y.map((q)=>this.client.del(q)))}while(g!=="0");await Promise.all(O)}catch(g){this.emit("error",g)}}async has(g){return g=this.createKeyPrefix(g,this.#g),this.client.exists(g)}async hasMany(g){let L=[];for(let D of g){let O=this.createKeyPrefix(D,this.#g);L.push(this.client.exists(O))}return Promise.all(L)}async getMany(g){if(g.length===0)return[];return g=g.map((D)=>this.createKeyPrefix(D,this.#g)),await this.client.mget(...g)}async disconnect(){this.client.close()}async deleteMany(g){let L=!1,D=[];for(let R of g){let I=this.createKeyPrefix(R,this.#g);if(this.#R)D.push(this.client.send("UNLINK",[I]));else D.push(this.client.del(I))}let O=await Promise.all(D);for(let R of O)if(typeof R==="number"&&R>0)L=!0;return L}async*iterator(g){let L=g?`${g}${this.#L}*`:"*",D="0";do{let O=await this.client.send("SCAN",[D,"MATCH",L,"TYPE","string"]),[R,I]=O;if(D=R.toString(),!g&&!this.#O)I=I.filter((Y)=>!Y.includes(this.#L));if(I.length>0){let Y=await this.client.mget(...I);for(let q of I.keys()){let j=this.getKeyWithoutPrefix(I[q],g),f=Y[q];yield[j,f]}}}while(D!=="0")}createKeyPrefix(g,L){return L?`${L}${this.#L}${g}`:g}getKeyWithoutPrefix(g,L){return L?g.replace(`${L}${this.#L}`,""):g}}var U=(g)=>{let L=E({stores:[new F({store:g,namespace:"cache"})]}),D=new Map;return{...L,tags(...O){let R=`cache__${A(O,(Y)=>Y).join("__")}`,I=D.get(R);if(!I)I=E({stores:[new F({store:g,namespace:R})]}),D.set(R,I);return I}}};class V{static#D;static#g;static weak=Object.seal({map:new WeakMap,get(g){if(!this.map.has(g))this.map.set(g,{});return this.map.get(g)},del(g){this.map.delete(g)}});static get redis(){if(!V.#D)V.#D=U(new J({connection:"cache"}));return V.#D}static get memory(){if(!V.#g)V.#g=U(new N({ttl:60000,lruSize:5000}));return V.#g}}var S=(g)=>{return V[g.storage??"redis"].tags("database")};class B{getConnectionName(g){return`db.connection.${g}`}getConnection(g="default"){if(g==="default"){let D=P.context.getStore()?.get("db:tx");if(D)return D}let L=this.getConnectionName(g);if(!G.exists(L))console.error(`No connection with name ${g} found. Please make sure to register the connection before using it.`),process.exit(1);return G.get(L)}registerConnection(g,L){let D=this.getConnectionName(g);if(G.exists(D))console.error(`A connection with the name ${g} has already been registered.`),process.exit(1);let O=this.driver.createConnection(L);return G.instance(D,O)}connectionExists(g){return G.exists(this.getConnectionName(g))}getDefaultConnection(){return this.getConnection("default")}setDefaultConnection(g){let L=this.getConnectionName("default");return G.remove(L),G.instance(L,this.getConnection(g))}getRawClient(g="default"){return this.driver.getRawClient(this.getConnection(g))}}import{Application as M}from"@elysiumjs/core";import{t as W}from"elysia";import{Application as H,Middleware as b}from"@elysiumjs/core";var _=null,x=()=>{let g=H.instance;if(!g)return{mode:"schema"};return g.getConfig("elysium:mnemosyne")?.tenancy??{mode:"schema"}},v=(g)=>{_=g},Z=()=>{return _},$=()=>{if(!H.instance||!H.context.getStore)return null;return H.context.getStore()?.get("tenant")??null},d=(g,L)=>{let D=H.context.getStore(),O=new Map(D);return O.set("tenant",g),H.context.run(O,L)};class Q extends b{header="x-tenant-id";allowPublic=!0;connectionName="default";async validateTenant(g){return!0}async onTenantResolved(g,L){}onTenantError(g,L){if(g==="missing")throw Error("Tenant ID required");else throw Error("Invalid tenant")}async onRequest(g){let L=g.request.headers.get(this.header);if(!L||L==="public"){if(this.allowPublic){g.tenant="public";return}return this.onTenantError("missing",g)}if(!await this.validateTenant(L))return this.onTenantError("invalid",g);g.tenant=L,await this.onTenantResolved(L,g)}}class T extends Q{}class z extends Q{allowPublic=!1}var X=(g,{mode:L="select"}={})=>{if(g===void 0||g.length===0)return W.Object({});let D={};for(let O of g){if(["create","update"].includes(L)&&O.isPrimaryKey)continue;if(D[O.name]=h(O),O.nullable)D[O.name]=W.Nullable(D[O.name]);if(L==="update"||O.hasDefault||O.nullable)D[O.name]=W.Optional(D[O.name])}return W.Object(D)},h=(g)=>{switch(g.dataType){case"string":return W.String();case"uuid":return W.String({format:"uuid"});case"number":return W.Number();case"boolean":return W.Boolean();case"array":return W.Array(W.Any());case"json":return W.Object({});case"date":return W.Transform(W.String({format:"date"})).Decode((L)=>new Date(L)).Encode((L)=>L.toISOString());case"datetime":return W.Transform(W.String({format:"date-time"})).Decode((L)=>new Date(L)).Encode((L)=>L.toISOString());case"bigint":return W.BigInt();case"buffer":return W.File();default:return W.Never()}},i=(g,L,D,O)=>{let R=D.getColumns(O);class I{static $inferSelect=void 0;static $inferInsert=void 0;static $inferUpdate=void 0;static get table(){if(!M.instance||!M.context.getStore)return O;if(this.supportTenancy){let Y=$()??"public";if(Y!=="public"){let q=Z();if(q)return q.resolveTable(O,Y);return D.createTenantTable(O,Y)}}return O}static tableName=g;static columns=L;static insertSchema=X(R,{mode:"create"});static updateSchema=X(R,{mode:"update"});static selectSchema=X(R,{mode:"select"});static supportTenancy=!1}return I};var u=(g,L)=>{class D{static Model=g;static connection="default";get db(){return L.getConnection(this.constructor.connection)}}return D};export{d as withTenant,v as registerTenancyStrategy,Z as getTenancyStrategy,x as getTenancyConfig,$ as getCurrentTenant,X as createSchemaFromModel,S as createDatabaseCacheStorage,Q as TenantMiddleware,z as StrictTenantMiddleware,T as SimpleTenantMiddleware,J as KeyvRedis,V as Cache,u as AbstractRepository,i as AbstractModel,B as AbstractDatabase};
@@ -1,350 +0,0 @@
1
- import type { TSchema } from 'elysia';
2
- /**
3
- * Contract for ORM drivers.
4
- *
5
- * A database driver is responsible for creating connections, managing
6
- * transactions, and exposing the raw underlying client.
7
- *
8
- * @author Axel Nana <axel.nana@workbud.com>
9
- * @template TConnection The connection type managed by the driver.
10
- * @template TConnectionConfig The configuration used to create a connection.
11
- */
12
- export interface DatabaseDriver<TConnection = unknown, TConnectionConfig = unknown> {
13
- /**
14
- * Creates a new database connection from the given configuration.
15
- * @param config The connection configuration.
16
- * @returns A new database connection.
17
- */
18
- createConnection(config: TConnectionConfig): TConnection;
19
- /**
20
- * Executes a callback within a database transaction.
21
- * @param connection The connection to use for the transaction.
22
- * @param callback The function to execute within the transaction.
23
- * @returns The return value of the callback.
24
- */
25
- withTransaction<T>(connection: TConnection, callback: (tx: TConnection) => Promise<T>): Promise<T>;
26
- /**
27
- * Returns the raw underlying client from a connection.
28
- * @param connection The connection to extract the raw client from.
29
- * @returns The raw client instance.
30
- */
31
- getRawClient(connection: TConnection): unknown;
32
- }
33
- /**
34
- * Normalized column metadata for a table.
35
- *
36
- * Provides an ORM-agnostic description of a column's name, type,
37
- * nullability, default status, and primary key status.
38
- *
39
- * @author Axel Nana <axel.nana@workbud.com>
40
- */
41
- export interface ColumnMetadata {
42
- /**
43
- * The column name.
44
- */
45
- name: string;
46
- /**
47
- * The normalized data type of the column.
48
- */
49
- dataType: 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'json' | 'array' | 'bigint' | 'buffer' | 'uuid';
50
- /**
51
- * Whether the column allows `NULL` values.
52
- */
53
- nullable: boolean;
54
- /**
55
- * Whether the column has a default value.
56
- */
57
- hasDefault: boolean;
58
- /**
59
- * Whether the column is a primary key.
60
- */
61
- isPrimaryKey: boolean;
62
- }
63
- /**
64
- * Bridges ORM-specific table schemas to framework metadata.
65
- *
66
- * A model adapter translates between the ORM's internal table
67
- * representation and the normalized metadata used by the framework.
68
- *
69
- * @author Axel Nana <axel.nana@workbud.com>
70
- * @template TTable The ORM-specific table type.
71
- */
72
- export interface ModelAdapter<TTable = unknown> {
73
- /**
74
- * Returns the name of the given table.
75
- * @param table The table to get the name of.
76
- * @returns The table name.
77
- */
78
- getTableName(table: TTable): string;
79
- /**
80
- * Returns the normalized column metadata for the given table.
81
- * @param table The table to extract columns from.
82
- * @returns An array of column metadata.
83
- */
84
- getColumns(table: TTable): ColumnMetadata[];
85
- /**
86
- * Creates a tenant-scoped copy of the given table.
87
- * @param table The original table.
88
- * @param tenant The tenant identifier.
89
- * @returns A new table scoped to the given tenant.
90
- */
91
- createTenantTable(table: TTable, tenant: string): TTable;
92
- }
93
- /**
94
- * Contract for tenancy strategies.
95
- *
96
- * A tenancy strategy determines how tables and connections are
97
- * scoped to a specific tenant.
98
- *
99
- * @author Axel Nana <axel.nana@workbud.com>
100
- * @template TTable The ORM-specific table type.
101
- * @template TConnection The connection type used by the strategy.
102
- */
103
- export interface TenancyStrategy<TTable = unknown, TConnection = unknown> {
104
- /**
105
- * The tenancy mode identifier (e.g. `'schema'`, `'rls'`).
106
- */
107
- readonly mode: string;
108
- /**
109
- * Resolves a table to its tenant-scoped equivalent.
110
- * @param table The original table.
111
- * @param tenant The tenant identifier.
112
- * @returns The tenant-scoped table.
113
- */
114
- resolveTable(table: TTable, tenant: string): TTable;
115
- /**
116
- * Executes a callback with tenant-level isolation applied to the connection.
117
- * @param connection The database connection.
118
- * @param tenant The tenant identifier.
119
- * @param callback The function to execute within the isolated context.
120
- * @returns The return value of the callback.
121
- */
122
- withIsolation<T>(connection: TConnection, tenant: string, callback: () => Promise<T>): Promise<T>;
123
- }
124
- /**
125
- * Contract for database query cache strategies.
126
- *
127
- * Implementations are responsible for storing, retrieving, and
128
- * invalidating cached query results.
129
- *
130
- * @author Axel Nana <axel.nana@workbud.com>
131
- */
132
- export interface DatabaseCacheStrategy {
133
- /**
134
- * Retrieves a cached query result by key.
135
- * @param key The cache key.
136
- * @returns The cached result, or `undefined` if not found.
137
- */
138
- get(key: string): Promise<unknown[] | undefined>;
139
- /**
140
- * Stores a query result in the cache.
141
- * @param key The cache key.
142
- * @param response The query result to cache.
143
- * @param tables The tables involved in the query.
144
- * @param config Optional cache configuration.
145
- */
146
- put(key: string, response: unknown[], tables: string[], config?: {
147
- ttl?: number;
148
- }): Promise<void>;
149
- /**
150
- * Invalidates cached entries affected by a mutation.
151
- * @param params The tables and/or tags affected by the mutation.
152
- */
153
- onMutate(params: {
154
- tables?: string[];
155
- tags?: string[];
156
- }): Promise<void>;
157
- }
158
- /**
159
- * Configuration for database query caching.
160
- * @author Axel Nana <axel.nana@workbud.com>
161
- */
162
- export interface DatabaseCacheConfig {
163
- /**
164
- * Whether caching is enabled.
165
- */
166
- enabled?: boolean;
167
- /**
168
- * The default TTL for cached data, in seconds.
169
- */
170
- ttl?: number;
171
- /**
172
- * The caching strategy.
173
- * - `'explicit'`: Only cache queries that explicitly opt in.
174
- * - `'all'`: Cache all queries automatically.
175
- */
176
- strategy?: 'explicit' | 'all';
177
- /**
178
- * The storage engine to use for the cache.
179
- */
180
- storage?: 'redis' | 'memory';
181
- }
182
- /**
183
- * Database primary column type.
184
- * @author Axel Nana <axel.nana@workbud.com>
185
- */
186
- export type IdType = number | string;
187
- /**
188
- * ORM-agnostic CRUD repository contract.
189
- *
190
- * Provides a standard interface for common database operations
191
- * regardless of the underlying ORM implementation.
192
- *
193
- * @author Axel Nana <axel.nana@workbud.com>
194
- * @template TSelect The type returned by select queries.
195
- * @template TInsert The type needed by insert queries.
196
- * @template TUpdate The type needed by update queries.
197
- * @template TId The primary key type.
198
- */
199
- export interface RepositoryInterface<TSelect, TInsert, TUpdate, TId extends IdType = string> {
200
- /**
201
- * Retrieves all the records in the database.
202
- * @returns All the records in the database.
203
- */
204
- all(): Promise<TSelect[]>;
205
- /**
206
- * Retrieves a paginated subset of the records in the database.
207
- * @param count The number of records per page.
208
- * @param page The page number to retrieve.
209
- * @returns A paginated response containing the records and the total count.
210
- */
211
- paginate(count: number, page: number): Promise<{
212
- page: number;
213
- data: TSelect[];
214
- total: number;
215
- }>;
216
- /**
217
- * Retrieves a record by its id.
218
- * @param id The id of the record to retrieve.
219
- * @returns The record with the given id, or `null` if not found.
220
- */
221
- find(id: TId): Promise<TSelect | null>;
222
- /**
223
- * Finds the first record with a column matching the given value.
224
- * @param column The column to filter by.
225
- * @param value The value the column should match.
226
- * @returns The first record with a column matching the given value, or `null`.
227
- */
228
- findBy<TKey extends keyof TSelect>(column: TKey, value: TSelect[TKey]): Promise<TSelect | null>;
229
- /**
230
- * Inserts a new record in the database.
231
- * @param data The data to insert.
232
- * @returns The inserted record.
233
- */
234
- insert(data: TInsert): Promise<TSelect>;
235
- /**
236
- * Updates a record in the database.
237
- * @param id The id of the record to update.
238
- * @param data The data to update.
239
- * @returns The updated record.
240
- */
241
- update(id: TId, data: TUpdate): Promise<TSelect>;
242
- /**
243
- * Updates all the records in the database.
244
- * @param data The data to update.
245
- * @returns The updated records.
246
- */
247
- updateAll(data: TUpdate): Promise<TSelect[]>;
248
- /**
249
- * Deletes a record from the database.
250
- * @param id The ID of the record to delete.
251
- * @returns The deleted record.
252
- */
253
- delete(id: TId): Promise<TSelect>;
254
- /**
255
- * Deletes all the records from the database.
256
- * @returns All the deleted records.
257
- */
258
- deleteAll(): Promise<TSelect[]>;
259
- /**
260
- * Checks if a record exists in the database.
261
- * @param id The ID of the record to check.
262
- * @returns `true` if the record exists, `false` otherwise.
263
- */
264
- exists(id: TId): Promise<boolean>;
265
- }
266
- /**
267
- * Shape of a model class.
268
- *
269
- * Describes the static interface that a model class must expose,
270
- * including inferred types, table metadata, and validation schemas.
271
- *
272
- * @author Axel Nana <axel.nana@workbud.com>
273
- * @template TSelect The type returned by select queries.
274
- * @template TInsert The type needed by insert queries.
275
- * @template TUpdate The type needed by update queries.
276
- * @template TTable The ORM-specific table type.
277
- */
278
- export type ModelClass<TSelect = unknown, TInsert = unknown, TUpdate = unknown, TTable = unknown> = {
279
- /**
280
- * The data type returned by select queries.
281
- */
282
- readonly $inferSelect: TSelect;
283
- /**
284
- * The data type needed by insert queries.
285
- */
286
- readonly $inferInsert: TInsert;
287
- /**
288
- * The data type needed by update queries.
289
- */
290
- readonly $inferUpdate: TUpdate;
291
- /**
292
- * The ORM-specific table schema wrapped by this model.
293
- */
294
- readonly table: TTable;
295
- /**
296
- * The name of the table wrapped by the model.
297
- */
298
- readonly tableName: string;
299
- /**
300
- * The table columns configuration.
301
- */
302
- readonly columns: Record<string, unknown>;
303
- /**
304
- * The validation schema for creating records.
305
- */
306
- readonly insertSchema: TSchema;
307
- /**
308
- * The validation schema for updating records.
309
- */
310
- readonly updateSchema: TSchema;
311
- /**
312
- * The validation schema for selecting records.
313
- */
314
- readonly selectSchema: TSchema;
315
- /**
316
- * Whether the model supports tenancy.
317
- */
318
- readonly supportTenancy: boolean;
319
- /**
320
- * Creates a new instance of the model.
321
- * @param args The arguments to pass to the constructor.
322
- * @returns A new instance of the model.
323
- */
324
- new (...args: unknown[]): unknown;
325
- };
326
- /**
327
- * Shape of a repository class.
328
- *
329
- * Describes the static interface that a repository class must expose,
330
- * including the associated model and connection name.
331
- *
332
- * @author Axel Nana <axel.nana@workbud.com>
333
- * @template TModel The model class type wrapped by the repository.
334
- */
335
- export type RepositoryClass<TModel extends ModelClass = ModelClass> = {
336
- /**
337
- * The model class wrapped by this repository.
338
- */
339
- readonly Model: TModel;
340
- /**
341
- * The database connection name to use in the repository.
342
- */
343
- readonly connection: string;
344
- /**
345
- * Creates a new instance of the repository.
346
- * @param args The arguments to pass to the constructor.
347
- * @returns A new repository instance.
348
- */
349
- new (...args: unknown[]): RepositoryInterface<TModel['$inferSelect'], TModel['$inferInsert'], TModel['$inferUpdate']>;
350
- };
@@ -1,84 +0,0 @@
1
- import type { KeyvStoreAdapter } from 'cacheable';
2
- import type { KeyvEntry, StoredData } from 'keyv';
3
- import { EventEmitter } from 'node:events';
4
- /**
5
- * Keyv adapter for redis. This adapter is based on the Bun's Redis client.
6
- * @author Axel Nana <axel.nana@workbud.com>
7
- */
8
- export declare class KeyvRedis extends EventEmitter implements KeyvStoreAdapter {
9
- #private;
10
- constructor(props: {
11
- /**
12
- * The Redis connection to use.
13
- */
14
- connection: string;
15
- /**
16
- * Namespace for the connection.
17
- */
18
- namespace?: string;
19
- /**
20
- * Separator to use between namespace and key.
21
- */
22
- keyPrefixSeparator?: string;
23
- /**
24
- * Number of keys to delete in a single batch.
25
- */
26
- clearBatchSize?: number;
27
- /**
28
- * Enable Unlink instead of using Del for clearing keys. This is more performant but may not be supported by all Redis versions.
29
- */
30
- useUnlink?: boolean;
31
- /**
32
- * Whether to allow clearing all keys when no namespace is set.
33
- * If set to true and no namespace is set, iterate() will return all keys.
34
- * Defaults to `false`.
35
- */
36
- noNamespaceAffectsAll?: boolean;
37
- });
38
- get client(): Bun.RedisClient;
39
- /**
40
- * Get the options for the adapter.
41
- */
42
- get opts(): {
43
- namespace: string | undefined;
44
- keyPrefixSeparator: string;
45
- clearBatchSize: number;
46
- noNamespaceAffectsAll: boolean;
47
- dialect: string;
48
- url: string;
49
- };
50
- /**
51
- * Gets the namespace for the adapter. If undefined, it will not use a namespace including keyPrefixing.
52
- * @default undefined
53
- */
54
- get namespace(): string | undefined;
55
- /**
56
- * Sets the namespace for the adapter. If undefined, it will not use a namespace including keyPrefixing.
57
- */
58
- set namespace(value: string | undefined);
59
- get<Value>(key: string): Promise<StoredData<Value> | undefined>;
60
- set(key: string, value: any, ttl?: number): Promise<void>;
61
- setMany(values: Array<KeyvEntry>): Promise<void>;
62
- delete(key: string): Promise<boolean>;
63
- clear(): Promise<void>;
64
- has(key: string): Promise<boolean>;
65
- hasMany(keys: string[]): Promise<boolean[]>;
66
- getMany<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>>;
67
- disconnect(): Promise<void>;
68
- deleteMany(keys: string[]): Promise<boolean>;
69
- iterator<Value>(namespace?: string): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
70
- /**
71
- * Helper function to create a key with a namespace.
72
- * @param key The key to prefix.
73
- * @param namespace The namespace to prefix the key with.
74
- * @returns The key with the namespace such as 'namespace::key'.
75
- */
76
- createKeyPrefix(key: string, namespace?: string): string;
77
- /**
78
- * Helper function to remove the namespace from a key.
79
- * @param key The key to remove the namespace from.
80
- * @param namespace The namespace to remove from the key.
81
- * @returns The key without the namespace.
82
- */
83
- getKeyWithoutPrefix(key: string, namespace?: string): string;
84
- }
package/dist/model.d.ts DELETED
@@ -1,68 +0,0 @@
1
- import type { ColumnMetadata, ModelAdapter } from './interfaces';
2
- /**
3
- * Creates a validation schema from normalized column metadata.
4
- * @author Axel Nana <axel.nana@workbud.com>
5
- * @param columns The column metadata to create the schema from.
6
- * @param options The schema generation options.
7
- * @returns A validation schema based on the given columns.
8
- */
9
- export declare const createSchemaFromModel: (columns: ColumnMetadata[], { mode }?: {
10
- mode?: "create" | "update" | "select";
11
- }) => import("@sinclair/typebox").TObject<{}>;
12
- /**
13
- * Mixin used to create a new abstract model class.
14
- * @author Axel Nana <axel.nana@workbud.com>
15
- * @template TTable The ORM-specific table type.
16
- * @template TColumns The table columns configuration type.
17
- * @param tableName The name of the table.
18
- * @param columns The table columns configuration.
19
- * @param adapter The model adapter for the ORM.
20
- * @param baseTable The base ORM table instance.
21
- */
22
- export declare const AbstractModel: <TTable, TColumns extends Record<string, unknown>>(tableName: string, columns: TColumns, adapter: ModelAdapter<TTable>, baseTable: TTable) => {
23
- new (): {};
24
- /**
25
- * The data type returned by the select queries.
26
- */
27
- readonly $inferSelect: unknown;
28
- /**
29
- * The data type needed by the insert queries.
30
- */
31
- readonly $inferInsert: unknown;
32
- /**
33
- * The data type needed by the update queries.
34
- */
35
- readonly $inferUpdate: unknown;
36
- /**
37
- * The ORM-specific table schema wrapped by this model.
38
- * Will be automatically resolved to a tenant-scoped table when tenancy is active.
39
- */
40
- get table(): TTable;
41
- /**
42
- * The name of the table wrapped by the model.
43
- */
44
- readonly tableName: string;
45
- /**
46
- * The table columns configuration.
47
- */
48
- readonly columns: TColumns;
49
- /**
50
- * The validation schema for creating records.
51
- */
52
- readonly insertSchema: import("@sinclair/typebox").TObject<{}>;
53
- /**
54
- * The validation schema for updating records.
55
- */
56
- readonly updateSchema: import("@sinclair/typebox").TObject<{}>;
57
- /**
58
- * The validation schema for selecting records.
59
- */
60
- readonly selectSchema: import("@sinclair/typebox").TObject<{}>;
61
- /**
62
- * Whether the model supports tenancy.
63
- *
64
- * Set it to `true` if the model supports tenancy. This means that the model will be
65
- * wrapped by the tenancy strategy when the current tenant is not `public`.
66
- */
67
- readonly supportTenancy: boolean;
68
- };
@@ -1,96 +0,0 @@
1
- import type { AbstractDatabase } from './database';
2
- import type { IdType, ModelClass } from './interfaces';
3
- /**
4
- * Mixin used to create a new abstract repository class over a model.
5
- *
6
- * All CRUD methods are abstract and must be implemented by driver-specific
7
- * subclasses.
8
- *
9
- * @author Axel Nana <axel.nana@workbud.com>
10
- * @template TModel The type of the model class wrapped by the repository.
11
- * @template TConnection The database connection type.
12
- * @param model The model class wrapped by the repository.
13
- * @param database The database manager instance.
14
- */
15
- export declare const AbstractRepository: <TModel extends ModelClass, TConnection>(model: TModel, database: AbstractDatabase<TConnection, unknown>) => (abstract new () => {
16
- /**
17
- * The database connection used by this repository.
18
- */
19
- get db(): TConnection;
20
- /**
21
- * Retrieves all the records in the database.
22
- * @returns All the records in the database.
23
- */
24
- all(): Promise<TModel["$inferSelect"][]>;
25
- /**
26
- * Get a paginated subset of the records in the database.
27
- * @param count The number of records to retrieve per page.
28
- * @param page The page number to retrieve.
29
- * @returns A paginated response containing the records and the total number of records.
30
- */
31
- paginate(count: number, page?: number): Promise<{
32
- page: number;
33
- data: TModel["$inferSelect"][];
34
- total: number;
35
- }>;
36
- /**
37
- * Retrieves a record by its id.
38
- * @param id The id of the record to retrieve.
39
- * @returns The record with the given id, or `null` if not found.
40
- */
41
- find(id: IdType): Promise<TModel["$inferSelect"] | null>;
42
- /**
43
- * Finds the first record with a column matching the given value.
44
- * @param column The column to filter by.
45
- * @param value The value the column should match.
46
- * @returns The first record with a column matching the given value.
47
- */
48
- findBy<TKey extends keyof TModel["$inferSelect"]>(column: TKey, value: TModel["$inferSelect"][TKey]): Promise<TModel["$inferSelect"] | null>;
49
- /**
50
- * Inserts a new record in the database.
51
- * @param data The data to insert.
52
- * @returns The inserted record.
53
- */
54
- insert(data: TModel["$inferInsert"]): Promise<TModel["$inferSelect"]>;
55
- /**
56
- * Updates a record in the database.
57
- * @param id The id of the record to update.
58
- * @param data The data to update.
59
- * @returns The updated record.
60
- */
61
- update(id: IdType, data: TModel["$inferUpdate"]): Promise<TModel["$inferSelect"]>;
62
- /**
63
- * Updates all the records in the database.
64
- * @param data The data to update.
65
- * @returns The updated records.
66
- */
67
- updateAll(data: TModel["$inferUpdate"]): Promise<TModel["$inferSelect"][]>;
68
- /**
69
- * Deletes a record from the database.
70
- * @param id The ID of the record to delete.
71
- * @returns The deleted record.
72
- */
73
- delete(id: IdType): Promise<TModel["$inferSelect"]>;
74
- /**
75
- * Deletes all the records from the database.
76
- * @returns All the deleted records.
77
- */
78
- deleteAll(): Promise<TModel["$inferSelect"][]>;
79
- /**
80
- * Checks if a record exists in the database.
81
- * @param id The ID of the record to check.
82
- * @returns True if the record exists, false otherwise.
83
- */
84
- exists(id: IdType): Promise<boolean>;
85
- }) & {
86
- /**
87
- * The model class wrapped by this repository.
88
- */
89
- readonly Model: TModel;
90
- /**
91
- * The database connection name to use.
92
- *
93
- * Update this value to change the database connection used by this repository.
94
- */
95
- readonly connection: string;
96
- };