@katajs/drizzle 0.1.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/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yaseer A. Okino
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @katajs/drizzle
|
|
2
|
+
|
|
3
|
+
Drizzle adapter for [katajs](https://github.com/ookino/katajs) — wires [Drizzle ORM](https://orm.drizzle.team) to [Cloudflare Hyperdrive](https://developers.cloudflare.com/hyperdrive/) for Postgres.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pnpm add @katajs/drizzle drizzle-orm pg
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { createApp } from '@katajs/core';
|
|
13
|
+
import { drizzleAdapter } from '@katajs/drizzle';
|
|
14
|
+
import * as schema from './db/schema';
|
|
15
|
+
|
|
16
|
+
type Bindings = {
|
|
17
|
+
HYPERDRIVE: Hyperdrive;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const { app } = createApp({
|
|
21
|
+
bindings: {} as Bindings,
|
|
22
|
+
db: drizzleAdapter({ schema }),
|
|
23
|
+
modules: [/* ... */],
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`drizzleAdapter` returns a `DbAdapter` that katajs's container middleware uses to construct a per-request `db` client backed by `env.HYPERDRIVE.connectionString`.
|
|
28
|
+
|
|
29
|
+
## Transactions
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// inside a service
|
|
33
|
+
async create(input: CreatePostInput) {
|
|
34
|
+
return c.withTransaction(async (tx) => {
|
|
35
|
+
const post = await tx.resolve('postRepository').insert(input);
|
|
36
|
+
await tx.resolve('auditService').log({ action: 'post.create', id: post.id });
|
|
37
|
+
return post;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`withTransaction` wraps `db.transaction(...)` and rebuilds a sub-container where every repository uses the transaction-bound `tx` client. Non-repository services are reused from the outer container. Nested calls reuse the outer transaction (no savepoints in v0.1).
|
|
43
|
+
|
|
44
|
+
## Public API
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
export { drizzleAdapter } from '@katajs/drizzle';
|
|
48
|
+
export type {
|
|
49
|
+
DrizzleAdapterConfig,
|
|
50
|
+
DrizzleClient,
|
|
51
|
+
DrizzleClientOrTx,
|
|
52
|
+
DrizzleTx,
|
|
53
|
+
HyperdriveBinding,
|
|
54
|
+
} from '@katajs/drizzle';
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Local development
|
|
58
|
+
|
|
59
|
+
When developing locally with `wrangler dev`, configure `wrangler.jsonc` with a `localConnectionString` for the Hyperdrive binding:
|
|
60
|
+
|
|
61
|
+
```jsonc
|
|
62
|
+
{
|
|
63
|
+
"hyperdrive": [
|
|
64
|
+
{
|
|
65
|
+
"binding": "HYPERDRIVE",
|
|
66
|
+
"id": "<your-hyperdrive-id>",
|
|
67
|
+
"localConnectionString": "postgres://postgres:postgres@localhost:5432/myapp"
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The binding `id` is required even locally; use any UUID until you've created the real Hyperdrive resource.
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
[MIT](./LICENSE) © Yaseer A. Okino
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
|
2
|
+
import { ExtractTablesWithRelations } from 'drizzle-orm';
|
|
3
|
+
import { PgTransaction, PgQueryResultHKT } from 'drizzle-orm/pg-core';
|
|
4
|
+
|
|
5
|
+
/** Drizzle client bound to node-postgres against a Hyperdrive connection. */
|
|
6
|
+
type DrizzleClient<TSchema extends Record<string, unknown> = Record<string, never>> = NodePgDatabase<TSchema>;
|
|
7
|
+
/** Drizzle transaction handle (same query API as the client). */
|
|
8
|
+
type DrizzleTx<TSchema extends Record<string, unknown> = Record<string, never>> = PgTransaction<PgQueryResultHKT, TSchema, ExtractTablesWithRelations<TSchema>>;
|
|
9
|
+
type DrizzleClientOrTx<TSchema extends Record<string, unknown> = Record<string, never>> = DrizzleClient<TSchema> | DrizzleTx<TSchema>;
|
|
10
|
+
|
|
11
|
+
/** Cloudflare Hyperdrive binding shape (per `env.HYPERDRIVE`). */
|
|
12
|
+
type HyperdriveBinding = {
|
|
13
|
+
connectionString: string;
|
|
14
|
+
};
|
|
15
|
+
type DrizzleAdapterConfig<TSchema extends Record<string, unknown> = Record<string, never>> = {
|
|
16
|
+
/** Drizzle relational schema. Required for `db.query.<table>` API. */
|
|
17
|
+
schema?: TSchema;
|
|
18
|
+
/**
|
|
19
|
+
* Override the Hyperdrive binding key on `env`. Default `HYPERDRIVE`.
|
|
20
|
+
* Useful when a project uses multiple bindings or a non-conventional name.
|
|
21
|
+
*/
|
|
22
|
+
bindingName?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Inject a custom client factory. When provided, `bindingName` is ignored.
|
|
25
|
+
* Primarily for tests; production code should let the adapter build the pool.
|
|
26
|
+
*/
|
|
27
|
+
makeClient?: (env: unknown) => DrizzleClient<TSchema>;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Drizzle adapter targeting Cloudflare Hyperdrive (Postgres). Per spec §6.2
|
|
31
|
+
* uses `pg` (`node-postgres`) with `nodejs_compat`.
|
|
32
|
+
*
|
|
33
|
+
* const { app } = createApp({
|
|
34
|
+
* bindings: {} as Bindings,
|
|
35
|
+
* db: drizzleAdapter({ schema }),
|
|
36
|
+
* modules: [...],
|
|
37
|
+
* });
|
|
38
|
+
*/
|
|
39
|
+
declare function drizzleAdapter<TSchema extends Record<string, unknown> = Record<string, never>>(config?: DrizzleAdapterConfig<TSchema>): {
|
|
40
|
+
create(env: unknown): DrizzleClient<TSchema>;
|
|
41
|
+
/**
|
|
42
|
+
* Run a function inside a Drizzle transaction. Surfaces the txDb to the
|
|
43
|
+
* caller via Drizzle's native `db.transaction(...)`. v0.1 has no
|
|
44
|
+
* savepoints — nested calls reuse the outer transaction (handled by core).
|
|
45
|
+
*/
|
|
46
|
+
runTransaction<T>(db: DrizzleClient<TSchema>, fn: (txDb: DrizzleTx<TSchema>) => Promise<T>): Promise<T>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export { type DrizzleAdapterConfig, type DrizzleClient, type DrizzleClientOrTx, type DrizzleTx, type HyperdriveBinding, drizzleAdapter };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/adapter.ts
|
|
2
|
+
import { drizzle } from "drizzle-orm/node-postgres";
|
|
3
|
+
import { Pool } from "pg";
|
|
4
|
+
function drizzleAdapter(config = {}) {
|
|
5
|
+
const bindingName = config.bindingName ?? "HYPERDRIVE";
|
|
6
|
+
return {
|
|
7
|
+
create(env) {
|
|
8
|
+
if (config.makeClient) return config.makeClient(env);
|
|
9
|
+
const binding = env?.[bindingName];
|
|
10
|
+
if (!binding?.connectionString) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
`[katajs] Missing '${bindingName}' binding or its connectionString. Add a Hyperdrive binding to wrangler.jsonc, or pass 'makeClient' for tests.`
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
const pool = new Pool({ connectionString: binding.connectionString });
|
|
16
|
+
return drizzle(pool, { schema: config.schema });
|
|
17
|
+
},
|
|
18
|
+
/**
|
|
19
|
+
* Run a function inside a Drizzle transaction. Surfaces the txDb to the
|
|
20
|
+
* caller via Drizzle's native `db.transaction(...)`. v0.1 has no
|
|
21
|
+
* savepoints — nested calls reuse the outer transaction (handled by core).
|
|
22
|
+
*/
|
|
23
|
+
async runTransaction(db, fn) {
|
|
24
|
+
return db.transaction(async (txDb) => fn(txDb));
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
drizzleAdapter
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapter.ts"],"sourcesContent":["import { drizzle } from 'drizzle-orm/node-postgres';\nimport { Pool } from 'pg';\nimport type { DrizzleClient, DrizzleTx } from './types';\n\n/** Cloudflare Hyperdrive binding shape (per `env.HYPERDRIVE`). */\nexport type HyperdriveBinding = {\n connectionString: string;\n};\n\nexport type DrizzleAdapterConfig<\n TSchema extends Record<string, unknown> = Record<string, never>,\n> = {\n /** Drizzle relational schema. Required for `db.query.<table>` API. */\n schema?: TSchema;\n /**\n * Override the Hyperdrive binding key on `env`. Default `HYPERDRIVE`.\n * Useful when a project uses multiple bindings or a non-conventional name.\n */\n bindingName?: string;\n /**\n * Inject a custom client factory. When provided, `bindingName` is ignored.\n * Primarily for tests; production code should let the adapter build the pool.\n */\n makeClient?: (env: unknown) => DrizzleClient<TSchema>;\n};\n\n/**\n * Drizzle adapter targeting Cloudflare Hyperdrive (Postgres). Per spec §6.2\n * uses `pg` (`node-postgres`) with `nodejs_compat`.\n *\n * const { app } = createApp({\n * bindings: {} as Bindings,\n * db: drizzleAdapter({ schema }),\n * modules: [...],\n * });\n */\nexport function drizzleAdapter<\n TSchema extends Record<string, unknown> = Record<string, never>,\n>(config: DrizzleAdapterConfig<TSchema> = {}) {\n const bindingName = config.bindingName ?? 'HYPERDRIVE';\n\n return {\n create(env: unknown): DrizzleClient<TSchema> {\n if (config.makeClient) return config.makeClient(env);\n\n const binding = (env as Record<string, unknown> | null | undefined)?.[\n bindingName\n ] as HyperdriveBinding | undefined;\n\n if (!binding?.connectionString) {\n throw new Error(\n `[katajs] Missing '${bindingName}' binding or its connectionString. ` +\n `Add a Hyperdrive binding to wrangler.jsonc, or pass 'makeClient' for tests.`,\n );\n }\n\n const pool = new Pool({ connectionString: binding.connectionString });\n return drizzle(pool, { schema: config.schema }) as DrizzleClient<TSchema>;\n },\n\n /**\n * Run a function inside a Drizzle transaction. Surfaces the txDb to the\n * caller via Drizzle's native `db.transaction(...)`. v0.1 has no\n * savepoints — nested calls reuse the outer transaction (handled by core).\n */\n async runTransaction<T>(\n db: DrizzleClient<TSchema>,\n fn: (txDb: DrizzleTx<TSchema>) => Promise<T>,\n ): Promise<T> {\n return db.transaction(async (txDb) => fn(txDb as DrizzleTx<TSchema>));\n },\n };\n}\n"],"mappings":";AAAA,SAAS,eAAe;AACxB,SAAS,YAAY;AAmCd,SAAS,eAEd,SAAwC,CAAC,GAAG;AAC5C,QAAM,cAAc,OAAO,eAAe;AAE1C,SAAO;AAAA,IACL,OAAO,KAAsC;AAC3C,UAAI,OAAO,WAAY,QAAO,OAAO,WAAW,GAAG;AAEnD,YAAM,UAAW,MACf,WACF;AAEA,UAAI,CAAC,SAAS,kBAAkB;AAC9B,cAAM,IAAI;AAAA,UACR,qBAAqB,WAAW;AAAA,QAElC;AAAA,MACF;AAEA,YAAM,OAAO,IAAI,KAAK,EAAE,kBAAkB,QAAQ,iBAAiB,CAAC;AACpE,aAAO,QAAQ,MAAM,EAAE,QAAQ,OAAO,OAAO,CAAC;AAAA,IAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,MAAM,eACJ,IACA,IACY;AACZ,aAAO,GAAG,YAAY,OAAO,SAAS,GAAG,IAA0B,CAAC;AAAA,IACtE;AAAA,EACF;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@katajs/drizzle",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Drizzle adapter for katajs — Hyperdrive-backed Postgres on Cloudflare Workers.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"katajs",
|
|
7
|
+
"drizzle",
|
|
8
|
+
"drizzle-orm",
|
|
9
|
+
"hyperdrive",
|
|
10
|
+
"cloudflare",
|
|
11
|
+
"workers",
|
|
12
|
+
"postgres"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "Yaseer A. Okino <yaseerokino@gmail.com>",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/ookino/katajs.git",
|
|
19
|
+
"directory": "packages/drizzle"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/ookino/katajs/tree/main/packages/drizzle#readme",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/ookino/katajs/issues"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"drizzle-orm": ">=0.36.0",
|
|
43
|
+
"pg": "^8.13.0",
|
|
44
|
+
"@katajs/core": "^0.1.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/pg": "^8.11.10",
|
|
48
|
+
"drizzle-orm": "^0.36.4",
|
|
49
|
+
"pg": "^8.13.1",
|
|
50
|
+
"tsup": "^8.3.5",
|
|
51
|
+
"typescript": "^5.6.3",
|
|
52
|
+
"vitest": "^2.1.5",
|
|
53
|
+
"@katajs/core": "0.1.0"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsup",
|
|
60
|
+
"dev": "tsup --watch",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"test:watch": "vitest",
|
|
63
|
+
"typecheck": "tsc --noEmit"
|
|
64
|
+
}
|
|
65
|
+
}
|