@xfcfam/xf-sql 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 +167 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/src/api/A.d.ts +17 -0
- package/dist/src/api/A.d.ts.map +1 -0
- package/dist/src/api/A.js +17 -0
- package/dist/src/api/A.js.map +1 -0
- package/dist/src/business/B.d.ts +17 -0
- package/dist/src/business/B.d.ts.map +1 -0
- package/dist/src/business/B.js +17 -0
- package/dist/src/business/B.js.map +1 -0
- package/dist/src/repository/R.d.ts +17 -0
- package/dist/src/repository/R.d.ts.map +1 -0
- package/dist/src/repository/R.js +17 -0
- package/dist/src/repository/R.js.map +1 -0
- package/dist/src/repository/base/DatabaseRepository.d.ts +184 -0
- package/dist/src/repository/base/DatabaseRepository.d.ts.map +1 -0
- package/dist/src/repository/base/DatabaseRepository.js +216 -0
- package/dist/src/repository/base/DatabaseRepository.js.map +1 -0
- package/dist/src/repository/base/TransactionalDatabaseRepository.d.ts +86 -0
- package/dist/src/repository/base/TransactionalDatabaseRepository.d.ts.map +1 -0
- package/dist/src/repository/base/TransactionalDatabaseRepository.js +104 -0
- package/dist/src/repository/base/TransactionalDatabaseRepository.js.map +1 -0
- package/dist/src/repository/general/DatabaseRepository.d.ts +192 -0
- package/dist/src/repository/general/DatabaseRepository.d.ts.map +1 -0
- package/dist/src/repository/general/DatabaseRepository.js +224 -0
- package/dist/src/repository/general/DatabaseRepository.js.map +1 -0
- package/dist/src/repository/general/TransactionalDatabaseRepository.d.ts +91 -0
- package/dist/src/repository/general/TransactionalDatabaseRepository.d.ts.map +1 -0
- package/dist/src/repository/general/TransactionalDatabaseRepository.js +114 -0
- package/dist/src/repository/general/TransactionalDatabaseRepository.js.map +1 -0
- package/dist/src/repository/structs/CheckViolationException.d.ts +19 -0
- package/dist/src/repository/structs/CheckViolationException.d.ts.map +1 -0
- package/dist/src/repository/structs/CheckViolationException.js +22 -0
- package/dist/src/repository/structs/CheckViolationException.js.map +1 -0
- package/dist/src/repository/structs/ConnectionException.d.ts +15 -0
- package/dist/src/repository/structs/ConnectionException.d.ts.map +1 -0
- package/dist/src/repository/structs/ConnectionException.js +16 -0
- package/dist/src/repository/structs/ConnectionException.js.map +1 -0
- package/dist/src/repository/structs/DatabaseException.d.ts +14 -0
- package/dist/src/repository/structs/DatabaseException.d.ts.map +1 -0
- package/dist/src/repository/structs/DatabaseException.js +15 -0
- package/dist/src/repository/structs/DatabaseException.js.map +1 -0
- package/dist/src/repository/structs/DeadlockException.d.ts +16 -0
- package/dist/src/repository/structs/DeadlockException.d.ts.map +1 -0
- package/dist/src/repository/structs/DeadlockException.js +17 -0
- package/dist/src/repository/structs/DeadlockException.js.map +1 -0
- package/dist/src/repository/structs/ForeignKeyViolationException.d.ts +20 -0
- package/dist/src/repository/structs/ForeignKeyViolationException.d.ts.map +1 -0
- package/dist/src/repository/structs/ForeignKeyViolationException.js +23 -0
- package/dist/src/repository/structs/ForeignKeyViolationException.js.map +1 -0
- package/dist/src/repository/structs/NotNullViolationException.d.ts +20 -0
- package/dist/src/repository/structs/NotNullViolationException.d.ts.map +1 -0
- package/dist/src/repository/structs/NotNullViolationException.js +23 -0
- package/dist/src/repository/structs/NotNullViolationException.js.map +1 -0
- package/dist/src/repository/structs/UniqueViolationException.d.ts +36 -0
- package/dist/src/repository/structs/UniqueViolationException.d.ts.map +1 -0
- package/dist/src/repository/structs/UniqueViolationException.js +40 -0
- package/dist/src/repository/structs/UniqueViolationException.js.map +1 -0
- package/dist/src/repository/transfers/CheckViolationException.d.ts +19 -0
- package/dist/src/repository/transfers/CheckViolationException.d.ts.map +1 -0
- package/dist/src/repository/transfers/CheckViolationException.js +22 -0
- package/dist/src/repository/transfers/CheckViolationException.js.map +1 -0
- package/dist/src/repository/transfers/ConnectionException.d.ts +15 -0
- package/dist/src/repository/transfers/ConnectionException.d.ts.map +1 -0
- package/dist/src/repository/transfers/ConnectionException.js +16 -0
- package/dist/src/repository/transfers/ConnectionException.js.map +1 -0
- package/dist/src/repository/transfers/DatabaseException.d.ts +14 -0
- package/dist/src/repository/transfers/DatabaseException.d.ts.map +1 -0
- package/dist/src/repository/transfers/DatabaseException.js +15 -0
- package/dist/src/repository/transfers/DatabaseException.js.map +1 -0
- package/dist/src/repository/transfers/DeadlockException.d.ts +16 -0
- package/dist/src/repository/transfers/DeadlockException.d.ts.map +1 -0
- package/dist/src/repository/transfers/DeadlockException.js +17 -0
- package/dist/src/repository/transfers/DeadlockException.js.map +1 -0
- package/dist/src/repository/transfers/ForeignKeyViolationException.d.ts +20 -0
- package/dist/src/repository/transfers/ForeignKeyViolationException.d.ts.map +1 -0
- package/dist/src/repository/transfers/ForeignKeyViolationException.js +23 -0
- package/dist/src/repository/transfers/ForeignKeyViolationException.js.map +1 -0
- package/dist/src/repository/transfers/NotNullViolationException.d.ts +20 -0
- package/dist/src/repository/transfers/NotNullViolationException.d.ts.map +1 -0
- package/dist/src/repository/transfers/NotNullViolationException.js +23 -0
- package/dist/src/repository/transfers/NotNullViolationException.js.map +1 -0
- package/dist/src/repository/transfers/UniqueViolationException.d.ts +36 -0
- package/dist/src/repository/transfers/UniqueViolationException.d.ts.map +1 -0
- package/dist/src/repository/transfers/UniqueViolationException.js +40 -0
- package/dist/src/repository/transfers/UniqueViolationException.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Israel Sanjurjo and the XF contributors
|
|
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,167 @@
|
|
|
1
|
+
# `@xfcfam/xf-sql`
|
|
2
|
+
|
|
3
|
+
SQL Access Layer Generalization for the **XF Architecture Model**.
|
|
4
|
+
Encapsulates the [Kysely](https://kysely.dev) query builder behind a
|
|
5
|
+
single XF-canonical class plus a typed Exception hierarchy.
|
|
6
|
+
|
|
7
|
+
**Dialect-agnostic.** xf-sql talks to any database for which Kysely
|
|
8
|
+
has a dialect implementation. Pair it with one of the adapter
|
|
9
|
+
packages:
|
|
10
|
+
|
|
11
|
+
- [`@xfcfam/xf-sql-postgres`](https://www.npmjs.com/package/@xfcfam/xf-sql-postgres) — Postgres via `pg`
|
|
12
|
+
- (future) `@xfcfam/xf-sql-mysql`, `@xfcfam/xf-sql-sqlite`, …
|
|
13
|
+
|
|
14
|
+
Or supply any Kysely `Dialect` directly to `DatabaseRepository`.
|
|
15
|
+
|
|
16
|
+
Peer dependency: `@xfcfam/xf`. `kysely` is a direct (bundled) dependency.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add @xfcfam/xf @xfcfam/xf-sql kysely
|
|
22
|
+
# plus one dialect adapter, e.g.
|
|
23
|
+
pnpm add @xfcfam/xf-sql-postgres pg
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## What ships here
|
|
27
|
+
|
|
28
|
+
| Export | Role |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `DatabaseRepository<Schema>` | Access Layer Generalization. Constructor `({ dialect })`. Protected `db: Kysely<Schema>`. `exec(op)` wrapper that funnels errors through `translateError`. Overridable hooks: `onConnected`, `onDisconnected`, `onQuery`, `onError`. |
|
|
31
|
+
| `TransactionalDatabaseRepository<Schema>` | Adds `transaction(callback)` that commits / rolls back the Kysely transaction and translates errors. Overridable hooks: `onTransactionStart`, `onTransactionCommit`, `onTransactionRollback`. |
|
|
32
|
+
| `DatabaseException` | Base class for every typed DB error. |
|
|
33
|
+
| `ConnectionException` | Database unreachable (DNS, refused, TLS, timeout). |
|
|
34
|
+
| `UniqueViolationException` | `UNIQUE` / `PRIMARY KEY` constraint violated. Carries `constraint`, `table`, `column`. |
|
|
35
|
+
| `ForeignKeyViolationException` | `FOREIGN KEY` constraint violated. Carries `constraint`, `table`. |
|
|
36
|
+
| `CheckViolationException` | `CHECK` constraint violated. Carries `constraint`, `table`. |
|
|
37
|
+
| `NotNullViolationException` | `NOT NULL` column set to `NULL`. Carries `table`, `column`. |
|
|
38
|
+
| `DeadlockException` | DB-detected deadlock; typically retryable. |
|
|
39
|
+
|
|
40
|
+
## Quick usage
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { TransactionalDatabaseRepository, UniqueViolationException } from '@xfcfam/xf-sql'
|
|
44
|
+
import { PostgresDialect } from 'kysely'
|
|
45
|
+
import { Pool } from 'pg'
|
|
46
|
+
|
|
47
|
+
interface Schema {
|
|
48
|
+
users: { id: number; name: string; email: string; created_at: Date }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class UsersDb extends TransactionalDatabaseRepository<Schema> {
|
|
52
|
+
constructor() {
|
|
53
|
+
super({
|
|
54
|
+
dialect: new PostgresDialect({
|
|
55
|
+
pool: new Pool({ connectionString: process.env.DATABASE_URL }),
|
|
56
|
+
}),
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
async init() { await super.init() }
|
|
60
|
+
async terminate() { await super.terminate() }
|
|
61
|
+
|
|
62
|
+
getUser(id: number) {
|
|
63
|
+
return this.exec(() =>
|
|
64
|
+
this.db.selectFrom('users').where('id', '=', id).selectAll().executeTakeFirstOrThrow()
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
createUser(input: { name: string; email: string }) {
|
|
69
|
+
return this.exec(() =>
|
|
70
|
+
this.db
|
|
71
|
+
.insertInto('users')
|
|
72
|
+
.values({ ...input, created_at: new Date() })
|
|
73
|
+
.returningAll()
|
|
74
|
+
.executeTakeFirstOrThrow()
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
> The example above uses the generic `DatabaseRepository` with a
|
|
81
|
+
> raw Kysely dialect. In a real project you would typically extend
|
|
82
|
+
> `PostgresDatabaseRepository` from `@xfcfam/xf-sql-postgres`, which
|
|
83
|
+
> wires the dialect and translates Postgres errors automatically.
|
|
84
|
+
|
|
85
|
+
## Batching pattern (deferred writes)
|
|
86
|
+
|
|
87
|
+
When a workload generates many small writes, batching them into a
|
|
88
|
+
single transaction can cut latency and load on the database
|
|
89
|
+
dramatically. xf-sql doesn't ship a dedicated "batch repository" —
|
|
90
|
+
batching is a Business-Layer concern (a policy on **when** to write),
|
|
91
|
+
not a SQL protocol concern. Compose the building blocks:
|
|
92
|
+
|
|
93
|
+
- **`BatchedBusiness<T>`** from `@xfcfam/xf` accumulates items in
|
|
94
|
+
memory and flushes them by size, by time, manually or on terminate.
|
|
95
|
+
Dialect-agnostic — works with Postgres, MySQL, SQLite, anything.
|
|
96
|
+
- **`TransactionalDatabaseRepository`** in the consumer's Access
|
|
97
|
+
Layer executes the flush as a single transaction.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { BatchedBusiness } from '@xfcfam/xf'
|
|
101
|
+
import { R } from '../R.js' // your Access injection
|
|
102
|
+
|
|
103
|
+
interface AuditEvent { actor: string; action: string; at: Date }
|
|
104
|
+
|
|
105
|
+
export class AuditBatchBusiness extends BatchedBusiness<AuditEvent> {
|
|
106
|
+
constructor() {
|
|
107
|
+
super({
|
|
108
|
+
maxSize: 500, // flush when 500 events queued, OR
|
|
109
|
+
maxAgeMs: 5_000, // every 5 seconds, whichever comes first
|
|
110
|
+
onErrorPolicy: 'retain',
|
|
111
|
+
flush: batch => R.auditDb.recordMany(batch), // single TX on the receiving Repository
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
record(event: AuditEvent) { this.add(event) }
|
|
116
|
+
|
|
117
|
+
protected override onFlushStart(batch: readonly AuditEvent[], reason) {
|
|
118
|
+
console.log(`[audit] flushing ${batch.length} events (${reason})`)
|
|
119
|
+
}
|
|
120
|
+
protected override onFlushError(batch, err) {
|
|
121
|
+
console.error(`[audit] flush failed, ${batch.length} events retained`, err)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
And on the receiving Repository:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { TransactionalDatabaseRepository } from '@xfcfam/xf-sql'
|
|
130
|
+
|
|
131
|
+
export class AuditDb extends TransactionalDatabaseRepository<Schema> {
|
|
132
|
+
recordMany(batch: readonly AuditEvent[]) {
|
|
133
|
+
return this.transaction(async (trx) => {
|
|
134
|
+
await trx.insertInto('audit').values([...batch]).execute()
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
This pattern is **fully compatible across dialects** — `AuditBatchBusiness`
|
|
141
|
+
doesn't know whether the target is Postgres, MySQL or SQLite. Swap the
|
|
142
|
+
dialect adapter, the business component stays unchanged.
|
|
143
|
+
|
|
144
|
+
## Error translation
|
|
145
|
+
|
|
146
|
+
xf-sql defines the Exception types but **does not translate driver
|
|
147
|
+
errors itself** — it doesn't know about Postgres SQLSTATEs or MySQL
|
|
148
|
+
error numbers. Either:
|
|
149
|
+
|
|
150
|
+
- Use a dialect adapter (e.g. `PostgresDatabaseRepository`) that
|
|
151
|
+
overrides `translateError` for you, **or**
|
|
152
|
+
- Override `translateError(err)` in your own subclass and map the
|
|
153
|
+
driver's error shape to the `*Exception` types above.
|
|
154
|
+
|
|
155
|
+
Wrap queries in `this.exec(() => …)` so the translation runs.
|
|
156
|
+
Transactions are wrapped automatically by
|
|
157
|
+
`TransactionalDatabaseRepository.transaction`.
|
|
158
|
+
|
|
159
|
+
## Documentation
|
|
160
|
+
|
|
161
|
+
- Specification — [xfcfam.org](https://xfcfam.org)
|
|
162
|
+
- Kysely docs — [kysely.dev](https://kysely.dev)
|
|
163
|
+
- Source — [github.com/xfcfam/lib-npm](https://github.com/xfcfam/lib-npm)
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@xfcfam/xf-sql` — SQL Access Layer Generalization for the XF
|
|
3
|
+
* Architecture Model.
|
|
4
|
+
*
|
|
5
|
+
* Encapsulates the [Kysely](https://kysely.dev) query builder behind
|
|
6
|
+
* an XF-canonical Generalization (`DatabaseRepository`) plus a
|
|
7
|
+
* transaction-aware specialisation (`TransactionalDatabaseRepository`)
|
|
8
|
+
* and a typed Exception hierarchy.
|
|
9
|
+
*
|
|
10
|
+
* xf-sql is **dialect-agnostic**: pair it with one of the dialect
|
|
11
|
+
* adapter packages (`@xfcfam/xf-sql-postgres`,
|
|
12
|
+
* `@xfcfam/xf-sql-mysql`, …) or supply any Kysely `Dialect` directly.
|
|
13
|
+
*
|
|
14
|
+
* Peer dependency: `@xfcfam/xf`. `kysely` is a direct (bundled) dependency.
|
|
15
|
+
*/
|
|
16
|
+
export { DatabaseRepository } from './src/repository/general/DatabaseRepository.js';
|
|
17
|
+
export type { DatabaseOptions } from './src/repository/general/DatabaseRepository.js';
|
|
18
|
+
export { TransactionalDatabaseRepository } from './src/repository/general/TransactionalDatabaseRepository.js';
|
|
19
|
+
export { DatabaseException } from './src/repository/transfers/DatabaseException.js';
|
|
20
|
+
export { ConnectionException } from './src/repository/transfers/ConnectionException.js';
|
|
21
|
+
export { UniqueViolationException } from './src/repository/transfers/UniqueViolationException.js';
|
|
22
|
+
export { ForeignKeyViolationException } from './src/repository/transfers/ForeignKeyViolationException.js';
|
|
23
|
+
export { CheckViolationException } from './src/repository/transfers/CheckViolationException.js';
|
|
24
|
+
export { NotNullViolationException } from './src/repository/transfers/NotNullViolationException.js';
|
|
25
|
+
export { DeadlockException } from './src/repository/transfers/DeadlockException.js';
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AACnF,YAAY,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAA;AACrF,OAAO,EAAE,+BAA+B,EAAE,MAAM,6DAA6D,CAAA;AAG7G,OAAO,EAAE,iBAAiB,EAAE,MAAiB,iDAAiD,CAAA;AAC9F,OAAO,EAAE,mBAAmB,EAAE,MAAe,mDAAmD,CAAA;AAChG,OAAO,EAAE,wBAAwB,EAAE,MAAU,wDAAwD,CAAA;AACrG,OAAO,EAAE,4BAA4B,EAAE,MAAM,4DAA4D,CAAA;AACzG,OAAO,EAAE,uBAAuB,EAAE,MAAW,uDAAuD,CAAA;AACpG,OAAO,EAAE,yBAAyB,EAAE,MAAS,yDAAyD,CAAA;AACtG,OAAO,EAAE,iBAAiB,EAAE,MAAiB,iDAAiD,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@xfcfam/xf-sql` — SQL Access Layer Generalization for the XF
|
|
3
|
+
* Architecture Model.
|
|
4
|
+
*
|
|
5
|
+
* Encapsulates the [Kysely](https://kysely.dev) query builder behind
|
|
6
|
+
* an XF-canonical Generalization (`DatabaseRepository`) plus a
|
|
7
|
+
* transaction-aware specialisation (`TransactionalDatabaseRepository`)
|
|
8
|
+
* and a typed Exception hierarchy.
|
|
9
|
+
*
|
|
10
|
+
* xf-sql is **dialect-agnostic**: pair it with one of the dialect
|
|
11
|
+
* adapter packages (`@xfcfam/xf-sql-postgres`,
|
|
12
|
+
* `@xfcfam/xf-sql-mysql`, …) or supply any Kysely `Dialect` directly.
|
|
13
|
+
*
|
|
14
|
+
* Peer dependency: `@xfcfam/xf`. `kysely` is a direct (bundled) dependency.
|
|
15
|
+
*/
|
|
16
|
+
// ── Access — base ─────────────────────────────────────────
|
|
17
|
+
export { DatabaseRepository } from './src/repository/general/DatabaseRepository.js';
|
|
18
|
+
export { TransactionalDatabaseRepository } from './src/repository/general/TransactionalDatabaseRepository.js';
|
|
19
|
+
// ── Access — structs (Exceptions) ─────────────────────────
|
|
20
|
+
export { DatabaseException } from './src/repository/transfers/DatabaseException.js';
|
|
21
|
+
export { ConnectionException } from './src/repository/transfers/ConnectionException.js';
|
|
22
|
+
export { UniqueViolationException } from './src/repository/transfers/UniqueViolationException.js';
|
|
23
|
+
export { ForeignKeyViolationException } from './src/repository/transfers/ForeignKeyViolationException.js';
|
|
24
|
+
export { CheckViolationException } from './src/repository/transfers/CheckViolationException.js';
|
|
25
|
+
export { NotNullViolationException } from './src/repository/transfers/NotNullViolationException.js';
|
|
26
|
+
export { DeadlockException } from './src/repository/transfers/DeadlockException.js';
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,6DAA6D;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAEnF,OAAO,EAAE,+BAA+B,EAAE,MAAM,6DAA6D,CAAA;AAE7G,6DAA6D;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAiB,iDAAiD,CAAA;AAC9F,OAAO,EAAE,mBAAmB,EAAE,MAAe,mDAAmD,CAAA;AAChG,OAAO,EAAE,wBAAwB,EAAE,MAAU,wDAAwD,CAAA;AACrG,OAAO,EAAE,4BAA4B,EAAE,MAAM,4DAA4D,CAAA;AACzG,OAAO,EAAE,uBAAuB,EAAE,MAAW,uDAAuD,CAAA;AACpG,OAAO,EAAE,yBAAyB,EAAE,MAAS,yDAAyD,CAAA;AACtG,OAAO,EAAE,iBAAiB,EAAE,MAAiB,iDAAiD,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction Layer Injection — placeholder.
|
|
3
|
+
*
|
|
4
|
+
* `A` is the canonical injection of the Interaction Layer. `@xfcfam/xf-sql`
|
|
5
|
+
* is a library that contributes Generalizations and Transfer objects;
|
|
6
|
+
* it does not own any Logical of this layer, so its own `A` declares
|
|
7
|
+
* no static slots. The class is kept structurally complete (private
|
|
8
|
+
* constructor + empty `init` / `terminate`) so the artefact passes XF
|
|
9
|
+
* validation. It is NOT exported from the package — consumers import
|
|
10
|
+
* `A` from their own artefact.
|
|
11
|
+
*/
|
|
12
|
+
export declare class A {
|
|
13
|
+
private constructor();
|
|
14
|
+
static init(): Promise<void>;
|
|
15
|
+
static terminate(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=A.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"A.d.ts","sourceRoot":"","sources":["../../../src/api/A.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,qBAAa,CAAC;IACZ,OAAO;WACM,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;WACrB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CACxC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction Layer Injection — placeholder.
|
|
3
|
+
*
|
|
4
|
+
* `A` is the canonical injection of the Interaction Layer. `@xfcfam/xf-sql`
|
|
5
|
+
* is a library that contributes Generalizations and Transfer objects;
|
|
6
|
+
* it does not own any Logical of this layer, so its own `A` declares
|
|
7
|
+
* no static slots. The class is kept structurally complete (private
|
|
8
|
+
* constructor + empty `init` / `terminate`) so the artefact passes XF
|
|
9
|
+
* validation. It is NOT exported from the package — consumers import
|
|
10
|
+
* `A` from their own artefact.
|
|
11
|
+
*/
|
|
12
|
+
export class A {
|
|
13
|
+
constructor() { }
|
|
14
|
+
static async init() { }
|
|
15
|
+
static async terminate() { }
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=A.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"A.js","sourceRoot":"","sources":["../../../src/api/A.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,CAAC;IACZ,gBAAuB,CAAC;IACxB,MAAM,CAAC,KAAK,CAAC,IAAI,KAAmB,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,SAAS,KAAmB,CAAC;CAC3C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Layer Injection — placeholder.
|
|
3
|
+
*
|
|
4
|
+
* `B` is the canonical injection of the Business Layer. `@xfcfam/xf-sql`
|
|
5
|
+
* is a library that contributes Generalizations and Transfer objects;
|
|
6
|
+
* it does not own any Logical of this layer, so its own `B` declares
|
|
7
|
+
* no static slots. The class is kept structurally complete (private
|
|
8
|
+
* constructor + empty `init` / `terminate`) so the artefact passes XF
|
|
9
|
+
* validation. It is NOT exported from the package — consumers import
|
|
10
|
+
* `B` from their own artefact.
|
|
11
|
+
*/
|
|
12
|
+
export declare class B {
|
|
13
|
+
private constructor();
|
|
14
|
+
static init(): Promise<void>;
|
|
15
|
+
static terminate(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=B.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"B.d.ts","sourceRoot":"","sources":["../../../src/business/B.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,qBAAa,CAAC;IACZ,OAAO;WACM,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;WACrB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CACxC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Layer Injection — placeholder.
|
|
3
|
+
*
|
|
4
|
+
* `B` is the canonical injection of the Business Layer. `@xfcfam/xf-sql`
|
|
5
|
+
* is a library that contributes Generalizations and Transfer objects;
|
|
6
|
+
* it does not own any Logical of this layer, so its own `B` declares
|
|
7
|
+
* no static slots. The class is kept structurally complete (private
|
|
8
|
+
* constructor + empty `init` / `terminate`) so the artefact passes XF
|
|
9
|
+
* validation. It is NOT exported from the package — consumers import
|
|
10
|
+
* `B` from their own artefact.
|
|
11
|
+
*/
|
|
12
|
+
export class B {
|
|
13
|
+
constructor() { }
|
|
14
|
+
static async init() { }
|
|
15
|
+
static async terminate() { }
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"B.js","sourceRoot":"","sources":["../../../src/business/B.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,CAAC;IACZ,gBAAuB,CAAC;IACxB,MAAM,CAAC,KAAK,CAAC,IAAI,KAAmB,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,SAAS,KAAmB,CAAC;CAC3C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access Layer Injection — placeholder.
|
|
3
|
+
*
|
|
4
|
+
* `R` is the canonical injection of the Access Layer. `@xfcfam/xf-sql`
|
|
5
|
+
* is a library that contributes Generalizations and Transfer objects;
|
|
6
|
+
* it does not own any Logical of this layer, so its own `R` declares
|
|
7
|
+
* no static slots. The class is kept structurally complete (private
|
|
8
|
+
* constructor + empty `init` / `terminate`) so the artefact passes XF
|
|
9
|
+
* validation. It is NOT exported from the package — consumers import
|
|
10
|
+
* `R` from their own artefact.
|
|
11
|
+
*/
|
|
12
|
+
export declare class R {
|
|
13
|
+
private constructor();
|
|
14
|
+
static init(): Promise<void>;
|
|
15
|
+
static terminate(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=R.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"R.d.ts","sourceRoot":"","sources":["../../../src/repository/R.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,qBAAa,CAAC;IACZ,OAAO;WACM,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;WACrB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CACxC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access Layer Injection — placeholder.
|
|
3
|
+
*
|
|
4
|
+
* `R` is the canonical injection of the Access Layer. `@xfcfam/xf-sql`
|
|
5
|
+
* is a library that contributes Generalizations and Transfer objects;
|
|
6
|
+
* it does not own any Logical of this layer, so its own `R` declares
|
|
7
|
+
* no static slots. The class is kept structurally complete (private
|
|
8
|
+
* constructor + empty `init` / `terminate`) so the artefact passes XF
|
|
9
|
+
* validation. It is NOT exported from the package — consumers import
|
|
10
|
+
* `R` from their own artefact.
|
|
11
|
+
*/
|
|
12
|
+
export class R {
|
|
13
|
+
constructor() { }
|
|
14
|
+
static async init() { }
|
|
15
|
+
static async terminate() { }
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"R.js","sourceRoot":"","sources":["../../../src/repository/R.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,CAAC;IACZ,gBAAuB,CAAC;IACxB,MAAM,CAAC,KAAK,CAAC,IAAI,KAAmB,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,SAAS,KAAmB,CAAC;CAC3C"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { Repository } from '@xfarch/xf';
|
|
2
|
+
import { Kysely, type Dialect } from 'kysely';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration accepted by {@link DatabaseRepository}'s constructor.
|
|
5
|
+
*
|
|
6
|
+
* The `dialect` is the only required field. Dialect adapter packages
|
|
7
|
+
* such as `@xfarch/xf-sql-postgres` build it for you behind a
|
|
8
|
+
* higher-level options shape.
|
|
9
|
+
*/
|
|
10
|
+
export interface DatabaseOptions {
|
|
11
|
+
/** Kysely Dialect implementation (Postgres, MySQL, SQLite, …). */
|
|
12
|
+
dialect: Dialect;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Base Generalization for the Access Layer when the underlying
|
|
16
|
+
* external system is a SQL database.
|
|
17
|
+
*
|
|
18
|
+
* Encapsulates the [Kysely](https://kysely.dev) query builder behind
|
|
19
|
+
* a single XF-canonical class. The implementer's concrete Logical
|
|
20
|
+
* extends this (or a dialect-specific subclass such as
|
|
21
|
+
* `PostgresDatabaseRepository`) and exposes domain-meaningful methods
|
|
22
|
+
* that compose queries against `this.db`, a `Kysely<Schema>` bound
|
|
23
|
+
* to the implementer's typed schema.
|
|
24
|
+
*
|
|
25
|
+
* Concrete dialect support lives in adapter packages — install one of
|
|
26
|
+
* `@xfarch/xf-sql-postgres`, `@xfarch/xf-sql-mysql`, etc., or supply
|
|
27
|
+
* any Kysely-compatible `Dialect` directly.
|
|
28
|
+
*
|
|
29
|
+
* ──────────────────────────────────────────────────────────────────
|
|
30
|
+
* IMPORTANT — Required configuration for subclasses
|
|
31
|
+
* ──────────────────────────────────────────────────────────────────
|
|
32
|
+
* The underlying Kysely instance is held in a static private WeakMap
|
|
33
|
+
* and created inside {@link init}. If a subclass overrides `init()` /
|
|
34
|
+
* `terminate()`, it MUST chain through `super`:
|
|
35
|
+
*
|
|
36
|
+
* async init() { await super.init(); // own setup }
|
|
37
|
+
* async terminate() { // own teardown; await super.terminate() }
|
|
38
|
+
*
|
|
39
|
+
* Forgetting `super.init()` leaves `this.db` uninitialised and every
|
|
40
|
+
* query will throw {@link NotInitializedException}.
|
|
41
|
+
*
|
|
42
|
+
* ──────────────────────────────────────────────────────────────────
|
|
43
|
+
* Overridable observation hooks
|
|
44
|
+
* ──────────────────────────────────────────────────────────────────
|
|
45
|
+
* - {@link onConnected} ← after `init()` creates the Kysely instance
|
|
46
|
+
* - {@link onDisconnected} ← after `terminate()` destroys it
|
|
47
|
+
* - {@link onQuery} ← for every query Kysely executes
|
|
48
|
+
* - {@link onError} ← for every {@link exec}-wrapped operation that rejects
|
|
49
|
+
*
|
|
50
|
+
* Transaction hooks ({@link onTransactionStart} / Commit / Rollback)
|
|
51
|
+
* live on {@link TransactionalDatabaseRepository}, the subclass that
|
|
52
|
+
* exposes explicit transaction control.
|
|
53
|
+
*
|
|
54
|
+
* ──────────────────────────────────────────────────────────────────
|
|
55
|
+
* Error translation
|
|
56
|
+
* ──────────────────────────────────────────────────────────────────
|
|
57
|
+
* Dialect-specific errors (driver Error objects) are not translated
|
|
58
|
+
* by this class — it does not know about Postgres SQLSTATEs, MySQL
|
|
59
|
+
* error numbers, etc. Use a dialect adapter subclass (such as
|
|
60
|
+
* `PostgresDatabaseRepository`) or override {@link translateError}
|
|
61
|
+
* yourself to map errors to the typed Exceptions exported from this
|
|
62
|
+
* package (`UniqueViolationException`, etc.).
|
|
63
|
+
*
|
|
64
|
+
* @typeParam Schema Implementer-defined TypeScript interface mapping
|
|
65
|
+
* table names to their column shapes. See the
|
|
66
|
+
* Kysely docs for the conventions on
|
|
67
|
+
* `Generated`, `ColumnType`, etc.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* import { DatabaseRepository } from '@xfarch/xf-sql'
|
|
72
|
+
* import { PostgresDialect } from 'kysely'
|
|
73
|
+
* import { Pool } from 'pg'
|
|
74
|
+
*
|
|
75
|
+
* interface Schema {
|
|
76
|
+
* users: { id: number; name: string; email: string }
|
|
77
|
+
* }
|
|
78
|
+
*
|
|
79
|
+
* export class UsersDb extends DatabaseRepository<Schema> {
|
|
80
|
+
* constructor() {
|
|
81
|
+
* super({
|
|
82
|
+
* dialect: new PostgresDialect({
|
|
83
|
+
* pool: new Pool({ connectionString: process.env.DATABASE_URL }),
|
|
84
|
+
* }),
|
|
85
|
+
* })
|
|
86
|
+
* }
|
|
87
|
+
* async init() { await super.init() }
|
|
88
|
+
* async terminate() { await super.terminate() }
|
|
89
|
+
*
|
|
90
|
+
* getUser(id: number) {
|
|
91
|
+
* return this.db
|
|
92
|
+
* .selectFrom('users')
|
|
93
|
+
* .where('id', '=', id)
|
|
94
|
+
* .selectAll()
|
|
95
|
+
* .executeTakeFirstOrThrow()
|
|
96
|
+
* }
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export declare abstract class DatabaseRepository<Schema = unknown> extends Repository<null> {
|
|
101
|
+
private static readonly state;
|
|
102
|
+
/** Options provided at construction time. */
|
|
103
|
+
protected readonly options: DatabaseOptions;
|
|
104
|
+
constructor(options: DatabaseOptions);
|
|
105
|
+
/**
|
|
106
|
+
* Typed Kysely instance bound to `Schema`. Use it to compose queries:
|
|
107
|
+
* `this.db.selectFrom('users')…`, `this.db.insertInto('users')…`.
|
|
108
|
+
* Throws if {@link init} has not been called.
|
|
109
|
+
*/
|
|
110
|
+
protected get db(): Kysely<Schema>;
|
|
111
|
+
/**
|
|
112
|
+
* Subclasses that override this method MUST call `await super.init()`
|
|
113
|
+
* **first**; otherwise {@link db} will throw on use.
|
|
114
|
+
*/
|
|
115
|
+
init(): Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* Subclasses that override this method MUST call `await super.terminate()`
|
|
118
|
+
* **last** to release the connection pool held by the Kysely instance.
|
|
119
|
+
*/
|
|
120
|
+
terminate(): Promise<void>;
|
|
121
|
+
/**
|
|
122
|
+
* Hook for dialect-specific error translation. Default
|
|
123
|
+
* implementation is identity (returns the input unchanged).
|
|
124
|
+
*
|
|
125
|
+
* Dialect adapter subclasses (such as `PostgresDatabaseRepository`)
|
|
126
|
+
* override this to map driver errors to the typed Exceptions
|
|
127
|
+
* exported from this package.
|
|
128
|
+
*
|
|
129
|
+
* Called automatically by {@link exec}; not called for direct
|
|
130
|
+
* `this.db.…` usage, where the implementer is responsible for
|
|
131
|
+
* wrapping queries in `this.exec(...)`.
|
|
132
|
+
*/
|
|
133
|
+
protected translateError(err: unknown): unknown;
|
|
134
|
+
/**
|
|
135
|
+
* Execute an operation against the database, translating any
|
|
136
|
+
* dialect-specific errors to xf-sql Exception types via
|
|
137
|
+
* {@link translateError}.
|
|
138
|
+
*
|
|
139
|
+
* Use this whenever you need automatic error translation. For raw
|
|
140
|
+
* Kysely access without translation, use {@link db} directly.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts
|
|
144
|
+
* async createUser(input: UserInput) {
|
|
145
|
+
* return this.exec(() =>
|
|
146
|
+
* this.db.insertInto('users').values(input).returningAll().executeTakeFirstOrThrow()
|
|
147
|
+
* )
|
|
148
|
+
* }
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
protected exec<R>(op: () => Promise<R>): Promise<R>;
|
|
152
|
+
/**
|
|
153
|
+
* Invoked after `init()` has created the Kysely instance. Default
|
|
154
|
+
* no-op. Override for connection-open telemetry, schema migrations,
|
|
155
|
+
* connection warmup, etc.
|
|
156
|
+
*/
|
|
157
|
+
protected onConnected(): Promise<void>;
|
|
158
|
+
/**
|
|
159
|
+
* Invoked after `terminate()` has destroyed the Kysely instance.
|
|
160
|
+
* Default no-op. Override for connection-close telemetry.
|
|
161
|
+
*/
|
|
162
|
+
protected onDisconnected(): Promise<void>;
|
|
163
|
+
/**
|
|
164
|
+
* Invoked for every query Kysely executes (both standalone and
|
|
165
|
+
* inside transactions). Receives the compiled SQL and the bound
|
|
166
|
+
* parameters. Default no-op.
|
|
167
|
+
*
|
|
168
|
+
* Use for audit logging or query profiling. The hook runs
|
|
169
|
+
* synchronously inside Kysely's pipeline — keep it cheap and avoid
|
|
170
|
+
* blocking work.
|
|
171
|
+
*/
|
|
172
|
+
protected onQuery(_sql: string, _params: readonly unknown[]): void;
|
|
173
|
+
/**
|
|
174
|
+
* Invoked when an `exec()`-wrapped operation rejects, or when
|
|
175
|
+
* Kysely emits a query-level error. The `operation` label
|
|
176
|
+
* distinguishes the source (`'exec'`, `'query'`, or the value
|
|
177
|
+
* supplied by a subclass). Default no-op.
|
|
178
|
+
*
|
|
179
|
+
* The hook fires before {@link translateError}; the (possibly
|
|
180
|
+
* untranslated) error is still re-thrown to the caller.
|
|
181
|
+
*/
|
|
182
|
+
protected onError(_operation: string, _error: unknown): void;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=DatabaseRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatabaseRepository.d.ts","sourceRoot":"","sources":["../../../../src/repository/base/DatabaseRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAA;AAChE,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAA;AAE7C;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,OAAO,EAAE,OAAO,CAAA;CACjB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;AACH,8BAAsB,kBAAkB,CAAC,MAAM,GAAG,OAAO,CAAE,SAAQ,UAAU,CAAC,IAAI,CAAC;IACjF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAuC;IAEpE,6CAA6C;IAC7C,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;gBAE/B,OAAO,EAAE,eAAe;IAKpC;;;;OAIG;IACH,SAAS,KAAK,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,CAMjC;IAED;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB3B;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAShC;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAI/C;;;;;;;;;;;;;;;;OAgBG;cACa,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAWzD;;;;OAIG;cACa,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAE5C;;;OAGG;cACa,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAE/C;;;;;;;;OAQG;IACH,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI;IAElE;;;;;;;;OAQG;IACH,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;CAC7D"}
|