fhir-persistence 0.1.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 +109 -1
- package/README.md +47 -14
- package/dist/cjs/index.cjs +413 -284
- package/dist/cjs/index.cjs.map +4 -4
- package/dist/cjs/index.d.ts +191 -40
- package/dist/esm/index.d.ts +191 -40
- package/dist/esm/index.mjs +410 -283
- package/dist/esm/index.mjs.map +4 -4
- package/dist/index.d.ts +191 -40
- package/dist/lib/db/adapter.d.ts +4 -4
- package/dist/lib/db/adapter.d.ts.map +1 -1
- package/dist/lib/db/index.d.ts +1 -2
- package/dist/lib/db/index.d.ts.map +1 -1
- package/dist/lib/db/postgres-adapter.d.ts +1 -19
- package/dist/lib/db/postgres-adapter.d.ts.map +1 -1
- package/dist/lib/index.d.ts +4 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/migration/reindex-scheduler.d.ts +3 -1
- package/dist/lib/migration/reindex-scheduler.d.ts.map +1 -1
- package/dist/lib/migrations/migration-runner.d.ts +3 -1
- package/dist/lib/migrations/migration-runner.d.ts.map +1 -1
- package/dist/lib/registry/package-registry-repo.d.ts +7 -1
- package/dist/lib/registry/package-registry-repo.d.ts.map +1 -1
- package/dist/lib/repo/indexing-pipeline.d.ts +3 -0
- package/dist/lib/repo/indexing-pipeline.d.ts.map +1 -1
- package/dist/lib/repo/lookup-table-writer.d.ts +3 -1
- package/dist/lib/repo/lookup-table-writer.d.ts.map +1 -1
- package/dist/lib/search/search-executor.d.ts +4 -1
- package/dist/lib/search/search-executor.d.ts.map +1 -1
- package/dist/lib/search/search-sql-builder.d.ts +4 -3
- package/dist/lib/search/search-sql-builder.d.ts.map +1 -1
- package/dist/lib/search/where-builder.d.ts +7 -7
- package/dist/lib/search/where-builder.d.ts.map +1 -1
- package/dist/lib/startup/fhir-system.d.ts.map +1 -1
- package/dist/lib/terminology/valueset-repo.d.ts +3 -1
- package/dist/lib/terminology/valueset-repo.d.ts.map +1 -1
- package/package.json +12 -3
- package/dist/lib/db/sqlite-adapter.d.ts +0 -41
- package/dist/lib/db/sqlite-adapter.d.ts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,17 +5,118 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.0] - 2025-03-15
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
#### PostgreSQL DDL Compatibility (Phase D)
|
|
13
|
+
|
|
14
|
+
- **`migration-runner.ts`** — Tracking table `_migrations` now uses `TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP` on PostgreSQL instead of SQLite-only `datetime('now')`
|
|
15
|
+
- **`package-registry-repo.ts`** — `_packages` and `_schema_version` tables use dialect-aware timestamp defaults; `INSERT OR REPLACE` replaced with `INSERT ... ON CONFLICT ... DO UPDATE` on PostgreSQL
|
|
16
|
+
- **`reindex-scheduler.ts`** — `_reindex_jobs` table uses `SERIAL PRIMARY KEY` on PostgreSQL instead of `AUTOINCREMENT`; `datetime('now')` replaced with `CURRENT_TIMESTAMP`
|
|
17
|
+
- **`valueset-repo.ts`** — `terminology_valuesets` table uses dialect-aware timestamp defaults; `INSERT OR REPLACE` replaced with `INSERT ... ON CONFLICT ... DO UPDATE` on PostgreSQL
|
|
18
|
+
- **`lookup-table-writer.ts`** — 4 global lookup tables (`HumanName`, `Address`, `ContactPoint`, `Identifier`) use `SERIAL PRIMARY KEY` on PostgreSQL instead of `AUTOINCREMENT`
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **`ig-persistence-manager.ts`** — Now passes `dialect` to `PackageRegistryRepo`, `MigrationRunnerV2`, and `ReindexScheduler` constructors
|
|
23
|
+
- **`indexing-pipeline.ts`** — `IndexingPipelineOptions` accepts `dialect` parameter, passed to `LookupTableWriter`
|
|
24
|
+
- **`fhir-system.ts`** — Passes `dialect` through to `IndexingPipeline` via `FhirPersistence` options
|
|
25
|
+
- All new `dialect` parameters default to `'sqlite'` — fully backward-compatible
|
|
26
|
+
|
|
27
|
+
### Test Coverage
|
|
28
|
+
|
|
29
|
+
- **1014 total tests** (1006 passing, 8 skipped) across 56 test files — no regressions
|
|
30
|
+
|
|
31
|
+
## [0.3.0] - 2025-03-15
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
#### Dual-Backend Validation
|
|
36
|
+
|
|
37
|
+
- Comprehensive dual-backend test suite (`dual-backend-validation.test.ts`) — 41 tests covering SQLite and PostgreSQL
|
|
38
|
+
- **Schema DDL correctness** — generate and execute DDL on both backends, verify tables/columns/indexes
|
|
39
|
+
- **IG lifecycle validation** — `compareSchemas` → `generateMigration` → apply migration on both backends
|
|
40
|
+
- **CRUD correctness** — `FhirStore` create/read/update/delete/history/vread on both SQLite and PostgreSQL
|
|
41
|
+
- Transaction atomicity verification on PostgreSQL
|
|
42
|
+
- Optimistic locking (`ifMatch`) verification on both backends
|
|
43
|
+
- History auto-increment `versionSeq` verification on PostgreSQL
|
|
44
|
+
|
|
45
|
+
#### PostgreSQL Integration Tests
|
|
46
|
+
|
|
47
|
+
- 23 PostgreSQL integration tests (`postgres-adapter.integration.test.ts`) covering CRUD, transactions, DDL generation, migrations, search SQL generation, concurrency, streaming, and NULL handling
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- `buildTableSet` helper now accepts parameterized `resourceType` for test isolation (unique constraint/index names per test run)
|
|
52
|
+
- Schema DDL comparison tests verify CREATE TABLE count parity rather than exact statement count (SQLite generates extra AUTOINCREMENT index)
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- PostgreSQL test isolation — unique resource type names per run prevent constraint/index name collisions across test runs
|
|
57
|
+
|
|
58
|
+
### Test Coverage
|
|
59
|
+
|
|
60
|
+
- **1014 total tests** (1006 passing, 8 skipped) across 56 test files
|
|
61
|
+
- Full CRUD verified on both SQLite (in-memory) and PostgreSQL (localhost:5433)
|
|
62
|
+
|
|
63
|
+
## [0.2.0] - 2025-03-15
|
|
64
|
+
|
|
65
|
+
### Added
|
|
66
|
+
|
|
67
|
+
#### PostgreSQL Support
|
|
68
|
+
|
|
69
|
+
- `PostgresAdapter` — full `StorageAdapter` implementation for PostgreSQL via `pg` Pool
|
|
70
|
+
- Automatic `?` → `$1, $2, ...` placeholder rewriting
|
|
71
|
+
- Transaction support via pool client + BEGIN/COMMIT/ROLLBACK
|
|
72
|
+
- `queryStream` via cursor-like row iteration
|
|
73
|
+
- Serialization failure retry (40001) with exponential backoff
|
|
74
|
+
- `close()` guard preventing use-after-close
|
|
75
|
+
- `PostgresDialect` — `SqlDialect` implementation for PostgreSQL
|
|
76
|
+
- Native `TEXT[]` array operators (`&&`, `@>`) instead of `json_each()`
|
|
77
|
+
- `GENERATED ALWAYS AS IDENTITY` for history sequence columns
|
|
78
|
+
- PostgreSQL-native type mappings (TIMESTAMPTZ, TEXT[], BOOLEAN, etc.)
|
|
79
|
+
- 23 PostgreSQL integration tests covering CRUD, transactions, DDL, migrations, search SQL, concurrency, streaming, and NULL handling
|
|
80
|
+
|
|
81
|
+
#### SQL Dialect Abstraction
|
|
82
|
+
|
|
83
|
+
- `SqlDialect` interface — abstracts SQL syntax differences between SQLite and PostgreSQL
|
|
84
|
+
- `SQLiteDialect` — `SqlDialect` implementation for SQLite (json_each, AUTOINCREMENT)
|
|
85
|
+
- Dialect-aware WHERE builders: `arrayContainsV2`, `arrayNotContainsV2`, `arrayContainsLikeV2`
|
|
86
|
+
- `buildWhereFragmentV2`, `buildWhereClauseV2` now accept optional `dialect` parameter
|
|
87
|
+
- `buildSearchSQLv2`, `buildCountSQLv2`, `buildTwoPhaseSearchSQLv2` accept optional `dialect`
|
|
88
|
+
- `executeSearchV2` accepts `dialect` via options
|
|
89
|
+
- Compartment filters are dialect-aware (json_each for SQLite, ARRAY operators for PostgreSQL)
|
|
90
|
+
|
|
91
|
+
### Changed
|
|
92
|
+
|
|
93
|
+
- `TransactionContext` methods (`execute`, `query`, `queryOne`) are now `async` (Promise-based)
|
|
94
|
+
- All transaction callers updated to `await` transaction operations
|
|
95
|
+
- `BetterSqlite3Adapter` transaction wraps sync operations in async interface
|
|
96
|
+
|
|
97
|
+
### Removed
|
|
98
|
+
|
|
99
|
+
- `sql.js` WASM adapter (`SQLiteAdapter`) — replaced by `BetterSqlite3Adapter`
|
|
100
|
+
- `sql.js` dependency removed from `package.json`
|
|
101
|
+
|
|
102
|
+
### Dependencies
|
|
103
|
+
|
|
104
|
+
- `pg` ^8.0.0 added as optional peer dependency
|
|
105
|
+
- `pg` ^8.20.0, `@types/pg` ^8.18.0 added as dev dependencies
|
|
106
|
+
|
|
8
107
|
## [0.1.0] - 2025-03-13
|
|
9
108
|
|
|
10
109
|
### Added
|
|
11
110
|
|
|
12
111
|
#### Storage Layer
|
|
112
|
+
|
|
13
113
|
- `StorageAdapter` interface — unified async database abstraction
|
|
14
114
|
- `SQLiteAdapter` — sql.js (WASM) implementation for cross-platform use
|
|
15
115
|
- `BetterSqlite3Adapter` — native better-sqlite3 implementation for production Node.js
|
|
16
116
|
- `SQLiteDialect` / PostgreSQL dialect support for DDL generation
|
|
17
117
|
|
|
18
118
|
#### CRUD & Persistence
|
|
119
|
+
|
|
19
120
|
- `FhirStore` — basic CRUD with soft delete and version tracking
|
|
20
121
|
- `FhirPersistence` — end-to-end facade with automatic search indexing
|
|
21
122
|
- `ConditionalService` — conditionalCreate / conditionalUpdate / conditionalDelete
|
|
@@ -24,6 +125,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
24
125
|
- History tracking via dedicated `_History` tables
|
|
25
126
|
|
|
26
127
|
#### Search
|
|
128
|
+
|
|
27
129
|
- `SearchParameterRegistry` — index FHIR SearchParameter bundles
|
|
28
130
|
- `parseSearchRequest` — parse FHIR search URL query parameters
|
|
29
131
|
- `buildSearchSQLv2` — generate SQL with `?` placeholders (SQLite + PG compatible)
|
|
@@ -34,6 +136,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
34
136
|
- `SearchBundleBuilder` — FHIR Bundle response construction with pagination
|
|
35
137
|
|
|
36
138
|
#### Indexing
|
|
139
|
+
|
|
37
140
|
- `IndexingPipeline` — automatic search column population on CRUD
|
|
38
141
|
- `RuntimeProvider` bridge — FHIRPath-driven extraction via `fhir-runtime`
|
|
39
142
|
- `buildSearchColumns` — fallback property-path extraction
|
|
@@ -42,6 +145,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
42
145
|
- Column strategy, token-column strategy, lookup-table strategy
|
|
43
146
|
|
|
44
147
|
#### Schema & Migration
|
|
148
|
+
|
|
45
149
|
- `StructureDefinitionRegistry` — register and resolve FHIR StructureDefinitions
|
|
46
150
|
- `buildResourceTableSet` — StructureDefinition + SearchParameter → table schema
|
|
47
151
|
- DDL generators for Main, History, References tables + indexes
|
|
@@ -53,25 +157,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
53
157
|
- `ReindexScheduler` — schedule reindex jobs for SP expression changes
|
|
54
158
|
|
|
55
159
|
#### Terminology
|
|
160
|
+
|
|
56
161
|
- `TerminologyCodeRepo` — code system concept storage
|
|
57
162
|
- `ValueSetRepo` — value set expansion storage
|
|
58
163
|
|
|
59
164
|
#### Platform IG
|
|
165
|
+
|
|
60
166
|
- Built-in platform resource types: User, Bot, Project, Agent, ClientApplication
|
|
61
167
|
- `initializePlatformIG` — auto-register platform search parameters
|
|
62
168
|
|
|
63
169
|
#### Provider Bridges (for fhir-engine)
|
|
170
|
+
|
|
64
171
|
- `FhirDefinitionBridge` — wraps `fhir-definition` `DefinitionRegistry` → `DefinitionProvider`
|
|
65
172
|
- `FhirRuntimeProvider` — wraps `fhir-runtime` `FhirRuntimeInstance` → `RuntimeProvider`
|
|
66
173
|
- `FhirSystem` — end-to-end startup orchestrator
|
|
67
174
|
|
|
68
175
|
#### Production
|
|
176
|
+
|
|
69
177
|
- `ResourceCacheV2` — in-memory resource cache with TTL
|
|
70
178
|
- `SearchLogger` — search query logging and diagnostics
|
|
71
179
|
- `reindexResourceTypeV2` / `reindexAllV2` — CLI reindex utilities
|
|
72
180
|
|
|
73
181
|
### Dependencies
|
|
182
|
+
|
|
74
183
|
- `fhir-definition` ^0.5.0
|
|
75
184
|
- `fhir-runtime` ^0.8.1
|
|
76
185
|
- `better-sqlite3` ^12.6.2
|
|
77
|
-
- `sql.js` ^1.14.1
|
package/README.md
CHANGED
|
@@ -5,10 +5,13 @@ Embedded FHIR R4 persistence layer — CRUD, search, indexing, and schema migrat
|
|
|
5
5
|
[](https://www.npmjs.com/package/fhir-persistence)
|
|
6
6
|
[](./LICENSE)
|
|
7
7
|
|
|
8
|
+
> **v0.4.0** — Full PostgreSQL DDL compatibility for all system and lookup tables
|
|
9
|
+
|
|
8
10
|
## Features
|
|
9
11
|
|
|
10
12
|
- **StorageAdapter abstraction** — unified async interface for SQLite and PostgreSQL
|
|
11
|
-
- **
|
|
13
|
+
- **Dual-backend support** — `BetterSqlite3Adapter` (native SQLite) + `PostgresAdapter` (pg)
|
|
14
|
+
- **SqlDialect abstraction** — dialect-aware SQL generation for array operators, DDL, upsert
|
|
12
15
|
- **3-table-per-resource pattern** — Main + History + References tables per FHIR resource type
|
|
13
16
|
- **Automatic search indexing** — column, token-column, and lookup-table strategies
|
|
14
17
|
- **FHIRPath-driven extraction** — optional `RuntimeProvider` bridge for `fhir-runtime` powered indexing
|
|
@@ -34,21 +37,24 @@ npm install fhir-persistence
|
|
|
34
37
|
|
|
35
38
|
```bash
|
|
36
39
|
npm install fhir-definition fhir-runtime
|
|
40
|
+
|
|
41
|
+
# For PostgreSQL support (optional):
|
|
42
|
+
npm install pg
|
|
37
43
|
```
|
|
38
44
|
|
|
39
45
|
## Quick Start
|
|
40
46
|
|
|
41
|
-
###
|
|
47
|
+
### SQLite (standalone)
|
|
42
48
|
|
|
43
49
|
```typescript
|
|
44
50
|
import {
|
|
45
|
-
|
|
51
|
+
BetterSqlite3Adapter,
|
|
46
52
|
FhirPersistence,
|
|
47
53
|
SearchParameterRegistry,
|
|
48
54
|
} from "fhir-persistence";
|
|
49
55
|
|
|
50
56
|
// 1. Create storage adapter
|
|
51
|
-
const adapter = new
|
|
57
|
+
const adapter = new BetterSqlite3Adapter({ path: "./fhir.db" });
|
|
52
58
|
|
|
53
59
|
// 2. Create search parameter registry
|
|
54
60
|
const spRegistry = new SearchParameterRegistry();
|
|
@@ -78,6 +84,29 @@ const result = await persistence.searchResources({
|
|
|
78
84
|
});
|
|
79
85
|
```
|
|
80
86
|
|
|
87
|
+
### PostgreSQL
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { PostgresAdapter, FhirStore } from "fhir-persistence";
|
|
91
|
+
import { Pool } from "pg";
|
|
92
|
+
|
|
93
|
+
const pool = new Pool({
|
|
94
|
+
host: "localhost",
|
|
95
|
+
port: 5432,
|
|
96
|
+
database: "fhir_db",
|
|
97
|
+
user: "postgres",
|
|
98
|
+
password: "secret",
|
|
99
|
+
});
|
|
100
|
+
const adapter = new PostgresAdapter(pool);
|
|
101
|
+
const store = new FhirStore(adapter);
|
|
102
|
+
|
|
103
|
+
// Same CRUD API as SQLite — no code changes needed
|
|
104
|
+
const patient = await store.createResource("Patient", {
|
|
105
|
+
resourceType: "Patient",
|
|
106
|
+
name: [{ family: "Smith" }],
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
81
110
|
### With FhirSystem (recommended for fhir-engine)
|
|
82
111
|
|
|
83
112
|
```typescript
|
|
@@ -96,7 +125,7 @@ const adapter = new BetterSqlite3Adapter({ path: './fhir.db' });
|
|
|
96
125
|
const definitionBridge = new FhirDefinitionBridge(registry);
|
|
97
126
|
|
|
98
127
|
// 4. Bootstrap via FhirSystem
|
|
99
|
-
const system = new FhirSystem(adapter, { dialect: 'sqlite' });
|
|
128
|
+
const system = new FhirSystem(adapter, { dialect: 'sqlite' }); // or 'postgres'
|
|
100
129
|
const { persistence, sdRegistry, spRegistry, igResult } =
|
|
101
130
|
await system.initialize(definitionBridge);
|
|
102
131
|
|
|
@@ -107,9 +136,13 @@ const patient = await persistence.createResource('Patient', { resourceType: 'Pat
|
|
|
107
136
|
## Architecture
|
|
108
137
|
|
|
109
138
|
```
|
|
110
|
-
StorageAdapter (
|
|
139
|
+
StorageAdapter (BetterSqlite3Adapter / PostgresAdapter)
|
|
140
|
+
│
|
|
141
|
+
├── SqlDialect (SQLiteDialect / PostgresDialect)
|
|
142
|
+
│ └── Dialect-aware: DDL, array operators, upsert, timestamps
|
|
143
|
+
│
|
|
111
144
|
└── FhirPersistence (end-to-end facade)
|
|
112
|
-
├── FhirStore (basic CRUD + soft delete + versioning)
|
|
145
|
+
├── FhirStore (basic CRUD + soft delete + optimistic locking + versioning)
|
|
113
146
|
├── IndexingPipeline
|
|
114
147
|
│ ├── RuntimeProvider (FHIRPath extraction, optional)
|
|
115
148
|
│ ├── buildSearchColumns (fallback row indexer)
|
|
@@ -119,7 +152,7 @@ StorageAdapter (SQLite / better-sqlite3 / PostgreSQL)
|
|
|
119
152
|
├── BundleProcessorV2 (transaction / batch)
|
|
120
153
|
├── SearchParameterRegistry
|
|
121
154
|
└── Search Engine
|
|
122
|
-
├── WhereBuilder v2 (chain search,
|
|
155
|
+
├── WhereBuilder v2 (chain search, dialect-aware)
|
|
123
156
|
├── SearchPlanner (filter reorder, two-phase recommendation)
|
|
124
157
|
├── SearchSQLBuilder v2 (single-phase + two-phase)
|
|
125
158
|
├── SearchExecutor (_include / _revinclude / _include:iterate)
|
|
@@ -131,8 +164,7 @@ StorageAdapter (SQLite / better-sqlite3 / PostgreSQL)
|
|
|
131
164
|
| Adapter | Backend | Use Case |
|
|
132
165
|
| ---------------------- | ----------------------- | --------------------------------- |
|
|
133
166
|
| `BetterSqlite3Adapter` | better-sqlite3 (native) | Production Node.js, CLI, Electron |
|
|
134
|
-
| `
|
|
135
|
-
| `PostgresAdapter` | pg | Production server |
|
|
167
|
+
| `PostgresAdapter` | pg (connection pool) | Production server |
|
|
136
168
|
|
|
137
169
|
## Search
|
|
138
170
|
|
|
@@ -155,7 +187,7 @@ const request = parseSearchRequest(
|
|
|
155
187
|
registry,
|
|
156
188
|
);
|
|
157
189
|
|
|
158
|
-
// Single-phase SQL
|
|
190
|
+
// Single-phase SQL (dialect-aware)
|
|
159
191
|
const sql = buildSearchSQLv2(request, registry);
|
|
160
192
|
|
|
161
193
|
// Two-phase SQL for large tables
|
|
@@ -184,7 +216,8 @@ The IG persistence manager automatically handles schema evolution:
|
|
|
184
216
|
```typescript
|
|
185
217
|
import { IGPersistenceManager } from "fhir-persistence";
|
|
186
218
|
|
|
187
|
-
|
|
219
|
+
// Dialect: 'sqlite' or 'postgres'
|
|
220
|
+
const igManager = new IGPersistenceManager(adapter, "postgres");
|
|
188
221
|
const result = await igManager.initialize({
|
|
189
222
|
name: "hl7.fhir.r4.core",
|
|
190
223
|
version: "4.0.1",
|
|
@@ -202,7 +235,7 @@ const result = await igManager.initialize({
|
|
|
202
235
|
import { createFhirEngine } from "fhir-engine";
|
|
203
236
|
|
|
204
237
|
const engine = await createFhirEngine({
|
|
205
|
-
database: { type: "sqlite", url: "./fhir.db" },
|
|
238
|
+
database: { type: "sqlite", url: "./fhir.db" }, // or { type: 'postgres', ... }
|
|
206
239
|
packages: { path: "./fhir-packages" },
|
|
207
240
|
});
|
|
208
241
|
|
|
@@ -218,7 +251,7 @@ const engine = await createFhirEngine({
|
|
|
218
251
|
| `fhir-definition` | StructureDefinition, SearchParameter, ValueSet, CodeSystem definitions |
|
|
219
252
|
| `fhir-runtime` | FHIRPath evaluation, validation, search value extraction |
|
|
220
253
|
| `better-sqlite3` | Native SQLite bindings (production) |
|
|
221
|
-
| `
|
|
254
|
+
| `pg` | PostgreSQL client (optional peer dependency) |
|
|
222
255
|
|
|
223
256
|
## License
|
|
224
257
|
|