hazo_connect 2.4.7 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -3
- package/dist/adapters/clause-builder.d.ts +49 -0
- package/dist/adapters/clause-builder.d.ts.map +1 -0
- package/dist/adapters/clause-builder.js +192 -0
- package/dist/adapters/clause-builder.js.map +1 -0
- package/dist/adapters/file-adapter.d.ts +2 -1
- package/dist/adapters/file-adapter.d.ts.map +1 -1
- package/dist/adapters/file-adapter.js +3 -0
- package/dist/adapters/file-adapter.js.map +1 -1
- package/dist/adapters/pg-adapter.d.ts +64 -0
- package/dist/adapters/pg-adapter.d.ts.map +1 -0
- package/dist/adapters/pg-adapter.js +120 -0
- package/dist/adapters/pg-adapter.js.map +1 -0
- package/dist/adapters/postgrest-adapter.d.ts +30 -1
- package/dist/adapters/postgrest-adapter.d.ts.map +1 -1
- package/dist/adapters/postgrest-adapter.js +104 -0
- package/dist/adapters/postgrest-adapter.js.map +1 -1
- package/dist/adapters/sqlite-adapter.d.ts +43 -1
- package/dist/adapters/sqlite-adapter.d.ts.map +1 -1
- package/dist/adapters/sqlite-adapter.js +131 -0
- package/dist/adapters/sqlite-adapter.js.map +1 -1
- package/dist/adapters/supabase-adapter.d.ts +2 -1
- package/dist/adapters/supabase-adapter.d.ts.map +1 -1
- package/dist/adapters/supabase-adapter.js +3 -0
- package/dist/adapters/supabase-adapter.js.map +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +7 -3
- package/dist/factory.js.map +1 -1
- package/dist/migrations/runner.d.ts +39 -0
- package/dist/migrations/runner.d.ts.map +1 -0
- package/dist/migrations/runner.js +87 -0
- package/dist/migrations/runner.js.map +1 -0
- package/dist/nextjs/setup-helpers.d.ts.map +1 -1
- package/dist/nextjs/setup-helpers.js +15 -4
- package/dist/nextjs/setup-helpers.js.map +1 -1
- package/dist/query-builder.d.ts +65 -0
- package/dist/query-builder.d.ts.map +1 -1
- package/dist/query-builder.js +148 -0
- package/dist/query-builder.js.map +1 -1
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4 -1
- package/dist/server/index.js.map +1 -1
- package/dist/sqlite/query-translator.d.ts.map +1 -1
- package/dist/sqlite/query-translator.js +39 -2
- package/dist/sqlite/query-translator.js.map +1 -1
- package/dist/types.d.ts +65 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/database-url.d.ts +20 -0
- package/dist/utils/database-url.d.ts.map +1 -0
- package/dist/utils/database-url.js +44 -0
- package/dist/utils/database-url.js.map +1 -0
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -465,12 +465,176 @@ const hazo = createHazoConnect({
|
|
|
465
465
|
})
|
|
466
466
|
```
|
|
467
467
|
|
|
468
|
+
### pg Configuration
|
|
469
|
+
|
|
470
|
+
Use the `pg` adapter when you need SQL features that PostgREST does not expose, such as `SELECT … FOR UPDATE SKIP LOCKED` for job-queue locking or advisory locks. It connects directly to Postgres via the `postgres` driver (postgres.js).
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
const hazo = createHazoConnect({
|
|
474
|
+
type: 'pg',
|
|
475
|
+
pg: {
|
|
476
|
+
connection_string: process.env.DATABASE_URL // e.g. postgres://user:pass@host:5432/db
|
|
477
|
+
}
|
|
478
|
+
})
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
**Adapters at a glance:**
|
|
482
|
+
|
|
483
|
+
| Adapter | When to use |
|
|
484
|
+
|---------|-------------|
|
|
485
|
+
| `postgrest` | Default REST-over-Postgres. Covers most CRUD needs. |
|
|
486
|
+
| `supabase` | Hosted PostgREST with Supabase auth and realtime. |
|
|
487
|
+
| `sqlite` | Embedded SQLite for local dev, tests, or edge deployments. |
|
|
488
|
+
| `pg` | Raw Postgres via `postgres` driver. Use when you need `SELECT … FOR UPDATE SKIP LOCKED` or other SQL features PostgREST doesn't expose. Requires a direct Postgres connection string. |
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## Using SQLite with Next.js App Router
|
|
493
|
+
|
|
494
|
+
This walkthrough covers the bootstrap shape an embedded-SQLite app (single-operator, local-file) typically wants: `DATABASE_URL`-driven config, migrations applied at boot, Server Components reading directly, route handlers writing inside an atomic transaction with idempotent UPSERT.
|
|
495
|
+
|
|
496
|
+
### 1. Configure via `DATABASE_URL`
|
|
497
|
+
|
|
498
|
+
```bash
|
|
499
|
+
# .env.local
|
|
500
|
+
DATABASE_URL=sqlite:./data/site-ops.db
|
|
501
|
+
HAZO_CONNECT_ENABLE_ADMIN_UI=true # optional, for the built-in admin UI
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Supported URI forms: `sqlite:./relative`, `sqlite:/absolute`, `sqlite:///absolute`, `sqlite::memory:`. `HAZO_CONNECT_SQLITE_PATH` (if set) wins over `DATABASE_URL`.
|
|
505
|
+
|
|
506
|
+
### 2. Singleton accessor
|
|
507
|
+
|
|
508
|
+
```ts
|
|
509
|
+
// lib/db.ts
|
|
510
|
+
import 'server-only'
|
|
511
|
+
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup'
|
|
512
|
+
|
|
513
|
+
export const db = getHazoConnectSingleton()
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### 3. Apply migrations at boot
|
|
517
|
+
|
|
518
|
+
Place migration files as `migrations/0001_*.sql`, `0002_*.sql`, … in your project root.
|
|
519
|
+
|
|
520
|
+
```ts
|
|
521
|
+
// lib/migrate.ts
|
|
522
|
+
import 'server-only'
|
|
523
|
+
import path from 'path'
|
|
524
|
+
import { runMigrations } from 'hazo_connect/server'
|
|
525
|
+
import { db } from './db'
|
|
526
|
+
|
|
527
|
+
let applied: Promise<void> | null = null
|
|
528
|
+
export function ensureMigrationsApplied() {
|
|
529
|
+
if (!applied) {
|
|
530
|
+
applied = runMigrations(db, {
|
|
531
|
+
directory: path.join(process.cwd(), 'migrations')
|
|
532
|
+
}).then(() => undefined)
|
|
533
|
+
}
|
|
534
|
+
return applied
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
`runMigrations` is idempotent — pending files are detected via a `_migrations` tracking table, applied inside an `adapter.transaction()`, and recorded with a SHA-256 checksum.
|
|
539
|
+
|
|
540
|
+
### 4. Read inside Server Components
|
|
541
|
+
|
|
542
|
+
```tsx
|
|
543
|
+
// app/(dashboard)/runs/page.tsx
|
|
544
|
+
import { QueryBuilder } from 'hazo_connect/server'
|
|
545
|
+
import { db } from '@/lib/db'
|
|
546
|
+
import { ensureMigrationsApplied } from '@/lib/migrate'
|
|
547
|
+
|
|
548
|
+
export default async function RunsPage() {
|
|
549
|
+
await ensureMigrationsApplied()
|
|
550
|
+
const runs = await db.query(
|
|
551
|
+
new QueryBuilder().from('daily_runs').order('run_date', 'desc').limit(20)
|
|
552
|
+
)
|
|
553
|
+
return <RunsTable runs={runs} />
|
|
554
|
+
}
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
All adapter methods return `Promise`s — Server Components `await` them directly.
|
|
558
|
+
|
|
559
|
+
### 5. Write inside route handlers (idempotent UPSERT + transactions)
|
|
560
|
+
|
|
561
|
+
```ts
|
|
562
|
+
// app/api/v1/runs/route.ts
|
|
563
|
+
import { NextResponse } from 'next/server'
|
|
564
|
+
import { QueryBuilder, type SqliteTransactionContext } from 'hazo_connect/server'
|
|
565
|
+
import { SqliteAdapter } from 'hazo_connect/server'
|
|
566
|
+
import { db } from '@/lib/db'
|
|
567
|
+
|
|
568
|
+
export async function POST(req: Request) {
|
|
569
|
+
const payload = await req.json()
|
|
570
|
+
const adapter = db as SqliteAdapter
|
|
571
|
+
|
|
572
|
+
const runId = await adapter.transaction(async (tx: SqliteTransactionContext) => {
|
|
573
|
+
// Idempotent on (site_id, run_date). Re-running the same routine on the
|
|
574
|
+
// same day updates the existing row.
|
|
575
|
+
const [run] = await tx.query(
|
|
576
|
+
new QueryBuilder()
|
|
577
|
+
.from('daily_runs')
|
|
578
|
+
.onConflict(['site_id', 'run_date'])
|
|
579
|
+
.doUpdate(),
|
|
580
|
+
'POST',
|
|
581
|
+
{
|
|
582
|
+
site_id: payload.site_id,
|
|
583
|
+
run_date: payload.run_date,
|
|
584
|
+
status: payload.status,
|
|
585
|
+
steps_completed: payload.steps_completed
|
|
586
|
+
}
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
for (const article of payload.articles ?? []) {
|
|
590
|
+
await tx.query(
|
|
591
|
+
new QueryBuilder().from('articles_published'),
|
|
592
|
+
'POST',
|
|
593
|
+
{ ...article, run_id: run.run_id }
|
|
594
|
+
)
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
for (const check of payload.health_checks ?? []) {
|
|
598
|
+
await tx.query(
|
|
599
|
+
new QueryBuilder()
|
|
600
|
+
.from('health_checks')
|
|
601
|
+
.onConflict(['site_id', 'check_date', 'check_key'])
|
|
602
|
+
.doUpdate(),
|
|
603
|
+
'POST',
|
|
604
|
+
{ ...check, run_id: run.run_id, site_id: payload.site_id }
|
|
605
|
+
)
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
return run.run_id
|
|
609
|
+
})
|
|
610
|
+
|
|
611
|
+
return NextResponse.json({ ok: true, data: { run_id: runId } }, { status: 201 })
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
Key points:
|
|
616
|
+
|
|
617
|
+
- `adapter.transaction(fn)` wraps the callback in `BEGIN`/`COMMIT`. If `fn` throws, `ROLLBACK` runs and no rows reach disk.
|
|
618
|
+
- The SQLite adapter persists the in-memory DB image to disk **exactly once** per transaction (not once per statement) — large multi-write payloads are reasonably fast.
|
|
619
|
+
- `QueryBuilder.onConflict(cols).doUpdate()` defaults to `SET col = excluded.col` for every inserted column except the conflict target. Pass an object — `doUpdate({ status: 'done' })` — to update only specific columns. Pass `doNothing()` to keep the existing row.
|
|
620
|
+
|
|
621
|
+
### 6. Backups
|
|
622
|
+
|
|
623
|
+
`sql.js` works on an in-memory image, so a "hot backup" while a transaction is mid-flight isn't meaningful. The simplest backup pattern is a cron job:
|
|
624
|
+
|
|
625
|
+
```bash
|
|
626
|
+
cp data/site-ops.db data/backups/$(date +%F).db
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
Run it outside an in-flight transaction window. (A typed `store.backup()` helper is on the roadmap once we move to `better-sqlite3`.)
|
|
630
|
+
|
|
468
631
|
### Environment Variables
|
|
469
632
|
|
|
470
633
|
| Variable | Description | Default |
|
|
471
634
|
|----------|-------------|---------|
|
|
472
|
-
| `HAZO_CONNECT_TYPE` | Database type (`sqlite`, `postgrest`, `supabase`) | `sqlite` |
|
|
473
|
-
| `
|
|
635
|
+
| `HAZO_CONNECT_TYPE` | Database type (`sqlite`, `postgrest`, `supabase`, `pg`) | `sqlite` |
|
|
636
|
+
| `DATABASE_URL` | SQLite-only URI form, e.g. `sqlite:./data/site-ops.db`, `sqlite:/var/lib/x.db`, `sqlite:///var/lib/x.db`, `sqlite::memory:`. Read by `createHazoConnectFromEnv` when `HAZO_CONNECT_SQLITE_PATH` is not set. | - |
|
|
637
|
+
| `HAZO_CONNECT_SQLITE_PATH` | Path to SQLite database file. Ignored when the config object supplies `sqlite.initial_sql` (so test seeds aren't overridden by ambient env). Takes precedence over `DATABASE_URL` when both are set. | `./database.sqlite` |
|
|
474
638
|
| `HAZO_CONNECT_SQLITE_READONLY` | Enable read-only mode | `false` |
|
|
475
639
|
| `HAZO_CONNECT_SQLITE_WASM_DIR` | Path to sql-wasm.wasm directory | Auto-detected |
|
|
476
640
|
| `HAZO_CONNECT_ENABLE_ADMIN_UI` | Enable SQLite admin UI | `false` |
|
|
@@ -575,7 +739,7 @@ Main configuration interface:
|
|
|
575
739
|
|
|
576
740
|
```typescript
|
|
577
741
|
interface HazoConnectConfig {
|
|
578
|
-
type: 'postgrest' | 'supabase' | 'sqlite' | 'file'
|
|
742
|
+
type: 'postgrest' | 'supabase' | 'sqlite' | 'file' | 'pg'
|
|
579
743
|
logger?: Logger
|
|
580
744
|
log_level?: 'debug' | 'info' | 'warn' | 'error' | 'none'
|
|
581
745
|
enable_admin_ui?: boolean // SQLite only
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared serialization helpers for the claimRows primitive.
|
|
3
|
+
* Pure functions; no I/O. Used by Pg, Postgrest, and Sqlite adapters.
|
|
4
|
+
*/
|
|
5
|
+
export type Dialect = "pg" | "postgrest" | "sqlite";
|
|
6
|
+
export type NowSentinel = {
|
|
7
|
+
$now: true;
|
|
8
|
+
};
|
|
9
|
+
export declare function isNowSentinel(v: unknown): v is NowSentinel;
|
|
10
|
+
export declare function validateColumnName(name: string): void;
|
|
11
|
+
export declare function validateOperator(op: string): void;
|
|
12
|
+
export type ResolvedNow = {
|
|
13
|
+
kind: "sql";
|
|
14
|
+
value: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: "literal";
|
|
17
|
+
value: unknown;
|
|
18
|
+
};
|
|
19
|
+
export declare function resolveNowSentinel(v: unknown, dialect: Dialect): ResolvedNow;
|
|
20
|
+
export declare function serializeWhereToPostgrest(where: Record<string, unknown>): Record<string, string>;
|
|
21
|
+
export interface PgSqlFragment {
|
|
22
|
+
fragment: string;
|
|
23
|
+
params: unknown[];
|
|
24
|
+
nextParamIndex: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function serializeWhereToPgSql(where: Record<string, unknown>, startIndex: number): PgSqlFragment;
|
|
27
|
+
type SetValue = unknown | NowSentinel | {
|
|
28
|
+
increment: number;
|
|
29
|
+
};
|
|
30
|
+
export declare function serializeSetToPgSql(set: Record<string, SetValue>, startIndex: number): PgSqlFragment;
|
|
31
|
+
export declare function serializeSetToPostgrestBody(set: Record<string, SetValue>, observed: Record<string, unknown>): Record<string, unknown>;
|
|
32
|
+
/** Columns the caller incremented — needed for CAS witnesses on PostgrestAdapter. */
|
|
33
|
+
export declare function incrementedColumns(set: Record<string, SetValue>): string[];
|
|
34
|
+
/**
|
|
35
|
+
* Reject empty where/set/returning at the API boundary so adapters
|
|
36
|
+
* don't generate malformed SQL or — on PostgrestAdapter — accidentally
|
|
37
|
+
* match every row.
|
|
38
|
+
*
|
|
39
|
+
* Caller is expected to pass the full ClaimRowsOptions; types kept loose
|
|
40
|
+
* here because the helper lives in clause-builder which doesn't import
|
|
41
|
+
* from types.ts (avoids circular import risk).
|
|
42
|
+
*/
|
|
43
|
+
export declare function validateClaimRowsOptions(opts: {
|
|
44
|
+
where: Record<string, unknown>;
|
|
45
|
+
set: Record<string, unknown>;
|
|
46
|
+
returning?: string[];
|
|
47
|
+
}): void;
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=clause-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clause-builder.d.ts","sourceRoot":"","sources":["../../src/lib/adapters/clause-builder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEpD,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC;AACzC,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,WAAW,CAE1D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIrD;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAIjD;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAC/F,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,WAAW,CAK5E;AAgBD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBhG;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB;AAMD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,aAAa,CAiCvG;AAID,KAAK,QAAQ,GAAG,OAAO,GAAG,WAAW,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,aAAa,CAqBpG;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAmBrI;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,CAI1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB,GAAG,IAAI,CAUP"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared serialization helpers for the claimRows primitive.
|
|
4
|
+
* Pure functions; no I/O. Used by Pg, Postgrest, and Sqlite adapters.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.isNowSentinel = isNowSentinel;
|
|
8
|
+
exports.validateColumnName = validateColumnName;
|
|
9
|
+
exports.validateOperator = validateOperator;
|
|
10
|
+
exports.resolveNowSentinel = resolveNowSentinel;
|
|
11
|
+
exports.serializeWhereToPostgrest = serializeWhereToPostgrest;
|
|
12
|
+
exports.serializeWhereToPgSql = serializeWhereToPgSql;
|
|
13
|
+
exports.serializeSetToPgSql = serializeSetToPgSql;
|
|
14
|
+
exports.serializeSetToPostgrestBody = serializeSetToPostgrestBody;
|
|
15
|
+
exports.incrementedColumns = incrementedColumns;
|
|
16
|
+
exports.validateClaimRowsOptions = validateClaimRowsOptions;
|
|
17
|
+
const COLUMN_NAME_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
18
|
+
const ALLOWED_OPS = new Set(["eq", "lte", "gte", "lt", "gt", "in", "increment", "$now"]);
|
|
19
|
+
function isNowSentinel(v) {
|
|
20
|
+
return typeof v === "object" && v !== null && "$now" in v && v.$now === true;
|
|
21
|
+
}
|
|
22
|
+
function validateColumnName(name) {
|
|
23
|
+
if (!COLUMN_NAME_RE.test(name)) {
|
|
24
|
+
throw new Error(`invalid column name: ${JSON.stringify(name)}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function validateOperator(op) {
|
|
28
|
+
if (!ALLOWED_OPS.has(op)) {
|
|
29
|
+
throw new Error(`unknown operator: ${JSON.stringify(op)}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function resolveNowSentinel(v, dialect) {
|
|
33
|
+
if (!isNowSentinel(v))
|
|
34
|
+
return { kind: "literal", value: v };
|
|
35
|
+
if (dialect === "pg")
|
|
36
|
+
return { kind: "sql", value: "now()" };
|
|
37
|
+
if (dialect === "sqlite")
|
|
38
|
+
return { kind: "sql", value: "datetime('now')" };
|
|
39
|
+
return { kind: "literal", value: new Date().toISOString() };
|
|
40
|
+
}
|
|
41
|
+
function asOperator(v) {
|
|
42
|
+
if (typeof v !== "object" || v === null || isNowSentinel(v))
|
|
43
|
+
return null;
|
|
44
|
+
const keys = Object.keys(v).filter((k) => ["lte", "gte", "lt", "gt", "in"].includes(k));
|
|
45
|
+
if (keys.length === 0)
|
|
46
|
+
return null;
|
|
47
|
+
if (keys.length > 1) {
|
|
48
|
+
throw new Error(`multiple operators in single clause not supported: ${keys.join(", ")}`);
|
|
49
|
+
}
|
|
50
|
+
const op = keys[0];
|
|
51
|
+
return { op, value: v[op] };
|
|
52
|
+
}
|
|
53
|
+
function serializeWhereToPostgrest(where) {
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const [col, raw] of Object.entries(where)) {
|
|
56
|
+
validateColumnName(col);
|
|
57
|
+
const opObj = asOperator(raw);
|
|
58
|
+
if (opObj) {
|
|
59
|
+
if (opObj.op === "in") {
|
|
60
|
+
if (!Array.isArray(opObj.value))
|
|
61
|
+
throw new Error(`in clause requires array for column ${col}`);
|
|
62
|
+
out[col] = `in.(${opObj.value.map(String).join(",")})`;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const resolved = resolveNowSentinel(opObj.value, "postgrest");
|
|
66
|
+
if (resolved.kind === "sql")
|
|
67
|
+
throw new Error("postgrest path cannot use sql sentinel");
|
|
68
|
+
out[col] = `${opObj.op}.${String(resolved.value)}`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// scalar => eq
|
|
73
|
+
const resolved = resolveNowSentinel(raw, "postgrest");
|
|
74
|
+
out[col] = `eq.${String(resolved.value)}`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
const PG_OP_SQL = {
|
|
80
|
+
lte: "<=", gte: ">=", lt: "<", gt: ">", eq: "=",
|
|
81
|
+
};
|
|
82
|
+
function serializeWhereToPgSql(where, startIndex) {
|
|
83
|
+
const parts = [];
|
|
84
|
+
const params = [];
|
|
85
|
+
let idx = startIndex;
|
|
86
|
+
for (const [col, raw] of Object.entries(where)) {
|
|
87
|
+
validateColumnName(col);
|
|
88
|
+
const opObj = asOperator(raw);
|
|
89
|
+
if (opObj) {
|
|
90
|
+
if (opObj.op === "in") {
|
|
91
|
+
if (!Array.isArray(opObj.value))
|
|
92
|
+
throw new Error(`in clause requires array for column ${col}`);
|
|
93
|
+
const slots = opObj.value.map(() => `$${idx++}`);
|
|
94
|
+
params.push(...opObj.value);
|
|
95
|
+
parts.push(`${col} IN (${slots.join(", ")})`);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const resolved = resolveNowSentinel(opObj.value, "pg");
|
|
99
|
+
if (resolved.kind === "sql") {
|
|
100
|
+
parts.push(`${col} ${PG_OP_SQL[opObj.op]} ${resolved.value}`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
parts.push(`${col} ${PG_OP_SQL[opObj.op]} $${idx++}`);
|
|
104
|
+
params.push(resolved.value);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
const resolved = resolveNowSentinel(raw, "pg");
|
|
110
|
+
if (resolved.kind === "sql") {
|
|
111
|
+
parts.push(`${col} = ${resolved.value}`);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
parts.push(`${col} = $${idx++}`);
|
|
115
|
+
params.push(resolved.value);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { fragment: parts.join(" AND "), params, nextParamIndex: idx };
|
|
120
|
+
}
|
|
121
|
+
function serializeSetToPgSql(set, startIndex) {
|
|
122
|
+
const parts = [];
|
|
123
|
+
const params = [];
|
|
124
|
+
let idx = startIndex;
|
|
125
|
+
for (const [col, raw] of Object.entries(set)) {
|
|
126
|
+
validateColumnName(col);
|
|
127
|
+
if (typeof raw === "object" && raw !== null && "increment" in raw) {
|
|
128
|
+
const n = raw.increment;
|
|
129
|
+
if (typeof n !== "number" || !Number.isFinite(n))
|
|
130
|
+
throw new Error(`increment must be a finite number for column ${col}`);
|
|
131
|
+
parts.push(`${col} = ${col} + ${n}`);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const resolved = resolveNowSentinel(raw, "pg");
|
|
135
|
+
if (resolved.kind === "sql") {
|
|
136
|
+
parts.push(`${col} = ${resolved.value}`);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
parts.push(`${col} = $${idx++}`);
|
|
140
|
+
params.push(resolved.value);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return { fragment: parts.join(", "), params, nextParamIndex: idx };
|
|
144
|
+
}
|
|
145
|
+
function serializeSetToPostgrestBody(set, observed) {
|
|
146
|
+
const out = {};
|
|
147
|
+
for (const [col, raw] of Object.entries(set)) {
|
|
148
|
+
validateColumnName(col);
|
|
149
|
+
if (typeof raw === "object" && raw !== null && "increment" in raw) {
|
|
150
|
+
const n = raw.increment;
|
|
151
|
+
if (typeof n !== "number" || !Number.isFinite(n))
|
|
152
|
+
throw new Error(`increment must be a finite number for column ${col}`);
|
|
153
|
+
const current = observed[col];
|
|
154
|
+
if (typeof current !== "number") {
|
|
155
|
+
const display = current === null ? "null" : typeof current;
|
|
156
|
+
throw new Error(`increment on ${col} requires observed numeric value (got ${display})`);
|
|
157
|
+
}
|
|
158
|
+
out[col] = current + n;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const resolved = resolveNowSentinel(raw, "postgrest");
|
|
162
|
+
out[col] = resolved.value;
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
/** Columns the caller incremented — needed for CAS witnesses on PostgrestAdapter. */
|
|
167
|
+
function incrementedColumns(set) {
|
|
168
|
+
return Object.entries(set)
|
|
169
|
+
.filter(([_, v]) => typeof v === "object" && v !== null && "increment" in v)
|
|
170
|
+
.map(([col]) => col);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Reject empty where/set/returning at the API boundary so adapters
|
|
174
|
+
* don't generate malformed SQL or — on PostgrestAdapter — accidentally
|
|
175
|
+
* match every row.
|
|
176
|
+
*
|
|
177
|
+
* Caller is expected to pass the full ClaimRowsOptions; types kept loose
|
|
178
|
+
* here because the helper lives in clause-builder which doesn't import
|
|
179
|
+
* from types.ts (avoids circular import risk).
|
|
180
|
+
*/
|
|
181
|
+
function validateClaimRowsOptions(opts) {
|
|
182
|
+
if (Object.keys(opts.where).length === 0) {
|
|
183
|
+
throw new Error("claimRows: where must contain at least one condition");
|
|
184
|
+
}
|
|
185
|
+
if (Object.keys(opts.set).length === 0) {
|
|
186
|
+
throw new Error("claimRows: set must contain at least one field");
|
|
187
|
+
}
|
|
188
|
+
if (opts.returning !== undefined && opts.returning.length === 0) {
|
|
189
|
+
throw new Error("claimRows: returning must contain at least one column (or omit for default *)");
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=clause-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clause-builder.js","sourceRoot":"","sources":["../../src/lib/adapters/clause-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* }
|
|
14
14
|
* }
|
|
15
15
|
*/
|
|
16
|
-
import type { HazoConnectAdapter, Logger } from '../types.js';
|
|
16
|
+
import type { HazoConnectAdapter, Logger, ClaimRowsOptions } from '../types.js';
|
|
17
17
|
import { BaseAdapter } from './base-adapter.js';
|
|
18
18
|
import { QueryBuilder } from '../query-builder.js';
|
|
19
19
|
/**
|
|
@@ -46,5 +46,6 @@ export declare class FileAdapter extends BaseAdapter implements HazoConnectAdapt
|
|
|
46
46
|
* @returns Promise with adapter-specific config
|
|
47
47
|
*/
|
|
48
48
|
getConfig(): Promise<any>;
|
|
49
|
+
claimRows<T = Record<string, unknown>>(_opts: ClaimRowsOptions): Promise<T[]>;
|
|
49
50
|
}
|
|
50
51
|
//# sourceMappingURL=file-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-adapter.d.ts","sourceRoot":"","sources":["../../src/lib/adapters/file-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"file-adapter.d.ts","sourceRoot":"","sources":["../../src/lib/adapters/file-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAGlD;;GAEG;AACH,qBAAa,WAAY,SAAQ,WAAY,YAAW,kBAAkB;IACxE;;;;OAIG;gBACS,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,MAAM;IAKxC;;;;;;OAMG;IACG,KAAK,CACT,OAAO,EAAE,YAAY,EACrB,MAAM,GAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAgB,EAC3D,IAAI,CAAC,EAAE,GAAG,GACT,OAAO,CAAC,GAAG,CAAC;IAOf;;;;;OAKG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,GAAG,CAAC;IAOzE;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC;IAIzB,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;CAGpF"}
|
|
@@ -57,6 +57,9 @@ class FileAdapter extends base_adapter_js_1.BaseAdapter {
|
|
|
57
57
|
async getConfig() {
|
|
58
58
|
return Promise.resolve(this.config.file || this.config);
|
|
59
59
|
}
|
|
60
|
+
async claimRows(_opts) {
|
|
61
|
+
this.throwError(types_js_1.ErrorCode.NOT_IMPLEMENTED, "FileAdapter.claimRows: not supported by file backend");
|
|
62
|
+
}
|
|
60
63
|
}
|
|
61
64
|
exports.FileAdapter = FileAdapter;
|
|
62
65
|
//# sourceMappingURL=file-adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-adapter.js","sourceRoot":"","sources":["../../src/lib/adapters/file-adapter.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAGH,uDAA+C;AAE/C,0CAAuC;AAEvC;;GAEG;AACH,MAAa,WAAY,SAAQ,6BAAW;IAC1C;;;;OAIG;IACH,YAAY,MAAW,EAAE,MAAe;QACtC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACrB,8CAA8C;IAChD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,CACT,OAAqB,EACrB,SAAsD,KAAK,EAC3D,IAAU;QAEV,IAAI,CAAC,UAAU,CACb,oBAAS,CAAC,eAAe,EACzB,4EAA4E,CAC7E,CAAA;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CAAC,QAAgB,EAAE,UAAuB,EAAE;QACxD,IAAI,CAAC,UAAU,CACb,oBAAS,CAAC,eAAe,EACzB,4EAA4E,CAC7E,CAAA;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,SAAS;QACb,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,CAAA;IACzD,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"file-adapter.js","sourceRoot":"","sources":["../../src/lib/adapters/file-adapter.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAGH,uDAA+C;AAE/C,0CAAuC;AAEvC;;GAEG;AACH,MAAa,WAAY,SAAQ,6BAAW;IAC1C;;;;OAIG;IACH,YAAY,MAAW,EAAE,MAAe;QACtC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACrB,8CAA8C;IAChD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,CACT,OAAqB,EACrB,SAAsD,KAAK,EAC3D,IAAU;QAEV,IAAI,CAAC,UAAU,CACb,oBAAS,CAAC,eAAe,EACzB,4EAA4E,CAC7E,CAAA;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CAAC,QAAgB,EAAE,UAAuB,EAAE;QACxD,IAAI,CAAC,UAAU,CACb,oBAAS,CAAC,eAAe,EACzB,4EAA4E,CAC7E,CAAA;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,SAAS;QACb,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,CAAA;IACzD,CAAC;IAED,KAAK,CAAC,SAAS,CAA8B,KAAuB;QAClE,IAAI,CAAC,UAAU,CAAC,oBAAS,CAAC,eAAe,EAAE,sDAAsD,CAAC,CAAA;IACpG,CAAC;CACF;AArDD,kCAqDC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purpose: PostgreSQL adapter powered by the `postgres` (postgres.js) driver.
|
|
3
|
+
*
|
|
4
|
+
* Supports raw SQL execution via sql.unsafe(), which is required for advanced
|
|
5
|
+
* Postgres features (e.g., SELECT … FOR UPDATE SKIP LOCKED) that PostgREST
|
|
6
|
+
* does not expose. The query(builder) method intentionally throws until Task 1.3
|
|
7
|
+
* adds toPgSql() to the QueryBuilder.
|
|
8
|
+
*/
|
|
9
|
+
import type { Logger, ClaimRowsOptions } from '../types.js';
|
|
10
|
+
import { BaseAdapter } from './base-adapter.js';
|
|
11
|
+
import type { QueryBuilder } from '../query-builder.js';
|
|
12
|
+
export interface PgAdapterConfig {
|
|
13
|
+
type: 'pg';
|
|
14
|
+
connectionString: string;
|
|
15
|
+
poolMax?: number;
|
|
16
|
+
ssl?: boolean | 'require';
|
|
17
|
+
log_level?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class PgAdapter extends BaseAdapter {
|
|
20
|
+
private sql;
|
|
21
|
+
constructor(config: PgAdapterConfig, logger?: Logger);
|
|
22
|
+
/**
|
|
23
|
+
* Execute a query using the QueryBuilder.
|
|
24
|
+
* Not yet implemented — toPgSql() is added in Task 1.3.
|
|
25
|
+
* hazo_jobs should use raw() directly until then.
|
|
26
|
+
*/
|
|
27
|
+
query(_builder: QueryBuilder, _method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', _body?: unknown): Promise<never>;
|
|
28
|
+
/**
|
|
29
|
+
* Not applicable for the pg adapter (no HTTP layer).
|
|
30
|
+
* Satisfies the HazoConnectAdapter interface — use raw() for direct SQL.
|
|
31
|
+
*/
|
|
32
|
+
rawQuery(_endpoint: string, _options?: RequestInit): Promise<never>;
|
|
33
|
+
/**
|
|
34
|
+
* Execute a raw SQL statement with positional parameters.
|
|
35
|
+
* Uses sql.unsafe() so that the caller controls the full query text.
|
|
36
|
+
* Parameters are passed as a plain array and forwarded to postgres.js.
|
|
37
|
+
*
|
|
38
|
+
* @param text - SQL text, e.g. "SELECT * FROM jobs WHERE id = $1"
|
|
39
|
+
* @param values - Positional parameter values
|
|
40
|
+
* @returns Array of row objects
|
|
41
|
+
*/
|
|
42
|
+
raw<T = unknown>(text: string, values?: unknown[]): Promise<T[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Atomically claim rows from a queue table using FOR UPDATE SKIP LOCKED.
|
|
45
|
+
*
|
|
46
|
+
* A CTE selects candidate rows matching `where`, locks them with
|
|
47
|
+
* SKIP LOCKED so concurrent callers never contend, then UPDATE sets
|
|
48
|
+
* the requested fields and returns the RETURNING projection.
|
|
49
|
+
*
|
|
50
|
+
* @param opts - Table, where filter, set patch, optional orderBy/limit/returning
|
|
51
|
+
* @returns Array of updated row objects (empty when no rows match)
|
|
52
|
+
*/
|
|
53
|
+
claimRows<T = Record<string, unknown>>(opts: ClaimRowsOptions): Promise<T[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Drain the connection pool and release all Postgres connections.
|
|
56
|
+
* Call this on process shutdown or when the adapter is no longer needed.
|
|
57
|
+
*/
|
|
58
|
+
close(): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Return the resolved adapter configuration.
|
|
61
|
+
*/
|
|
62
|
+
getConfig(): Promise<PgAdapterConfig>;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=pg-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg-adapter.d.ts","sourceRoot":"","sources":["../../src/lib/adapters/pg-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAQvD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,IAAI,CAAA;IACV,gBAAgB,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,qBAAa,SAAU,SAAQ,WAAW;IACxC,OAAO,CAAC,GAAG,CAAK;gBAEJ,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,MAAM;IAYpD;;;;OAIG;IACG,KAAK,CACT,QAAQ,EAAE,YAAY,EACtB,OAAO,GAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAgB,EAC5D,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,KAAK,CAAC;IAOjB;;;OAGG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC;IAOzE;;;;;;;;OAQG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAS1E;;;;;;;;;OASG;IACG,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAkClF;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;CAG5C"}
|