@elysiumjs/mnemosyne-drizzle 0.2.0 → 0.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/CHANGELOG.md +112 -0
- package/dist/cache.d.ts +60 -0
- package/dist/commands/migration_run.command.d.ts +13 -0
- package/dist/commands/project.d.ts +11 -0
- package/dist/database.d.ts +82 -31
- package/dist/driver.d.ts +39 -0
- package/dist/drivers/bun-sql.d.ts +25 -0
- package/dist/drivers/bun-sql.js +1 -0
- package/dist/drivers/hyperdrive.d.ts +46 -0
- package/dist/drivers/hyperdrive.js +1 -0
- package/dist/drivers/node-postgres.d.ts +23 -0
- package/dist/drivers/node-postgres.js +1 -0
- package/dist/drivers/postgres-js.d.ts +25 -0
- package/dist/drivers/postgres-js.js +1 -0
- package/dist/drizzle.module.d.ts +3 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +11 -1
- package/dist/migrations.d.ts +12 -0
- package/dist/model.d.ts +9 -9
- package/dist/query.d.ts +28 -0
- package/dist/repository.d.ts +34 -6
- package/dist/tenancy.d.ts +25 -8
- package/package.json +63 -11
- package/.omc/state/agent-replay-3920b579-6d8e-4f5f-924a-319202936685.jsonl +0 -7
- package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/last-tool-error-state.json +0 -7
- package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/mission-state.json +0 -93
- package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/pre-tool-advisory-throttle.json +0 -18
- package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/subagent-tracking-state.json +0 -61
- package/.turbo/turbo-build.log +0 -3
- package/dist/commands/migration_generate.command.js +0 -1
- package/dist/commands/migration_run.command.js +0 -15
- package/dist/database.js +0 -1
- package/dist/drizzle.module.js +0 -1
- package/dist/migrations.js +0 -1
- package/dist/model.js +0 -1
- package/dist/repository.js +0 -1
- package/dist/table.js +0 -1
- package/dist/tenancy.js +0 -1
- package/scripts/minify.ts +0 -10
- package/src/commands/migration_generate.command.ts +0 -101
- package/src/commands/migration_run.command.ts +0 -160
- package/src/database.ts +0 -205
- package/src/drizzle.module.ts +0 -97
- package/src/index.ts +0 -47
- package/src/migrations.ts +0 -100
- package/src/model.ts +0 -178
- package/src/repository.ts +0 -113
- package/src/table.ts +0 -70
- package/src/tenancy.ts +0 -249
- package/tests/drizzle.module.test.ts +0 -201
- package/tests/migrations.test.ts +0 -123
- package/tests/model.test.ts +0 -362
- package/tests/setup.ts +0 -0
- package/tests/table.test.ts +0 -72
- package/tests/tenancy.test.ts +0 -212
- package/tsconfig.json +0 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,117 @@
|
|
|
1
1
|
# @elysiumjs/mnemosyne-drizzle
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#15](https://github.com/na2axl/elysiumjs/pull/15) [`fbcc7da`](https://github.com/na2axl/elysiumjs/commit/fbcc7dad127db29da42e7a4a5c2124966731cd88) Thanks [@na2axl](https://github.com/na2axl)! - Resources, queries, units of work and rate limits.
|
|
8
|
+
|
|
9
|
+
Breaking:
|
|
10
|
+
|
|
11
|
+
- A route with a `response` schema serializes its handler result through it: fields the schema does not declare are dropped, a `Date` becomes an ISO string (`YYYY-MM-DD` for `format: 'date'`), and an object with `toJSON()` becomes what it returns. Set `serialize: false` on a route to send the result as it is.
|
|
12
|
+
|
|
13
|
+
Added:
|
|
14
|
+
|
|
15
|
+
- `Resource.hidden(schema)` marks a field that never reaches responses nor the OpenAPI document. `Resource.serialize()` and `Resource.project()` are exported for use outside routes.
|
|
16
|
+
- Sparse fieldsets: `?fields=id,title` keeps only those fields of an object, of each item of an array, or of each item of a `data` array. An unknown or hidden field answers a 400 problem.
|
|
17
|
+
- Rate limits with `@RateLimit({ window, max, key?, store?, name? })` on routes and controllers (`@RateLimit(false)` turns one off), and a default limit and store in the app's `rateLimit` option, with fixed windows. Responses carry `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and `RateLimit-Policy`; a client over the limit gets a 429 problem with `Retry-After`. Counts are kept by a `RateLimitStore`: `MemoryRateLimitStore` (core), `RedisRateLimitStore` (`@elysiumjs/redis`) or `WorkersRateLimitStore` over a Cloudflare rate limiting binding (`@elysiumjs/runtime-workers`), which only decides whether a hit is over the limit, so its responses carry no `RateLimit-Reset`.
|
|
18
|
+
- `ModelResource(model, { hidden, pick, omit, extend })` (`@elysiumjs/mnemosyne`) builds a response schema from a model.
|
|
19
|
+
- `Query.define(model, spec)` declares the filters (`filter[field][op]=value`), sorts, page size and cursor a list accepts; `Query.schema()` gives its query schema, `Query.parse()` turns a request query into a `ParsedQuery` and answers a 400 problem with a pointer per mistake, and `Query.page()` / `Query.pageSchema()` build cursor pages (`{ data, nextCursor }`).
|
|
20
|
+
- `DrizzleRepository.list(query)` and `count(query)` run a `ParsedQuery` with keyset pagination (`@elysiumjs/mnemosyne-drizzle`), and `compileQuery()` gives its `where` and `orderBy`.
|
|
21
|
+
- Units of work: `UnitOfWork.run()` and the `@Transactional()` method decorator run work in one transaction, and `UnitOfWork.afterCommit()` / `afterRollback()` defer work, such as sending a message, until the outermost transaction has ended. `transactional` routes open a unit of work too.
|
|
22
|
+
|
|
23
|
+
- [#16](https://github.com/na2axl/elysiumjs/pull/16) [`ac96e55`](https://github.com/na2axl/elysiumjs/commit/ac96e55874b0ffe350b287c4278cd85afecb7576) Thanks [@na2axl](https://github.com/na2axl)! - Redis, databases, logs, jobs and builds on Bun, Node.js and Cloudflare Workers.
|
|
24
|
+
|
|
25
|
+
Breaking:
|
|
26
|
+
|
|
27
|
+
- The level shortcuts of `InteractsWithConsole` (`info`, `success`, `warning`, `error` and `debug`) write a tag (`[I]`, `[S]`, `[W]`, `[E]` and `[D]`, in color) before the message, which `InteractsWithConsole.useTags()` changes. `trace()` writes to stderr.
|
|
28
|
+
- Outside Bun, a Drizzle connection needs a `driver`. Without one, the `connection` and `client` props are a Bun SQL connection, which is only available on Bun; elsewhere the connection throws `MissingDriverError`, which names the drivers.
|
|
29
|
+
|
|
30
|
+
Added:
|
|
31
|
+
|
|
32
|
+
- Redis adapters (`@elysiumjs/redis`): `ioredis(create)` plugs an ioredis client into the Redis port on Node.js, and `upstash({ token, url?, fetch? })` talks to Upstash over its REST API, for Workers (no pub/sub). `bunRedis` explains which adapter to use when it runs outside Bun.
|
|
33
|
+
- Drizzle drivers (`@elysiumjs/mnemosyne-drizzle`): a `DrizzleDriver` port set with the `driver` prop of a connection, and drivers on subpaths so that only the chosen database client is imported: `/bun-sql` (`bunSql()`), `/postgres-js` (`postgresJs()`), `/node-postgres` (`nodePostgres()`) and `/hyperdrive` (`hyperdrive({ binding, driver })`, a client per Worker invocation over a Cloudflare Hyperdrive binding). `DrizzleModule` closes connections through their driver, and `migration:run` runs on any driver.
|
|
34
|
+
- `InteractsWithConsole.write()` and `Runtime.write()` take the level of the line (`OutputLevel`), which the level shortcuts pass. On Cloudflare Workers, a line is written with the console method of its level, so Workers Logs keep it.
|
|
35
|
+
- `JsonConsoleLogger` (`@elysiumjs/hermes`): JSON lines through the console of the runtime (warnings and errors on stderr), with levels, error serialization and `child()`. `HermesModule.with({ transport: 'console' | 'pino' })` picks it, and it is the default on Workers. `RequestLogInterceptor` writes one structured line per request: method, route, status, duration, client address and request id.
|
|
36
|
+
- Scheduled jobs (`@elysiumjs/heracles`): `@Schedule(cron, { timezone, args })` on a job class, a five-field cron parser (`Cron`, with lists, ranges, steps and names), and a `Scheduler` that dispatches the jobs on time on Bun and Node.js, taking a Redis lock per tick when a Redis connection is set. The `heracles:schedule` command runs it.
|
|
37
|
+
- `@elysiumjs/heracles-workers`: `CloudflareQueueTransport` sends jobs to a Cloudflare Queue (dispatch delays become `delaySeconds`), and `HeraclesWorkersModule` consumes them in the Worker's `queue` handler (ack on success, retry with a delay up to the job's retries) and dispatches the `@Schedule()` jobs whose expression is the cron of a trigger.
|
|
38
|
+
- Queue handlers (`@elysiumjs/runtime-workers`) can settle a message themselves with `ack()` or `retry({ delaySeconds })`; the messages they leave are acked when no handler failed on them.
|
|
39
|
+
- `styx build --target node` (`@elysiumjs/hephaestus`) bundles the app into one ES module for Node.js, with decorator metadata emitted at build time, run with `node dist/server.js serve`. `styx build --target workers` runs from the CLI, resolves packages to their browser entry, and leaves Node.js modules imported by bare names to workerd (`nodejs_compat`).
|
|
40
|
+
- `styx create` (`@elysiumjs/styx`) takes `--runtime bun|node|workers`, `--database`, `--cache` and `--package-manager bun|npm|pnpm`. Each runtime gets its entry, tsconfig types, scripts and drivers: postgres.js and ioredis on Node.js; Hyperdrive, Upstash, console logs and a `wrangler.jsonc` on Workers.
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- [#11](https://github.com/na2axl/elysiumjs/pull/11) [`632d77b`](https://github.com/na2axl/elysiumjs/commit/632d77b561fc43ade605fb69b06ac1b9b9a2ffc4) Thanks [@na2axl](https://github.com/na2axl)! - Services are identified by their class, or by the name given to `@Service.register({ name })`. Class names are never used as identifiers, so services resolve the same way in minified builds; `bun run check:minified` in core bundles a minified app and checks that every service resolves. `@Service.inject()` without an argument injects the class of the parameter type, and throws when the type is unknown. Factory services in a module's `services` take a class or a name in `name`.
|
|
45
|
+
|
|
46
|
+
`ServiceScope.REQUEST` gives one instance per HTTP request, shared by the request's middlewares, controller and handler. `Service.runInRequestScope(fn)` opens a request scope outside a route. Resolving a request-scoped service outside a request throws `OutsideRequestScopeError`, and a singleton (or a server-scoped controller) depending on one throws `ScopeMismatchError`.
|
|
47
|
+
|
|
48
|
+
`HermesModule` registers the logger by the `HermesLogger` class and as `logger`.
|
|
49
|
+
|
|
50
|
+
- Updated dependencies [[`6bc48fe`](https://github.com/na2axl/elysiumjs/commit/6bc48febd51f7090c582e73f349eaeff7261241c), [`e9c3d98`](https://github.com/na2axl/elysiumjs/commit/e9c3d98dd2714b69100215f7c8a80046da463148), [`557a3ca`](https://github.com/na2axl/elysiumjs/commit/557a3cab7af8053a8bab9944e492e5022d91aa82), [`ccc3f5b`](https://github.com/na2axl/elysiumjs/commit/ccc3f5bb904d1bf52d8c72ebf7ea8d10f617a8c4), [`6789879`](https://github.com/na2axl/elysiumjs/commit/678987976ecfd46b534b65276e0de3f448977562), [`87299fd`](https://github.com/na2axl/elysiumjs/commit/87299fd9da82d1a408ced1891c0c3d42991444e5), [`bee66bd`](https://github.com/na2axl/elysiumjs/commit/bee66bdc874b8f23fea356f7d3adf7555a48ca64), [`0057b67`](https://github.com/na2axl/elysiumjs/commit/0057b67df0e3abecab8a9accff6b55a6a64c21df), [`1738567`](https://github.com/na2axl/elysiumjs/commit/17385674c14991f0ddb27eb6ee967afbcebcc307), [`632d77b`](https://github.com/na2axl/elysiumjs/commit/632d77b561fc43ade605fb69b06ac1b9b9a2ffc4), [`1ea417e`](https://github.com/na2axl/elysiumjs/commit/1ea417e3583250bc2f975d795f398b7ff736115d), [`0956186`](https://github.com/na2axl/elysiumjs/commit/0956186db0ca5a83c0a6636aeb2a4c81a0033de4), [`fbcc7da`](https://github.com/na2axl/elysiumjs/commit/fbcc7dad127db29da42e7a4a5c2124966731cd88), [`ac96e55`](https://github.com/na2axl/elysiumjs/commit/ac96e55874b0ffe350b287c4278cd85afecb7576), [`98a16aa`](https://github.com/na2axl/elysiumjs/commit/98a16aae889d46f7a9fb5573188f4cbe3629dd3b)]:
|
|
51
|
+
- @elysiumjs/core@0.11.0
|
|
52
|
+
- @elysiumjs/runtime-workers@0.1.0
|
|
53
|
+
- @elysiumjs/mnemosyne@0.4.0
|
|
54
|
+
|
|
55
|
+
## 0.3.1
|
|
56
|
+
|
|
57
|
+
### Patch Changes
|
|
58
|
+
|
|
59
|
+
- Updated dependencies [[`68a0cdd`](https://github.com/na2axl/elysiumjs/commit/68a0cdd8b2e4a003d6e0af2d78985623cae40428), [`2c49acd`](https://github.com/na2axl/elysiumjs/commit/2c49acd3b552aa43765d70339fa216961499e1b5), [`76ba0ff`](https://github.com/na2axl/elysiumjs/commit/76ba0ff18f3c196cebc2189426328f67cb699f46), [`4ebf029`](https://github.com/na2axl/elysiumjs/commit/4ebf029611e6d753a4f1bfdbe247a75d954d9ded), [`bacce71`](https://github.com/na2axl/elysiumjs/commit/bacce7146f667a1a46bf474dc0344fb0111ae12a)]:
|
|
60
|
+
- @elysiumjs/core@0.10.0
|
|
61
|
+
- @elysiumjs/mnemosyne@0.3.1
|
|
62
|
+
|
|
63
|
+
## 0.3.0
|
|
64
|
+
|
|
65
|
+
### Minor Changes
|
|
66
|
+
|
|
67
|
+
- [`5fef4a7`](https://github.com/na2axl/elysiumjs/commit/5fef4a7199f502fc4fe035299e7670739459a108) Thanks [@na2axl](https://github.com/na2axl)! - Fix tenant isolation, transactions and query caching in the database layer.
|
|
68
|
+
|
|
69
|
+
Breaking changes:
|
|
70
|
+
|
|
71
|
+
- `TenantMiddleware.validateTenant()` now rejects every tenant unless you override it, and tenant identifiers must match `TENANT_ID_PATTERN` (1 to 63 ASCII letters, digits, `_` or `-`, not starting with `pg_` and other than `information_schema`, in any case) before it is called. Requests that send any other tenant now fail with `Invalid tenant`. Requests without a tenant still resolve to `public` on `SimpleTenantMiddleware`. To migrate, check the tenant against your own data:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
class OrganizationMiddleware extends SimpleTenantMiddleware {
|
|
75
|
+
protected async validateTenant(tenant: string): Promise<boolean> {
|
|
76
|
+
return Organization.exists(tenant);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- `getTenantSchema()`, `registerTenantSchema()` and `wrapTenantSchema()` throw on tenant identifiers that do not match `TENANT_ID_PATTERN`.
|
|
82
|
+
- `setConnectionTenant()` is removed. It set the tenant on a pooled connection for the whole session, so the tenant leaked to other requests. Use `withRLS()`, or `Database.transaction()` in RLS mode, which scope the tenant to a transaction.
|
|
83
|
+
- `RepositoryInterface.update()` and `delete()`, and the `DrizzleRepository` implementations, return `null` when no row has the id. They returned `undefined` while typed as a row. `DrizzleRepository` also requires a model whose table has an `id` column.
|
|
84
|
+
- `@transactional` handlers run through the `db.transaction` service that `DrizzleModule` provides (its name is exported by `@elysiumjs/core` as `DATABASE_TRANSACTION_SERVICE`, and still re-exported by `@elysiumjs/mnemosyne`). A transactional handler without a database module now fails with an error naming the service.
|
|
85
|
+
- `@transactional` generator handlers commit only when the whole stream was sent. A stream closed early, or whose client disconnects (even while the handler is waiting), rolls back.
|
|
86
|
+
- In RLS mode, a transaction is bound to one tenant for its whole life: the tenant set (with a transaction-local `set_config`) when `Database.transaction()`, a `@transactional` handler, `withRLS()` or `withIsolation()` opens it, from the explicit tenant or the current one (`public` when there is none). Work that finds a transaction open on its connection (`withRLS()`, `withIsolation()`, `Database.transaction()`, repository calls) joins it only when its tenant is the transaction's tenant, and throws `TenantMismatchError` otherwise, without running anything: the tenant of an open transaction never changes. Inside a transaction, `Database.getConnection()` only returns it to work for its tenant (the current tenant, or `public`), and throws `TenantMismatchError` otherwise, so raw queries never run for another tenant; queries on the `tx` handle a callback received run as the transaction's tenant. Work for several tenants, such as an admin fan-out, must use one `withRLS()` per tenant outside any transaction, not nested in one.
|
|
87
|
+
- In RLS mode, each repository call made outside a transaction runs in its own transaction bound to the current tenant: `BEGIN`, `set_config` of the tenant, the query, `COMMIT`. These calls do not use the query cache, since the cache is bypassed inside transactions. Group calls in `Database.transaction()` or `withRLS()` to share one transaction.
|
|
88
|
+
- In RLS mode, code running without a tenant in context (background jobs, CLI commands, scripts) is scoped to the `public` tenant. Set the tenant with `withTenant(tenant, () => ...)` around the work (repository calls and `Database.transaction()` then use it), or with `withRLS(tenant, (tx) => ...)`.
|
|
89
|
+
- `migration:run` validates `--tenant` against `TENANT_ID_PATTERN`. Without a terminal it no longer creates a missing schema: pass `--create-schema` (which also skips the question in a terminal), or it fails.
|
|
90
|
+
- Query cache keys start with the connection name, and each connection has its own cache transaction scope. When several applications or environments share one cache store and use the same connection names for different databases, set `cache: { prefix }` on each connection: the prefix comes before the connection name in every key (empty by default).
|
|
91
|
+
- `DrizzleDatabaseCache` keys and values changed: entries written by earlier versions are ignored. The default TTL of cached queries (including with `cache: true`) is now 60 seconds instead of 1 second, and is set with `cache: { ttl }` in seconds.
|
|
92
|
+
- `Cache.memory` keeps a separate LRU per tag namespace, so `lruSize` applies to each namespace.
|
|
93
|
+
|
|
94
|
+
Fixes and additions:
|
|
95
|
+
|
|
96
|
+
- In RLS mode, repository operations outside a transaction run in one bound to the current tenant, through the strategy's `withIsolation()`. Transactions opened with `Database.transaction()` or by `@transactional` handlers set the tenant variable when they open. `withIsolation()` and `withRLS()` expose their transaction to repositories and `Database.getConnection()`. `TenantMismatchError` is exported.
|
|
97
|
+
- `Database.transaction(callback, connection?)` opens a transaction and registers it for the callback. When a transaction is already open on the same connection, the callback joins it (no savepoint: an error rolls back the whole transaction); in RLS mode only if the current tenant is the transaction's tenant (see above). Transactions are tracked by connection, so every name of a connection (`default` and the name it aliases) sees them, and named connections take part in transactions. `Database.getBaseConnection()`, `Database.inTransaction()` and `Database.runInTransaction()` are added. The `db:tx` context entry is still set for the default connection.
|
|
98
|
+
- `@transactional` generator handlers keep their transaction open until the stream ends, then commit (or roll back if the handler throws). They previously committed before running and failed with `generator.next is not a function`. Generator handlers also see the request context (`tenant`, `http:context`).
|
|
99
|
+
- The query cache is scoped to the connection and the current tenant, is shared correctly by several app instances (table versions stored in the cache), is not read or written inside transactions, and invalidates the tables a transaction changed once it commits. A result is only stored when no mutation happened since its query started, including when concurrent queries of the same key finish out of order. Cached queries honour Drizzle's `ex`, `px`, `exat`, `pxat` and `keepTtl` options.
|
|
100
|
+
- Cache namespaces (`Cache.redis.tags(...)`, `Cache.memory.tags(...)`) no longer overwrite each other: reads, deletes and `clear()` stay within their namespace.
|
|
101
|
+
- `getSessionTenant()` reads the Bun SQL result correctly, and `getCurrentTenant()` works without an application instance (for example under `Application.testing`).
|
|
102
|
+
- `migration:run` takes an advisory lock per tenant, adds a unique index on `elysium_migrations.name` (also to existing tables), finds the migrations from the project root (`.elysiumrc`), sets the `search_path` for the transaction only, asks before opening the transaction whether to create a missing schema, and always closes its client. Existing duplicate migration names must be removed before the unique index can be created.
|
|
103
|
+
- `migration:generate` only removes `"public".` qualifiers from the migration it generates, and leaves string literals, comments and dollar-quoted bodies (`DO` blocks, functions) untouched.
|
|
104
|
+
- `DatabaseDriver.createConnection()` receives the connection name as an optional second argument.
|
|
105
|
+
- `KeyvRedis` deletes with a single `UNLINK` (or `DEL`) per call or batch and reports failed deletes in `clear()` as `error` events.
|
|
106
|
+
|
|
107
|
+
### Patch Changes
|
|
108
|
+
|
|
109
|
+
- [`ea419db`](https://github.com/na2axl/elysiumjs/commit/ea419db) Thanks [@na2axl](https://github.com/na2axl)! - `DrizzleModel()` accepts tables made with `pgTable()` again. Under TypeScript 7 it rejected every concrete table, so models and repositories over them did not typecheck.
|
|
110
|
+
- [`3987671`](https://github.com/na2axl/elysiumjs/commit/3987671) Thanks [@na2axl](https://github.com/na2axl)! - The package only contains its build output, README and changelog. It no longer ships sources, tests or local tool state.
|
|
111
|
+
- Updated dependencies [[`5fef4a7`](https://github.com/na2axl/elysiumjs/commit/5fef4a7199f502fc4fe035299e7670739459a108)]:
|
|
112
|
+
- @elysiumjs/core@0.9.0
|
|
113
|
+
- @elysiumjs/mnemosyne@0.3.0
|
|
114
|
+
|
|
3
115
|
## 0.2.0
|
|
4
116
|
|
|
5
117
|
### Minor Changes
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { CacheConfig } from 'drizzle-orm/cache/core/types';
|
|
2
|
+
import { Table } from 'drizzle-orm';
|
|
3
|
+
import { Cache as DrizzleCache } from 'drizzle-orm/cache/core';
|
|
4
|
+
/**
|
|
5
|
+
* Default time to live of cached query results, in seconds.
|
|
6
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_CACHE_TTL = 60;
|
|
9
|
+
/**
|
|
10
|
+
* Drizzle query cache backed by the framework's cache storage.
|
|
11
|
+
*
|
|
12
|
+
* - Results are cached per connection and tenant: every key starts with the configured prefix
|
|
13
|
+
* (if any) and the connection name, result keys include the current tenant (or `public`), and
|
|
14
|
+
* tags are invalidated for the current tenant. Each connection has its own transaction scope.
|
|
15
|
+
* - Invalidation works across application instances sharing the cache store: each table has a
|
|
16
|
+
* version token in the store, every result records the versions it was read at, and a mutation
|
|
17
|
+
* replaces the versions of the tables it touches. Table versions are shared by all tenants, as
|
|
18
|
+
* a mutation made for one tenant can change rows other tenants read (shared tables, RLS
|
|
19
|
+
* bypass). Every key is written with a TTL.
|
|
20
|
+
* - A result is only stored when the table versions are still the ones its query started at, and
|
|
21
|
+
* every concurrent miss of the key read the same versions: Drizzle does not pair a `put` with its
|
|
22
|
+
* `get`, so a result that may predate a mutation is never stored.
|
|
23
|
+
* - Inside a transaction, the cache is neither read nor written, since the transaction may read
|
|
24
|
+
* its own uncommitted changes. Tables mutated in a transaction are invalidated once it commits,
|
|
25
|
+
* and not at all when it rolls back.
|
|
26
|
+
*
|
|
27
|
+
* Remaining race: a mutation run outside a transaction is invalidated while its statement runs
|
|
28
|
+
* (Drizzle starts both together), so a read on another connection that completes between the
|
|
29
|
+
* invalidation and the commit can cache the previous rows until their TTL expires. Mutations run
|
|
30
|
+
* in a transaction (including RLS-scoped repository calls) are invalidated after the commit and
|
|
31
|
+
* are not affected.
|
|
32
|
+
*
|
|
33
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
34
|
+
*/
|
|
35
|
+
export declare class DrizzleDatabaseCache extends DrizzleCache {
|
|
36
|
+
#private;
|
|
37
|
+
/**
|
|
38
|
+
* @param cacheStrategy Whether queries are cached only when they opt in (`explicit`), or always.
|
|
39
|
+
* @param globalTtl The default time to live of cached results, in seconds.
|
|
40
|
+
* @param storageEngine The cache storage to use.
|
|
41
|
+
* @param connectionName The name of the connection, which prefixes every key.
|
|
42
|
+
* @param prefix A prefix for every key, before the connection name (empty for none).
|
|
43
|
+
*/
|
|
44
|
+
constructor(cacheStrategy?: 'explicit' | 'all', globalTtl?: number, storageEngine?: 'redis' | 'memory', connectionName?: string, prefix?: string);
|
|
45
|
+
strategy(): 'explicit' | 'all';
|
|
46
|
+
/**
|
|
47
|
+
* Runs a transaction so that the cache is bypassed inside it, and the tables it mutates are
|
|
48
|
+
* invalidated once it commits.
|
|
49
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
50
|
+
* @param run Opens and runs the transaction.
|
|
51
|
+
* @returns The return value of `run`.
|
|
52
|
+
*/
|
|
53
|
+
trackTransaction<T>(run: () => Promise<T>): Promise<T>;
|
|
54
|
+
get(key: string, tables?: string[], isTag?: boolean, autoInvalidate?: boolean): Promise<any[] | undefined>;
|
|
55
|
+
put(key: string, response: any, _tables: string[], isTag: boolean, config?: CacheConfig): Promise<void>;
|
|
56
|
+
onMutate(params: {
|
|
57
|
+
tags?: string | string[];
|
|
58
|
+
tables?: string | string[] | Table<any> | Table<any>[];
|
|
59
|
+
}): Promise<void>;
|
|
60
|
+
}
|
|
@@ -9,5 +9,18 @@ export declare class MigrationRunCommand extends Command {
|
|
|
9
9
|
private tenant;
|
|
10
10
|
private connection;
|
|
11
11
|
private fresh;
|
|
12
|
+
private createSchema;
|
|
12
13
|
run(): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Runs the pending migrations in one transaction.
|
|
16
|
+
* @param sql The client.
|
|
17
|
+
*/
|
|
18
|
+
private migrate;
|
|
19
|
+
/**
|
|
20
|
+
* Checks that the tenant schema exists, or that it may be created: with `--create-schema`, or
|
|
21
|
+
* when the user agrees. Without a terminal to ask, a missing schema is an error.
|
|
22
|
+
* @param sql The client.
|
|
23
|
+
* @returns `false` if the schema must not be created.
|
|
24
|
+
*/
|
|
25
|
+
private ensureSchemaChoice;
|
|
13
26
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets the root path of the Elysium.js project: the closest parent holding an `.elysiumrc`, or
|
|
3
|
+
* the current directory when there is none.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
*/
|
|
6
|
+
export declare const getProjectPath: () => string;
|
|
7
|
+
/**
|
|
8
|
+
* Gets the directory holding the migrations of the Elysium.js project.
|
|
9
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
10
|
+
*/
|
|
11
|
+
export declare const getMigrationsPath: () => string;
|
package/dist/database.d.ts
CHANGED
|
@@ -1,74 +1,126 @@
|
|
|
1
1
|
import type { DatabaseCacheConfig, DatabaseDriver } from '@elysiumjs/mnemosyne';
|
|
2
2
|
import type { DrizzleConfig } from 'drizzle-orm';
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
3
|
+
import type { PgAsyncDatabase, PgQueryResultHKT } from 'drizzle-orm/pg-core';
|
|
4
|
+
import type { DrizzleDriver } from './driver';
|
|
5
|
+
import { ElysiumError } from '@elysiumjs/core';
|
|
5
6
|
import { AbstractDatabase } from '@elysiumjs/mnemosyne';
|
|
6
|
-
|
|
7
|
-
import { Cache as DrizzleCache } from 'drizzle-orm/cache/core';
|
|
7
|
+
export { DEFAULT_CACHE_TTL, DrizzleDatabaseCache } from './cache';
|
|
8
8
|
/**
|
|
9
9
|
* Connection configuration for Drizzle ORM.
|
|
10
10
|
*
|
|
11
|
-
* Extends `DrizzleConfig` with
|
|
11
|
+
* Extends `DrizzleConfig` with the driver and optional caching. Without `driver`, `connection`
|
|
12
|
+
* or `client` connect with Bun SQL, on Bun only.
|
|
12
13
|
*
|
|
13
14
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
14
15
|
* @template TSchema The Drizzle schema type.
|
|
15
16
|
*/
|
|
16
17
|
export type DrizzleConnectionProps<TSchema extends Record<string, unknown> = Record<string, never>> = Omit<DrizzleConfig<TSchema>, 'cache'> & ({
|
|
18
|
+
driver: DrizzleDriver;
|
|
19
|
+
} | {
|
|
17
20
|
connection: string | ({
|
|
18
21
|
url?: string;
|
|
19
|
-
} &
|
|
22
|
+
} & Record<string, unknown>);
|
|
20
23
|
} | {
|
|
21
|
-
client:
|
|
24
|
+
client: unknown;
|
|
22
25
|
}) & {
|
|
23
26
|
cache?: true | DatabaseCacheConfig;
|
|
24
27
|
};
|
|
25
28
|
/**
|
|
26
|
-
* A Drizzle database connection
|
|
29
|
+
* A Drizzle database connection, whatever its driver.
|
|
27
30
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
28
31
|
*/
|
|
29
|
-
export type DrizzleConnection =
|
|
30
|
-
$client:
|
|
32
|
+
export type DrizzleConnection = PgAsyncDatabase<DrizzleQueryResultHKT, any> & {
|
|
33
|
+
$client: any;
|
|
31
34
|
};
|
|
32
35
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
* The query results of a {@link DrizzleConnection}: rows, for `returning()` and selects. What
|
|
37
|
+
* `execute()` resolves to depends on the driver.
|
|
38
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
39
|
+
*/
|
|
40
|
+
export interface DrizzleQueryResultHKT extends PgQueryResultHKT {
|
|
41
|
+
type: this['row'][];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Closes the client of a connection through its driver.
|
|
45
|
+
* @internal
|
|
46
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
47
|
+
* @param connection The connection.
|
|
48
|
+
*/
|
|
49
|
+
export declare const closeConnection: (connection: DrizzleConnection) => Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Thrown in RLS mode when work for one tenant would join a transaction bound to another.
|
|
38
52
|
*
|
|
53
|
+
* A transaction is bound to the tenant set when it is opened, for its whole life. Work for another
|
|
54
|
+
* tenant must run outside the transaction, or in its own `withRLS()` before the transaction opens.
|
|
39
55
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
40
56
|
*/
|
|
41
|
-
export declare class
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
put(key: string, response: any, tables: string[], _isTag: boolean, config?: CacheConfig): Promise<void>;
|
|
50
|
-
onMutate(params: {
|
|
51
|
-
tags?: string | string[];
|
|
52
|
-
tables?: string | string[] | Table<any> | Table<any>[];
|
|
53
|
-
}): Promise<void>;
|
|
57
|
+
export declare class TenantMismatchError extends ElysiumError {
|
|
58
|
+
readonly transactionTenant: string | null;
|
|
59
|
+
readonly tenant: string;
|
|
60
|
+
/**
|
|
61
|
+
* @param transactionTenant The tenant the open transaction is bound to, or `null` if none.
|
|
62
|
+
* @param tenant The tenant of the work that tried to join it.
|
|
63
|
+
*/
|
|
64
|
+
constructor(transactionTenant: string | null, tenant: string);
|
|
54
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Binds a transaction to a tenant: sets the RLS tenant variable for the rest of the transaction.
|
|
68
|
+
* @internal
|
|
69
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
70
|
+
* @param tx The transaction, just opened.
|
|
71
|
+
* @param tenant The tenant identifier.
|
|
72
|
+
*/
|
|
73
|
+
export declare const bindTransactionTenant: (tx: DrizzleConnection, tenant: string) => Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Checks that work for a tenant may join an open transaction: it must be bound to that tenant.
|
|
76
|
+
* @internal
|
|
77
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
78
|
+
* @param tx The open transaction.
|
|
79
|
+
* @param tenant The tenant of the work.
|
|
80
|
+
* @throws {TenantMismatchError} If the transaction is bound to another tenant, or to none.
|
|
81
|
+
*/
|
|
82
|
+
export declare const assertTransactionTenant: (tx: DrizzleConnection, tenant: string) => void;
|
|
55
83
|
/**
|
|
56
84
|
* Drizzle-specific database manager.
|
|
57
85
|
*
|
|
58
86
|
* Implements the abstract database class with a driver that creates
|
|
59
|
-
* Drizzle connections
|
|
87
|
+
* Drizzle connections through the {@link DrizzleDriver} of each connection.
|
|
60
88
|
*
|
|
61
89
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
62
90
|
*/
|
|
63
91
|
declare class DrizzleDatabase extends AbstractDatabase<DrizzleConnection, DrizzleConnectionProps> {
|
|
92
|
+
/**
|
|
93
|
+
* Retrieves the connection with the given name, or the transaction open on it.
|
|
94
|
+
*
|
|
95
|
+
* In RLS mode, an open transaction bound to a tenant is only returned to work for that tenant,
|
|
96
|
+
* the current one (or `public`).
|
|
97
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
98
|
+
* @param name The connection name.
|
|
99
|
+
* @returns The connection, or its open transaction.
|
|
100
|
+
* @throws {TenantMismatchError} If the open transaction is bound to another tenant.
|
|
101
|
+
*/
|
|
102
|
+
getConnection(name?: string): DrizzleConnection;
|
|
103
|
+
/**
|
|
104
|
+
* Runs a callback in a transaction, joining the one open on the connection if any.
|
|
105
|
+
*
|
|
106
|
+
* In RLS mode, a new transaction is bound to the current tenant (or `public`), and an open one
|
|
107
|
+
* is only joined when it is bound to the current tenant.
|
|
108
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
109
|
+
* @param callback The function to run with the transaction.
|
|
110
|
+
* @param name The connection name.
|
|
111
|
+
* @returns The return value of the callback.
|
|
112
|
+
* @throws {TenantMismatchError} If the open transaction is bound to another tenant.
|
|
113
|
+
*/
|
|
114
|
+
transaction<T>(callback: (tx: DrizzleConnection) => Promise<T>, name?: string): Promise<T>;
|
|
64
115
|
/**
|
|
65
116
|
* Creates a Drizzle connection from its properties. Used by the `DrizzleModule` to build
|
|
66
117
|
* the `db.connection.{name}` services.
|
|
67
118
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
68
119
|
* @param props The connection properties.
|
|
120
|
+
* @param name The name of the connection, which scopes its query cache.
|
|
69
121
|
* @returns A new connection.
|
|
70
122
|
*/
|
|
71
|
-
createConnection(props: DrizzleConnectionProps): DrizzleConnection;
|
|
123
|
+
createConnection(props: DrizzleConnectionProps, name?: string): DrizzleConnection;
|
|
72
124
|
protected driver: DatabaseDriver<DrizzleConnection, DrizzleConnectionProps>;
|
|
73
125
|
}
|
|
74
126
|
/**
|
|
@@ -76,4 +128,3 @@ declare class DrizzleDatabase extends AbstractDatabase<DrizzleConnection, Drizzl
|
|
|
76
128
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
77
129
|
*/
|
|
78
130
|
export declare const Database: DrizzleDatabase;
|
|
79
|
-
export {};
|
package/dist/driver.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { DrizzleConfig } from 'drizzle-orm';
|
|
2
|
+
import type { DrizzleDatabaseCache } from './cache';
|
|
3
|
+
import type { DrizzleConnection } from './database';
|
|
4
|
+
import { ElysiumError } from '@elysiumjs/core';
|
|
5
|
+
/**
|
|
6
|
+
* What a driver connects with: the Drizzle options of the connection and its query cache.
|
|
7
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
8
|
+
*/
|
|
9
|
+
export type DrizzleDriverConfig = Omit<DrizzleConfig<Record<string, unknown>>, 'cache'> & {
|
|
10
|
+
cache?: DrizzleDatabaseCache;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Connects Drizzle to PostgreSQL through a client: Bun SQL (`/bun-sql`), postgres.js
|
|
14
|
+
* (`/postgres-js`), node-postgres (`/node-postgres`) or Cloudflare Hyperdrive (`/hyperdrive`).
|
|
15
|
+
* Implement it to plug in another client.
|
|
16
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
17
|
+
*/
|
|
18
|
+
export interface DrizzleDriver {
|
|
19
|
+
/** The name of the driver, for errors and logs. */
|
|
20
|
+
readonly name: string;
|
|
21
|
+
/**
|
|
22
|
+
* Creates the Drizzle database of a connection.
|
|
23
|
+
* @param config The Drizzle options and the query cache.
|
|
24
|
+
*/
|
|
25
|
+
connect(config: DrizzleDriverConfig): DrizzleConnection;
|
|
26
|
+
/**
|
|
27
|
+
* Closes the client of a database the driver created.
|
|
28
|
+
* @param connection The database.
|
|
29
|
+
*/
|
|
30
|
+
close(connection: DrizzleConnection): Promise<void> | void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Raised when a connection sets no driver outside Bun, where the default Bun SQL driver is not
|
|
34
|
+
* available.
|
|
35
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
36
|
+
*/
|
|
37
|
+
export declare class MissingDriverError extends ElysiumError {
|
|
38
|
+
constructor(name: string);
|
|
39
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { SQL } from 'bun';
|
|
2
|
+
import type { DrizzleDriver } from '../driver';
|
|
3
|
+
/**
|
|
4
|
+
* Options of {@link bunSql}: a connection URL or options, or a client.
|
|
5
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
6
|
+
*/
|
|
7
|
+
export type BunSqlDriverOptions = {
|
|
8
|
+
connection: string | ({
|
|
9
|
+
url?: string;
|
|
10
|
+
} & SQL.Options);
|
|
11
|
+
} | {
|
|
12
|
+
client: SQL;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Connects with Bun's built-in SQL client. Runs on Bun only.
|
|
16
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
17
|
+
* @param options The connection URL or options, or a client.
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { bunSql } from '@elysiumjs/mnemosyne-drizzle/bun-sql';
|
|
21
|
+
*
|
|
22
|
+
* DrizzleModule.with({ connections: { default: { driver: bunSql({ connection: url }) } } });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare const bunSql: (options: BunSqlDriverOptions) => DrizzleDriver;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{drizzle}from"drizzle-orm/bun-sql";var bunSql=(options)=>({name:"bun-sql",connect:(config)=>drizzle({...config,...options}),close:async(connection)=>{await connection.$client.close()}});export{bunSql};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { DrizzleDriver } from '../driver';
|
|
2
|
+
/**
|
|
3
|
+
* A Hyperdrive binding, as Cloudflare Workers pass it.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
*/
|
|
6
|
+
export type HyperdriveBinding = {
|
|
7
|
+
readonly connectionString: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Options of {@link hyperdrive}.
|
|
11
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
12
|
+
*/
|
|
13
|
+
export type HyperdriveDriverOptions = {
|
|
14
|
+
/** The name of the Hyperdrive binding, as declared in the wrangler config. */
|
|
15
|
+
binding: string;
|
|
16
|
+
/**
|
|
17
|
+
* The driver that connects to the connection string of the binding, such as
|
|
18
|
+
* `(url) => postgresJs({ connection: { url, max: 5, fetch_types: false } })`.
|
|
19
|
+
*/
|
|
20
|
+
driver: (connectionString: string) => DrizzleDriver;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Connects through a Cloudflare Hyperdrive binding. A Worker cannot reuse a socket opened in
|
|
24
|
+
* another invocation, so the database opens a client per invocation (request, queue batch or
|
|
25
|
+
* scheduled event) on first use. The runtime closes its sockets when the invocation ends, and
|
|
26
|
+
* Hyperdrive pools the connections to the database.
|
|
27
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
28
|
+
* @param options The binding name and the client driver.
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { hyperdrive } from '@elysiumjs/mnemosyne-drizzle/hyperdrive';
|
|
32
|
+
* import { postgresJs } from '@elysiumjs/mnemosyne-drizzle/postgres-js';
|
|
33
|
+
*
|
|
34
|
+
* DrizzleModule.with({
|
|
35
|
+
* connections: {
|
|
36
|
+
* default: {
|
|
37
|
+
* driver: hyperdrive({
|
|
38
|
+
* binding: 'HYPERDRIVE',
|
|
39
|
+
* driver: (url) => postgresJs({ connection: { url, max: 5, fetch_types: false } })
|
|
40
|
+
* })
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare const hyperdrive: (options: HyperdriveDriverOptions) => DrizzleDriver;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Workers}from"@elysiumjs/runtime-workers";var hyperdrive=(options)=>({name:"hyperdrive",connect:(config)=>invocationDatabase(options,config),close:()=>{}}),invocationDatabase=(options,config)=>{let databases=new WeakMap,current=()=>{let context=Workers.context(),database=databases.get(context);if(!database){let{connectionString}=Workers.binding(options.binding);database=options.driver(connectionString).connect(config),databases.set(context,database)}return database};return new Proxy({},{get(target,property){if(Object.hasOwn(target,property))return Reflect.get(target,property);let database=current(),value=Reflect.get(database,property,database);return typeof value==="function"?value.bind(database):value},has(target,property){return Object.hasOwn(target,property)||property in current()},getPrototypeOf(){return Object.getPrototypeOf(current())}})};export{hyperdrive};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Pool, PoolConfig } from 'pg';
|
|
2
|
+
import type { DrizzleDriver } from '../driver';
|
|
3
|
+
/**
|
|
4
|
+
* Options of {@link nodePostgres}: a connection URL or pool options, or a pool.
|
|
5
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
6
|
+
*/
|
|
7
|
+
export type NodePostgresDriverOptions = {
|
|
8
|
+
connection: string | PoolConfig;
|
|
9
|
+
} | {
|
|
10
|
+
client: Pool;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Connects with node-postgres (`pg`), on Node.js and Bun.
|
|
14
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
15
|
+
* @param options The connection URL or pool options, or a pool.
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { nodePostgres } from '@elysiumjs/mnemosyne-drizzle/node-postgres';
|
|
19
|
+
*
|
|
20
|
+
* DrizzleModule.with({ connections: { default: { driver: nodePostgres({ connection: url }) } } });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare const nodePostgres: (options: NodePostgresDriverOptions) => DrizzleDriver;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{drizzle}from"drizzle-orm/node-postgres";var nodePostgres=(options)=>({name:"node-postgres",connect:(config)=>drizzle({...config,...options}),close:async(connection)=>{await connection.$client.end()}});export{nodePostgres};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Options, PostgresType, Sql } from 'postgres';
|
|
2
|
+
import type { DrizzleDriver } from '../driver';
|
|
3
|
+
/**
|
|
4
|
+
* Options of {@link postgresJs}: a connection URL or options, or a client.
|
|
5
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
6
|
+
*/
|
|
7
|
+
export type PostgresJsDriverOptions = {
|
|
8
|
+
connection: string | ({
|
|
9
|
+
url?: string;
|
|
10
|
+
} & Options<Record<string, PostgresType>>);
|
|
11
|
+
} | {
|
|
12
|
+
client: Sql;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Connects with postgres.js (`postgres`), on Node.js, Bun and Cloudflare Workers.
|
|
16
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
17
|
+
* @param options The connection URL or options, or a client.
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { postgresJs } from '@elysiumjs/mnemosyne-drizzle/postgres-js';
|
|
21
|
+
*
|
|
22
|
+
* DrizzleModule.with({ connections: { default: { driver: postgresJs({ connection: url }) } } });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare const postgresJs: (options: PostgresJsDriverOptions) => DrizzleDriver;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{drizzle}from"drizzle-orm/postgres-js";var postgresJs=(options)=>({name:"postgres-js",connect:(config)=>drizzle({...config,...options}),close:async(connection)=>{await connection.$client.end()}});export{postgresJs};
|
package/dist/drizzle.module.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ declare const DrizzleModule_base: (abstract new () => {
|
|
|
16
16
|
readonly config: DrizzleModuleConfig;
|
|
17
17
|
onInit(): Promise<void> | void;
|
|
18
18
|
onDestroy(): Promise<void> | void;
|
|
19
|
-
onServe(_app: import("elysia").
|
|
19
|
+
onServe(_app: import("elysia").Elysia<any>): Promise<void> | void;
|
|
20
20
|
}) & {
|
|
21
21
|
readonly config: string;
|
|
22
22
|
with(config: Partial<DrizzleModuleConfig> | (() => Partial<DrizzleModuleConfig> | Promise<Partial<DrizzleModuleConfig>>)): import("@elysiumjs/core").ConfiguredModule<DrizzleModuleConfig>;
|
|
@@ -29,8 +29,8 @@ declare const DrizzleModule_base: (abstract new () => {
|
|
|
29
29
|
};
|
|
30
30
|
/**
|
|
31
31
|
* Declares Drizzle connections as global services named `db.connection.{name}`, plus
|
|
32
|
-
* `db.connection.default` aliasing the configured default,
|
|
33
|
-
* and strategy. Connections are created on first use. Also provides the migration commands.
|
|
32
|
+
* `db.connection.default` aliasing the configured default, `db.transaction` (used by
|
|
33
|
+
* `@transactional` handlers), and registers the tenancy config and strategy. Connections are created on first use. Also provides the migration commands.
|
|
34
34
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
35
35
|
*/
|
|
36
36
|
export declare class DrizzleModule extends DrizzleModule_base {
|
package/dist/index.d.ts
CHANGED
|
@@ -2,9 +2,11 @@ export * from 'drizzle-orm';
|
|
|
2
2
|
export * from 'drizzle-orm/pg-core';
|
|
3
3
|
export type { SelectedFields, SelectedFieldsFlat, SelectedFieldsOrdered, TableConfig } from 'drizzle-orm/pg-core';
|
|
4
4
|
export { pgTable, getTableBuilders } from './table';
|
|
5
|
-
export { Database, DrizzleDatabaseCache } from './database';
|
|
6
|
-
export type { DrizzleConnectionProps, DrizzleConnection } from './database';
|
|
5
|
+
export { Database, DEFAULT_CACHE_TTL, DrizzleDatabaseCache, TenantMismatchError } from './database';
|
|
6
|
+
export type { DrizzleConnectionProps, DrizzleConnection, DrizzleQueryResultHKT } from './database';
|
|
7
|
+
export { type DrizzleDriver, type DrizzleDriverConfig, MissingDriverError } from './driver';
|
|
7
8
|
export { DrizzleModel, createSchemaFromDrizzle, drizzleAdapter, type DrizzleModelOptions } from './model';
|
|
8
9
|
export { DrizzleModule, type DrizzleModuleConfig } from './drizzle.module';
|
|
10
|
+
export { compileAfter, compileFilter, compileQuery } from './query';
|
|
9
11
|
export { DrizzleRepository } from './repository';
|
|
10
|
-
export { DrizzleSchemaTenancy, DrizzleRLSTenancy, wrapTenantSchema, registerTenantSchema, getTenantSchema, withRLS,
|
|
12
|
+
export { DrizzleSchemaTenancy, DrizzleRLSTenancy, wrapTenantSchema, registerTenantSchema, getTenantSchema, withRLS, getSessionTenant, createRLSPolicy } from './tenancy';
|