@streetjs/schema-inspector 1.0.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/ARCHITECTURE.md +79 -0
- package/CHANGELOG.md +27 -0
- package/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/schema-inspector.d.ts +80 -0
- package/dist/schema-inspector.d.ts.map +1 -0
- package/dist/schema-inspector.js +351 -0
- package/dist/schema-inspector.js.map +1 -0
- package/package.json +89 -0
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Architecture — @streetjs/schema-inspector
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`@streetjs/schema-inspector` turns a live database connection into a normalized,
|
|
6
|
+
engine-agnostic `DatabaseSchema`. It is the introspection layer the migration
|
|
7
|
+
differ and dev tooling build on. It is deliberately decoupled from any concrete
|
|
8
|
+
connection pool: it speaks only the structural `QueryablePool` interface and
|
|
9
|
+
routes by the pool's constructor name.
|
|
10
|
+
|
|
11
|
+
## Dependencies
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
@streetjs/postgres (the shared DbResult result type only)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
That is the sole dependency, and it is used purely for the `DbResult` type that
|
|
18
|
+
`QueryablePool.query` resolves to. No cyclic dependencies; no coupling to
|
|
19
|
+
`@streetjs/pool`, the wasm SQLite module, or any MySQL driver.
|
|
20
|
+
|
|
21
|
+
## Design
|
|
22
|
+
|
|
23
|
+
### Structural pool interface
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
interface QueryablePool { query(sql: string, params?: unknown[]): Promise<DbResult> }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`PgPool`, `MysqlPool`, and `SqlitePool` all satisfy this structurally, so the
|
|
30
|
+
inspector never imports a concrete class. Dialect selection is by
|
|
31
|
+
`pool.constructor.name`:
|
|
32
|
+
|
|
33
|
+
- `SqlitePool` → PRAGMA-based introspection;
|
|
34
|
+
- `PgPool` → `information_schema` + `pg_indexes`;
|
|
35
|
+
- anything else → MySQL/MariaDB `information_schema`.
|
|
36
|
+
|
|
37
|
+
This name-based routing is what lets the package stay dependency-light: the
|
|
38
|
+
concrete pools live in other packages/core, but the inspector only needs their
|
|
39
|
+
runtime `query` method.
|
|
40
|
+
|
|
41
|
+
### Normalization
|
|
42
|
+
|
|
43
|
+
Each engine path issues a small, fixed set of catalogue queries and folds the
|
|
44
|
+
rows into a `Map<tableName, TableSchema>`:
|
|
45
|
+
|
|
46
|
+
- **Postgres** parses index column lists out of the `indexdef` DDL string and
|
|
47
|
+
treats `is_pk` values of `'t'`/`'true'` as primary-key membership.
|
|
48
|
+
- **MySQL** groups the one-row-per-column `STATISTICS` output into composite
|
|
49
|
+
`IndexMeta` and reads `NON_UNIQUE = '0'` as unique.
|
|
50
|
+
- **SQLite** reads `PRAGMA table_info` for columns/PK (sorted by the `pk`
|
|
51
|
+
position for composite keys), `foreign_key_list` for FKs, and
|
|
52
|
+
`index_list` + `index_info` for indexes.
|
|
53
|
+
|
|
54
|
+
All values arrive as strings (matching the text-protocol/affinity semantics of
|
|
55
|
+
`DbResult`), so parsing is uniform and every field access is defended with a
|
|
56
|
+
fallback (`?? ''` / `?? null`).
|
|
57
|
+
|
|
58
|
+
### Caching
|
|
59
|
+
|
|
60
|
+
`inspect` caches the resulting `DatabaseSchema` per pool object (a
|
|
61
|
+
`Map<object, { schema, expiresAt }>`) for a configurable TTL (default 60s).
|
|
62
|
+
`invalidateCache(pool)` drops the entry to force a fresh read. The cache is keyed
|
|
63
|
+
by object identity, so distinct pools never collide.
|
|
64
|
+
|
|
65
|
+
## Testing
|
|
66
|
+
|
|
67
|
+
The suite runs with **no live database** by supplying fake `QueryablePool`
|
|
68
|
+
objects whose `constructor.name` is `PgPool`/`SqlitePool`/`MysqlPool`, driving
|
|
69
|
+
each dialect path with canned catalogue rows. It covers primary keys (including
|
|
70
|
+
composite and the `'t'`/`'true'` encodings), foreign keys, unique/non-unique and
|
|
71
|
+
multi-column index parsing, quoted-identifier stripping, empty databases,
|
|
72
|
+
per-field fallbacks for sparse rows, and the full cache/TTL/invalidation
|
|
73
|
+
lifecycle. Coverage is 100% lines/functions and ≥98% branches.
|
|
74
|
+
|
|
75
|
+
## Non-goals
|
|
76
|
+
|
|
77
|
+
- No DDL generation or migration diffing (that is the migration layer).
|
|
78
|
+
- No connection management (that is `@streetjs/pool` / the SQLite pool).
|
|
79
|
+
- No data reads beyond catalogue introspection.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@streetjs/schema-inspector` are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial standalone release of the StreetJS database schema introspector,
|
|
13
|
+
extracted from the `streetjs` core (`src/database/schema-inspector.ts`).
|
|
14
|
+
- `SchemaInspector.inspect(pool, opts?)` returning a unified `DatabaseSchema`
|
|
15
|
+
(tables, columns, primary keys, foreign keys, indexes) for PostgreSQL,
|
|
16
|
+
MySQL/MariaDB, and SQLite, with per-pool TTL caching (default 60s).
|
|
17
|
+
- `SchemaInspector.invalidateCache(pool)`.
|
|
18
|
+
- Public types: `DatabaseSchema`, `TableSchema`, `ColumnMeta`, `FkMeta`,
|
|
19
|
+
`IndexMeta`, and the structural `QueryablePool` interface.
|
|
20
|
+
- Decoupled from concrete pools: routes by `constructor.name` and depends only on
|
|
21
|
+
`@streetjs/postgres` for the shared `DbResult` type. ESM.
|
|
22
|
+
- 14 tests (no live database required), 100% line coverage, and a runnable
|
|
23
|
+
example. During extraction the public signature was generalized from
|
|
24
|
+
`PgPool | SqlitePool | QueryablePool` to `QueryablePool`; both `PgPool` and
|
|
25
|
+
`SqlitePool` satisfy it structurally, so existing callers are unaffected.
|
|
26
|
+
|
|
27
|
+
[1.0.0]: https://github.com/hassanmubiru/StreetJS/releases/tag/schema-inspector-v1.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 street 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,90 @@
|
|
|
1
|
+
# @streetjs/schema-inspector
|
|
2
|
+
|
|
3
|
+
The StreetJS database schema introspector: produces a unified
|
|
4
|
+
`DatabaseSchema` — tables, columns, primary keys, foreign keys, and indexes —
|
|
5
|
+
from a live **PostgreSQL**, **MySQL/MariaDB**, or **SQLite** database, with
|
|
6
|
+
per-pool TTL caching. ESM, strict-TypeScript.
|
|
7
|
+
|
|
8
|
+
It talks only through a structural `QueryablePool` interface and routes by the
|
|
9
|
+
pool's constructor name, so it has **no dependency on any concrete pool
|
|
10
|
+
implementation** — the only dependency is `@streetjs/postgres` for the shared
|
|
11
|
+
`DbResult` type.
|
|
12
|
+
|
|
13
|
+
This is the standalone home of the inspector that also backs the `streetjs`
|
|
14
|
+
framework. The framework re-exports this package, so there is a single source of
|
|
15
|
+
truth.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @streetjs/schema-inspector
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { SchemaInspector } from '@streetjs/schema-inspector';
|
|
27
|
+
|
|
28
|
+
// `pool` can be any object with `query(sql, params?): Promise<DbResult>`
|
|
29
|
+
// — PgPool, MysqlPool, and SqlitePool all qualify.
|
|
30
|
+
const schema = await SchemaInspector.inspect(pool);
|
|
31
|
+
|
|
32
|
+
for (const table of schema.tables) {
|
|
33
|
+
console.log(table.name, table.primaryKey, table.columns.length);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
|
|
39
|
+
### `SchemaInspector.inspect(pool, opts?): Promise<DatabaseSchema>`
|
|
40
|
+
|
|
41
|
+
Introspects the database and returns its schema. Results are cached per pool for
|
|
42
|
+
`opts.ttlMs` milliseconds (default `60000`). The dialect is detected from the
|
|
43
|
+
pool's constructor name (`PgPool` → PostgreSQL, `SqlitePool` → SQLite, anything
|
|
44
|
+
else → MySQL/MariaDB).
|
|
45
|
+
|
|
46
|
+
### `SchemaInspector.invalidateCache(pool): void`
|
|
47
|
+
|
|
48
|
+
Drops the cached schema for `pool` so the next `inspect` re-fetches.
|
|
49
|
+
|
|
50
|
+
### Types
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
interface DatabaseSchema { tables: TableSchema[]; inspectedAt: Date }
|
|
54
|
+
interface TableSchema {
|
|
55
|
+
name: string;
|
|
56
|
+
columns: ColumnMeta[];
|
|
57
|
+
primaryKey: string[];
|
|
58
|
+
foreignKeys: FkMeta[];
|
|
59
|
+
indexes: IndexMeta[];
|
|
60
|
+
}
|
|
61
|
+
interface ColumnMeta { name: string; type: string; nullable: boolean; default: string | null }
|
|
62
|
+
interface FkMeta { column: string; refTable: string; refColumn: string }
|
|
63
|
+
interface IndexMeta { name: string; columns: string[]; unique: boolean }
|
|
64
|
+
interface QueryablePool { query(sql: string, params?: unknown[]): Promise<DbResult> }
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## How it works
|
|
68
|
+
|
|
69
|
+
- **PostgreSQL** — three round-trips against `information_schema` (columns +
|
|
70
|
+
primary keys), `referential_constraints` (foreign keys), and `pg_indexes`
|
|
71
|
+
(indexes, with the column list parsed from `indexdef`).
|
|
72
|
+
- **MySQL/MariaDB** — `information_schema.COLUMNS`/`KEY_COLUMN_USAGE`/`STATISTICS`,
|
|
73
|
+
grouping the per-column `STATISTICS` rows into composite indexes.
|
|
74
|
+
- **SQLite** — `sqlite_master` for the table list, then `PRAGMA table_info`,
|
|
75
|
+
`index_list`/`index_info`, and `foreign_key_list` per table.
|
|
76
|
+
|
|
77
|
+
All engines normalize into the same `DatabaseSchema` shape.
|
|
78
|
+
|
|
79
|
+
## Example
|
|
80
|
+
|
|
81
|
+
A complete runnable example lives in
|
|
82
|
+
[`src/examples/integration.ts`](./src/examples/integration.ts):
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm run example -w packages/schema-inspector
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT — see [LICENSE](./LICENSE).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streetjs/schema-inspector — the StreetJS database schema introspector.
|
|
3
|
+
*
|
|
4
|
+
* Produces a unified {@link DatabaseSchema} — tables, columns, primary keys,
|
|
5
|
+
* foreign keys, and indexes — from a live PostgreSQL, MySQL/MariaDB, or SQLite
|
|
6
|
+
* database, with per-pool TTL caching. It routes by the pool's constructor name
|
|
7
|
+
* and talks only through the structural {@link QueryablePool} interface, so it
|
|
8
|
+
* has no dependency on any concrete pool implementation. Public API only.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { SchemaInspector } from '@streetjs/schema-inspector';
|
|
12
|
+
*
|
|
13
|
+
* const schema = await SchemaInspector.inspect(pool); // any queryable pool
|
|
14
|
+
* for (const table of schema.tables) console.log(table.name, table.columns.length);
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* > This is the standalone home of the inspector that also backs the `streetjs`
|
|
18
|
+
* > framework; the framework re-exports it, so there is a single implementation.
|
|
19
|
+
*/
|
|
20
|
+
export { SchemaInspector } from './schema-inspector.js';
|
|
21
|
+
export type { ColumnMeta, IndexMeta, FkMeta, TableSchema, DatabaseSchema, QueryablePool, } from './schema-inspector.js';
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EACV,UAAU,EACV,SAAS,EACT,MAAM,EACN,WAAW,EACX,cAAc,EACd,aAAa,GACd,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streetjs/schema-inspector — the StreetJS database schema introspector.
|
|
3
|
+
*
|
|
4
|
+
* Produces a unified {@link DatabaseSchema} — tables, columns, primary keys,
|
|
5
|
+
* foreign keys, and indexes — from a live PostgreSQL, MySQL/MariaDB, or SQLite
|
|
6
|
+
* database, with per-pool TTL caching. It routes by the pool's constructor name
|
|
7
|
+
* and talks only through the structural {@link QueryablePool} interface, so it
|
|
8
|
+
* has no dependency on any concrete pool implementation. Public API only.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { SchemaInspector } from '@streetjs/schema-inspector';
|
|
12
|
+
*
|
|
13
|
+
* const schema = await SchemaInspector.inspect(pool); // any queryable pool
|
|
14
|
+
* for (const table of schema.tables) console.log(table.name, table.columns.length);
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* > This is the standalone home of the inspector that also backs the `streetjs`
|
|
18
|
+
* > framework; the framework re-exports it, so there is a single implementation.
|
|
19
|
+
*/
|
|
20
|
+
export { SchemaInspector } from './schema-inspector.js';
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { DbResult } from '@streetjs/postgres';
|
|
2
|
+
export interface ColumnMeta {
|
|
3
|
+
name: string;
|
|
4
|
+
type: string;
|
|
5
|
+
nullable: boolean;
|
|
6
|
+
default: string | null;
|
|
7
|
+
}
|
|
8
|
+
export interface IndexMeta {
|
|
9
|
+
name: string;
|
|
10
|
+
columns: string[];
|
|
11
|
+
unique: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface FkMeta {
|
|
14
|
+
column: string;
|
|
15
|
+
refTable: string;
|
|
16
|
+
refColumn: string;
|
|
17
|
+
}
|
|
18
|
+
export interface TableSchema {
|
|
19
|
+
name: string;
|
|
20
|
+
columns: ColumnMeta[];
|
|
21
|
+
primaryKey: string[];
|
|
22
|
+
foreignKeys: FkMeta[];
|
|
23
|
+
indexes: IndexMeta[];
|
|
24
|
+
}
|
|
25
|
+
export interface DatabaseSchema {
|
|
26
|
+
tables: TableSchema[];
|
|
27
|
+
inspectedAt: Date;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Minimal interface satisfied by any Street database pool — `PgPool`,
|
|
31
|
+
* `MysqlPool`, and `SqlitePool` all match it structurally. The inspector routes
|
|
32
|
+
* by the pool's constructor name, so it never needs to import a concrete pool
|
|
33
|
+
* class (keeping this package free of engine-specific dependencies).
|
|
34
|
+
*/
|
|
35
|
+
export interface QueryablePool {
|
|
36
|
+
query(sql: string, params?: unknown[]): Promise<DbResult>;
|
|
37
|
+
}
|
|
38
|
+
interface CacheEntry {
|
|
39
|
+
schema: DatabaseSchema;
|
|
40
|
+
expiresAt: number;
|
|
41
|
+
}
|
|
42
|
+
export declare class SchemaInspector {
|
|
43
|
+
/** Schema cache keyed by pool object reference. */
|
|
44
|
+
static readonly _cache: Map<object, CacheEntry>;
|
|
45
|
+
/**
|
|
46
|
+
* Inspect the connected database and return its schema.
|
|
47
|
+
* Results are cached for `opts.ttlMs` milliseconds (default 60 000).
|
|
48
|
+
*/
|
|
49
|
+
static inspect(pool: QueryablePool, opts?: {
|
|
50
|
+
ttlMs?: number;
|
|
51
|
+
}): Promise<DatabaseSchema>;
|
|
52
|
+
/**
|
|
53
|
+
* Remove the cached schema for `pool`, forcing the next `inspect()` call
|
|
54
|
+
* to fetch fresh data from the database.
|
|
55
|
+
*/
|
|
56
|
+
static invalidateCache(pool: QueryablePool): void;
|
|
57
|
+
private static _isSqlitePool;
|
|
58
|
+
private static _isPgPool;
|
|
59
|
+
/**
|
|
60
|
+
* Inspect a PostgreSQL database.
|
|
61
|
+
* Uses 3 round-trips:
|
|
62
|
+
* 1. columns + primary keys (information_schema.columns + key_column_usage)
|
|
63
|
+
* 2. foreign keys (information_schema.referential_constraints + key_column_usage)
|
|
64
|
+
* 3. indexes (pg_indexes)
|
|
65
|
+
*/
|
|
66
|
+
private static _inspectPostgres;
|
|
67
|
+
/**
|
|
68
|
+
* Inspect a MySQL/MariaDB database using information_schema catalog tables.
|
|
69
|
+
* Uses 3 parallel round-trips: columns+pk, foreign keys, indexes.
|
|
70
|
+
*/
|
|
71
|
+
private static _inspectMysql;
|
|
72
|
+
/**
|
|
73
|
+
* Inspect a SQLite database using PRAGMA statements.
|
|
74
|
+
* Fetches the table list first, then issues PRAGMA queries for each table.
|
|
75
|
+
*/
|
|
76
|
+
private static _inspectSqlite;
|
|
77
|
+
private static _inspectSqliteTable;
|
|
78
|
+
}
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=schema-inspector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-inspector.d.ts","sourceRoot":"","sources":["../src/schema-inspector.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAInD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,WAAW,EAAE,IAAI,CAAC;CACnB;AAID;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC3D;AAID,UAAU,UAAU;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,qBAAa,eAAe;IAC1B,mDAAmD;IACnD,MAAM,CAAC,QAAQ,CAAC,MAAM,0BAAiC;IAEvD;;;OAGG;WACU,OAAO,CAClB,IAAI,EAAE,aAAa,EACnB,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACxB,OAAO,CAAC,cAAc,CAAC;IA4B1B;;;OAGG;IACH,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAMjD,OAAO,CAAC,MAAM,CAAC,aAAa;IAW5B,OAAO,CAAC,MAAM,CAAC,SAAS;IAUxB;;;;;;OAMG;mBACkB,gBAAgB;IAiIrC;;;OAGG;mBACkB,aAAa;IAwGlC;;;OAGG;mBACkB,cAAc;mBAed,mBAAmB;CAgEzC"}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
// src/schema-inspector.ts
|
|
2
|
+
// Database schema introspection for PostgreSQL, MySQL, and SQLite.
|
|
3
|
+
// Provides a unified DatabaseSchema regardless of the underlying engine.
|
|
4
|
+
// ─── SchemaInspector ─────────────────────────────────────────────────────────
|
|
5
|
+
export class SchemaInspector {
|
|
6
|
+
/** Schema cache keyed by pool object reference. */
|
|
7
|
+
static _cache = new Map();
|
|
8
|
+
/**
|
|
9
|
+
* Inspect the connected database and return its schema.
|
|
10
|
+
* Results are cached for `opts.ttlMs` milliseconds (default 60 000).
|
|
11
|
+
*/
|
|
12
|
+
static async inspect(pool, opts) {
|
|
13
|
+
const ttlMs = opts?.ttlMs ?? 60_000;
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
const cached = SchemaInspector._cache.get(pool);
|
|
16
|
+
if (cached && cached.expiresAt > now) {
|
|
17
|
+
return cached.schema;
|
|
18
|
+
}
|
|
19
|
+
// Detect dialect by duck-typing the pool
|
|
20
|
+
let schema;
|
|
21
|
+
if (SchemaInspector._isSqlitePool(pool)) {
|
|
22
|
+
schema = await SchemaInspector._inspectSqlite(pool);
|
|
23
|
+
}
|
|
24
|
+
else if (SchemaInspector._isPgPool(pool)) {
|
|
25
|
+
schema = await SchemaInspector._inspectPostgres(pool);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// MySQL or any other pool that satisfies QueryablePool
|
|
29
|
+
schema = await SchemaInspector._inspectMysql(pool);
|
|
30
|
+
}
|
|
31
|
+
SchemaInspector._cache.set(pool, {
|
|
32
|
+
schema,
|
|
33
|
+
expiresAt: now + ttlMs,
|
|
34
|
+
});
|
|
35
|
+
return schema;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Remove the cached schema for `pool`, forcing the next `inspect()` call
|
|
39
|
+
* to fetch fresh data from the database.
|
|
40
|
+
*/
|
|
41
|
+
static invalidateCache(pool) {
|
|
42
|
+
SchemaInspector._cache.delete(pool);
|
|
43
|
+
}
|
|
44
|
+
// ── Dialect detection ───────────────────────────────────────────────────────
|
|
45
|
+
static _isSqlitePool(pool) {
|
|
46
|
+
// SqlitePool uses worker_threads and exposes a `filePath`-based constructor.
|
|
47
|
+
// We detect it by relying on the pool constructor name.
|
|
48
|
+
return (pool !== null &&
|
|
49
|
+
typeof pool === 'object' &&
|
|
50
|
+
pool['constructor'] !== undefined &&
|
|
51
|
+
pool.constructor.name === 'SqlitePool');
|
|
52
|
+
}
|
|
53
|
+
static _isPgPool(pool) {
|
|
54
|
+
return (pool !== null &&
|
|
55
|
+
typeof pool === 'object' &&
|
|
56
|
+
pool.constructor.name === 'PgPool');
|
|
57
|
+
}
|
|
58
|
+
// ── PostgreSQL introspection ────────────────────────────────────────────────
|
|
59
|
+
/**
|
|
60
|
+
* Inspect a PostgreSQL database.
|
|
61
|
+
* Uses 3 round-trips:
|
|
62
|
+
* 1. columns + primary keys (information_schema.columns + key_column_usage)
|
|
63
|
+
* 2. foreign keys (information_schema.referential_constraints + key_column_usage)
|
|
64
|
+
* 3. indexes (pg_indexes)
|
|
65
|
+
*/
|
|
66
|
+
static async _inspectPostgres(pool) {
|
|
67
|
+
// Round-trip 1: columns and primary key membership
|
|
68
|
+
const colSql = `
|
|
69
|
+
SELECT
|
|
70
|
+
c.table_name,
|
|
71
|
+
c.column_name,
|
|
72
|
+
c.data_type,
|
|
73
|
+
c.is_nullable,
|
|
74
|
+
c.column_default,
|
|
75
|
+
CASE WHEN kcu.column_name IS NOT NULL THEN true ELSE false END AS is_pk
|
|
76
|
+
FROM information_schema.columns c
|
|
77
|
+
LEFT JOIN (
|
|
78
|
+
SELECT kcu.table_schema, kcu.table_name, kcu.column_name
|
|
79
|
+
FROM information_schema.key_column_usage kcu
|
|
80
|
+
JOIN information_schema.table_constraints tc
|
|
81
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
82
|
+
AND tc.table_schema = kcu.table_schema
|
|
83
|
+
AND tc.table_name = kcu.table_name
|
|
84
|
+
WHERE tc.constraint_type = 'PRIMARY KEY'
|
|
85
|
+
AND tc.table_schema = current_schema()
|
|
86
|
+
) kcu
|
|
87
|
+
ON kcu.table_schema = c.table_schema
|
|
88
|
+
AND kcu.table_name = c.table_name
|
|
89
|
+
AND kcu.column_name = c.column_name
|
|
90
|
+
WHERE c.table_schema = current_schema()
|
|
91
|
+
AND c.table_name IN (
|
|
92
|
+
SELECT table_name FROM information_schema.tables
|
|
93
|
+
WHERE table_schema = current_schema()
|
|
94
|
+
AND table_type = 'BASE TABLE'
|
|
95
|
+
)
|
|
96
|
+
ORDER BY c.table_name, c.ordinal_position
|
|
97
|
+
`;
|
|
98
|
+
// Round-trip 2: foreign keys
|
|
99
|
+
const fkSql = `
|
|
100
|
+
SELECT
|
|
101
|
+
kcu.table_name,
|
|
102
|
+
kcu.column_name,
|
|
103
|
+
ccu.table_name AS ref_table,
|
|
104
|
+
ccu.column_name AS ref_column
|
|
105
|
+
FROM information_schema.referential_constraints rc
|
|
106
|
+
JOIN information_schema.key_column_usage kcu
|
|
107
|
+
ON kcu.constraint_name = rc.constraint_name
|
|
108
|
+
AND kcu.table_schema = rc.constraint_schema
|
|
109
|
+
JOIN information_schema.constraint_column_usage ccu
|
|
110
|
+
ON ccu.constraint_name = rc.unique_constraint_name
|
|
111
|
+
AND ccu.table_schema = rc.unique_constraint_schema
|
|
112
|
+
WHERE rc.constraint_schema = current_schema()
|
|
113
|
+
ORDER BY kcu.table_name, kcu.column_name
|
|
114
|
+
`;
|
|
115
|
+
// Round-trip 3: indexes
|
|
116
|
+
const idxSql = `
|
|
117
|
+
SELECT
|
|
118
|
+
tablename,
|
|
119
|
+
indexname,
|
|
120
|
+
indexdef
|
|
121
|
+
FROM pg_indexes
|
|
122
|
+
WHERE schemaname = current_schema()
|
|
123
|
+
ORDER BY tablename, indexname
|
|
124
|
+
`;
|
|
125
|
+
const [colResult, fkResult, idxResult] = await Promise.all([
|
|
126
|
+
pool.query(colSql),
|
|
127
|
+
pool.query(fkSql),
|
|
128
|
+
pool.query(idxSql),
|
|
129
|
+
]);
|
|
130
|
+
// Build table map from columns
|
|
131
|
+
const tableMap = new Map();
|
|
132
|
+
for (const row of colResult.rows) {
|
|
133
|
+
const tbl = row['table_name'] ?? '';
|
|
134
|
+
if (!tableMap.has(tbl)) {
|
|
135
|
+
tableMap.set(tbl, { name: tbl, columns: [], primaryKey: [], foreignKeys: [], indexes: [] });
|
|
136
|
+
}
|
|
137
|
+
const ts = tableMap.get(tbl);
|
|
138
|
+
const col = {
|
|
139
|
+
name: row['column_name'] ?? '',
|
|
140
|
+
type: row['data_type'] ?? '',
|
|
141
|
+
nullable: row['is_nullable'] === 'YES',
|
|
142
|
+
default: row['column_default'] ?? null,
|
|
143
|
+
};
|
|
144
|
+
ts.columns.push(col);
|
|
145
|
+
if (row['is_pk'] === 'true' || row['is_pk'] === 't') {
|
|
146
|
+
ts.primaryKey.push(col.name);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Attach foreign keys
|
|
150
|
+
for (const row of fkResult.rows) {
|
|
151
|
+
const tbl = row['table_name'] ?? '';
|
|
152
|
+
const ts = tableMap.get(tbl);
|
|
153
|
+
if (!ts)
|
|
154
|
+
continue;
|
|
155
|
+
ts.foreignKeys.push({
|
|
156
|
+
column: row['column_name'] ?? '',
|
|
157
|
+
refTable: row['ref_table'] ?? '',
|
|
158
|
+
refColumn: row['ref_column'] ?? '',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
// Parse and attach indexes
|
|
162
|
+
for (const row of idxResult.rows) {
|
|
163
|
+
const tbl = row['tablename'] ?? '';
|
|
164
|
+
const ts = tableMap.get(tbl);
|
|
165
|
+
if (!ts)
|
|
166
|
+
continue;
|
|
167
|
+
const indexDef = row['indexdef'] ?? '';
|
|
168
|
+
const indexName = row['indexname'] ?? '';
|
|
169
|
+
const unique = /CREATE UNIQUE INDEX/i.test(indexDef);
|
|
170
|
+
// Parse column list from index definition:
|
|
171
|
+
// "CREATE [UNIQUE] INDEX name ON table USING method (col1, col2)"
|
|
172
|
+
const colMatch = indexDef.match(/\(([^)]+)\)/);
|
|
173
|
+
const columns = colMatch
|
|
174
|
+
? colMatch[1].split(',').map((s) => s.trim().replace(/^"(.+)"$/, '$1'))
|
|
175
|
+
: [];
|
|
176
|
+
ts.indexes.push({ name: indexName, columns, unique });
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
tables: Array.from(tableMap.values()),
|
|
180
|
+
inspectedAt: new Date(),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
// ── MySQL introspection ─────────────────────────────────────────────────────
|
|
184
|
+
/**
|
|
185
|
+
* Inspect a MySQL/MariaDB database using information_schema catalog tables.
|
|
186
|
+
* Uses 3 parallel round-trips: columns+pk, foreign keys, indexes.
|
|
187
|
+
*/
|
|
188
|
+
static async _inspectMysql(pool) {
|
|
189
|
+
const colSql = `
|
|
190
|
+
SELECT
|
|
191
|
+
c.TABLE_NAME AS table_name,
|
|
192
|
+
c.COLUMN_NAME AS column_name,
|
|
193
|
+
c.DATA_TYPE AS data_type,
|
|
194
|
+
c.IS_NULLABLE AS is_nullable,
|
|
195
|
+
c.COLUMN_DEFAULT AS column_default,
|
|
196
|
+
c.COLUMN_KEY AS column_key
|
|
197
|
+
FROM information_schema.COLUMNS c
|
|
198
|
+
WHERE c.TABLE_SCHEMA = DATABASE()
|
|
199
|
+
ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION
|
|
200
|
+
`;
|
|
201
|
+
const fkSql = `
|
|
202
|
+
SELECT
|
|
203
|
+
kcu.TABLE_NAME AS table_name,
|
|
204
|
+
kcu.COLUMN_NAME AS column_name,
|
|
205
|
+
kcu.REFERENCED_TABLE_NAME AS ref_table,
|
|
206
|
+
kcu.REFERENCED_COLUMN_NAME AS ref_column
|
|
207
|
+
FROM information_schema.KEY_COLUMN_USAGE kcu
|
|
208
|
+
WHERE kcu.TABLE_SCHEMA = DATABASE()
|
|
209
|
+
AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
|
|
210
|
+
ORDER BY kcu.TABLE_NAME, kcu.COLUMN_NAME
|
|
211
|
+
`;
|
|
212
|
+
const idxSql = `
|
|
213
|
+
SELECT
|
|
214
|
+
TABLE_NAME AS table_name,
|
|
215
|
+
INDEX_NAME AS index_name,
|
|
216
|
+
COLUMN_NAME AS column_name,
|
|
217
|
+
NON_UNIQUE AS non_unique
|
|
218
|
+
FROM information_schema.STATISTICS
|
|
219
|
+
WHERE TABLE_SCHEMA = DATABASE()
|
|
220
|
+
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX
|
|
221
|
+
`;
|
|
222
|
+
const [colResult, fkResult, idxResult] = await Promise.all([
|
|
223
|
+
pool.query(colSql),
|
|
224
|
+
pool.query(fkSql),
|
|
225
|
+
pool.query(idxSql),
|
|
226
|
+
]);
|
|
227
|
+
const tableMap = new Map();
|
|
228
|
+
for (const row of colResult.rows) {
|
|
229
|
+
const tbl = row['table_name'] ?? '';
|
|
230
|
+
if (!tableMap.has(tbl)) {
|
|
231
|
+
tableMap.set(tbl, { name: tbl, columns: [], primaryKey: [], foreignKeys: [], indexes: [] });
|
|
232
|
+
}
|
|
233
|
+
const ts = tableMap.get(tbl);
|
|
234
|
+
const col = {
|
|
235
|
+
name: row['column_name'] ?? '',
|
|
236
|
+
type: row['data_type'] ?? '',
|
|
237
|
+
nullable: row['is_nullable'] === 'YES',
|
|
238
|
+
default: row['column_default'] ?? null,
|
|
239
|
+
};
|
|
240
|
+
ts.columns.push(col);
|
|
241
|
+
if (row['column_key'] === 'PRI') {
|
|
242
|
+
ts.primaryKey.push(col.name);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
for (const row of fkResult.rows) {
|
|
246
|
+
const tbl = row['table_name'] ?? '';
|
|
247
|
+
const ts = tableMap.get(tbl);
|
|
248
|
+
if (!ts)
|
|
249
|
+
continue;
|
|
250
|
+
ts.foreignKeys.push({
|
|
251
|
+
column: row['column_name'] ?? '',
|
|
252
|
+
refTable: row['ref_table'] ?? '',
|
|
253
|
+
refColumn: row['ref_column'] ?? '',
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
// Group index rows (one row per column in the index) into IndexMeta
|
|
257
|
+
const indexAccum = new Map();
|
|
258
|
+
for (const row of idxResult.rows) {
|
|
259
|
+
const tbl = row['table_name'] ?? '';
|
|
260
|
+
const idxName = row['index_name'] ?? '';
|
|
261
|
+
const key = `${tbl}::${idxName}`;
|
|
262
|
+
if (!indexAccum.has(key)) {
|
|
263
|
+
indexAccum.set(key, {
|
|
264
|
+
tableName: tbl,
|
|
265
|
+
name: idxName,
|
|
266
|
+
columns: [],
|
|
267
|
+
unique: row['non_unique'] === '0',
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
indexAccum.get(key).columns.push(row['column_name'] ?? '');
|
|
271
|
+
}
|
|
272
|
+
for (const idx of indexAccum.values()) {
|
|
273
|
+
const ts = tableMap.get(idx.tableName);
|
|
274
|
+
if (!ts)
|
|
275
|
+
continue;
|
|
276
|
+
ts.indexes.push({ name: idx.name, columns: idx.columns, unique: idx.unique });
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
tables: Array.from(tableMap.values()),
|
|
280
|
+
inspectedAt: new Date(),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
// ── SQLite introspection ────────────────────────────────────────────────────
|
|
284
|
+
/**
|
|
285
|
+
* Inspect a SQLite database using PRAGMA statements.
|
|
286
|
+
* Fetches the table list first, then issues PRAGMA queries for each table.
|
|
287
|
+
*/
|
|
288
|
+
static async _inspectSqlite(pool) {
|
|
289
|
+
// Get all user tables (exclude internal sqlite_ tables)
|
|
290
|
+
const tablesResult = await pool.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name");
|
|
291
|
+
const tableNames = tablesResult.rows.map((r) => r['name'] ?? '');
|
|
292
|
+
const tables = await Promise.all(tableNames.map((name) => SchemaInspector._inspectSqliteTable(pool, name)));
|
|
293
|
+
return { tables, inspectedAt: new Date() };
|
|
294
|
+
}
|
|
295
|
+
static async _inspectSqliteTable(pool, tableName) {
|
|
296
|
+
// Run all three PRAGMAs for this table
|
|
297
|
+
const [colResult, idxListResult, fkResult] = await Promise.all([
|
|
298
|
+
pool.query(`PRAGMA table_info(${JSON.stringify(tableName)})`),
|
|
299
|
+
pool.query(`PRAGMA index_list(${JSON.stringify(tableName)})`),
|
|
300
|
+
pool.query(`PRAGMA foreign_key_list(${JSON.stringify(tableName)})`),
|
|
301
|
+
]);
|
|
302
|
+
// Columns and primary key from table_info
|
|
303
|
+
// Columns: cid, name, type, notnull, dflt_value, pk
|
|
304
|
+
const columns = [];
|
|
305
|
+
for (const row of colResult.rows) {
|
|
306
|
+
columns.push({
|
|
307
|
+
name: row['name'] ?? '',
|
|
308
|
+
type: row['type'] ?? '',
|
|
309
|
+
nullable: row['notnull'] === '0',
|
|
310
|
+
default: row['dflt_value'] ?? null,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
// Sort primary key columns by their pk position
|
|
314
|
+
const pkEntries = colResult.rows
|
|
315
|
+
.filter((r) => r['pk'] !== '0' && r['pk'] !== null && r['pk'] !== undefined)
|
|
316
|
+
.sort((a, b) => Number(a['pk']) - Number(b['pk']))
|
|
317
|
+
.map((r) => r['name'] ?? '');
|
|
318
|
+
// Foreign keys from foreign_key_list
|
|
319
|
+
// Columns: id, seq, table, from, to, on_update, on_delete, match
|
|
320
|
+
const foreignKeys = fkResult.rows.map((row) => ({
|
|
321
|
+
column: row['from'] ?? '',
|
|
322
|
+
refTable: row['table'] ?? '',
|
|
323
|
+
refColumn: row['to'] ?? '',
|
|
324
|
+
}));
|
|
325
|
+
// Indexes from index_list, then fetch columns for each non-partial index
|
|
326
|
+
// Columns: seq, name, unique, origin, partial
|
|
327
|
+
const indexes = [];
|
|
328
|
+
for (const idxRow of idxListResult.rows) {
|
|
329
|
+
const idxName = idxRow['name'] ?? '';
|
|
330
|
+
// Fetch columns for this index via PRAGMA index_info
|
|
331
|
+
const infoResult = await pool.query(`PRAGMA index_info(${JSON.stringify(idxName)})`);
|
|
332
|
+
// Columns: seqno, cid, name
|
|
333
|
+
const cols = infoResult.rows
|
|
334
|
+
.sort((a, b) => Number(a['seqno']) - Number(b['seqno']))
|
|
335
|
+
.map((r) => r['name'] ?? '');
|
|
336
|
+
indexes.push({
|
|
337
|
+
name: idxName,
|
|
338
|
+
columns: cols,
|
|
339
|
+
unique: idxRow['unique'] === '1',
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
name: tableName,
|
|
344
|
+
columns,
|
|
345
|
+
primaryKey: pkEntries,
|
|
346
|
+
foreignKeys,
|
|
347
|
+
indexes,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=schema-inspector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-inspector.js","sourceRoot":"","sources":["../src/schema-inspector.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@streetjs/schema-inspector",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "StreetJS database schema introspection: a unified DatabaseSchema (tables, columns, primary keys, foreign keys, indexes) across PostgreSQL, MySQL/MariaDB, and SQLite, with TTL caching. Works with any queryable pool.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/**/*.js",
|
|
16
|
+
"dist/**/*.js.map",
|
|
17
|
+
"dist/**/*.d.ts",
|
|
18
|
+
"dist/**/*.d.ts.map",
|
|
19
|
+
"!dist/**/*.test.js",
|
|
20
|
+
"!dist/**/*.test.js.map",
|
|
21
|
+
"!dist/**/*.test.d.ts",
|
|
22
|
+
"!dist/**/*.test.d.ts.map",
|
|
23
|
+
"!dist/tests/**",
|
|
24
|
+
"!dist/examples/**",
|
|
25
|
+
"README.md",
|
|
26
|
+
"ARCHITECTURE.md",
|
|
27
|
+
"CHANGELOG.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"c8": {
|
|
31
|
+
"include": ["dist/**/*.js"],
|
|
32
|
+
"exclude": ["dist/tests/**", "dist/examples/**"],
|
|
33
|
+
"reporter": ["text", "lcov"],
|
|
34
|
+
"all": true,
|
|
35
|
+
"check-coverage": true,
|
|
36
|
+
"lines": 90,
|
|
37
|
+
"functions": 90,
|
|
38
|
+
"branches": 90,
|
|
39
|
+
"statements": 90
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc",
|
|
43
|
+
"test": "node --test dist/tests/*.test.js",
|
|
44
|
+
"coverage": "c8 node --test dist/tests/*.test.js",
|
|
45
|
+
"example": "node dist/examples/integration.js",
|
|
46
|
+
"lint": "tsc --noEmit",
|
|
47
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\""
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"streetjs",
|
|
51
|
+
"street-framework",
|
|
52
|
+
"schema",
|
|
53
|
+
"introspection",
|
|
54
|
+
"database",
|
|
55
|
+
"postgresql",
|
|
56
|
+
"mysql",
|
|
57
|
+
"sqlite",
|
|
58
|
+
"information-schema",
|
|
59
|
+
"typescript",
|
|
60
|
+
"esm"
|
|
61
|
+
],
|
|
62
|
+
"author": "street contributors",
|
|
63
|
+
"license": "MIT",
|
|
64
|
+
"homepage": "https://hassanmubiru.github.io/StreetJS/",
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "git+https://github.com/hassanmubiru/StreetJS.git"
|
|
68
|
+
},
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/hassanmubiru/StreetJS/issues"
|
|
71
|
+
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"@streetjs/postgres": "^1.0.0"
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@types/node": "^26.1.0",
|
|
77
|
+
"c8": "^11.0.0",
|
|
78
|
+
"typescript": "^6.0.3"
|
|
79
|
+
},
|
|
80
|
+
"peerDependencies": {
|
|
81
|
+
"typescript": ">=5.0.0"
|
|
82
|
+
},
|
|
83
|
+
"engines": {
|
|
84
|
+
"node": ">=22.0.0"
|
|
85
|
+
},
|
|
86
|
+
"publishConfig": {
|
|
87
|
+
"access": "public"
|
|
88
|
+
}
|
|
89
|
+
}
|