@typesql/pg 0.0.3 → 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.
Files changed (46) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +41 -23
  3. package/dist/bin.d.ts +3 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +5 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/client.d.ts +7 -29
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +44 -73
  10. package/dist/client.js.map +1 -1
  11. package/dist/index.d.ts +15 -6
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +5 -9
  14. package/dist/index.js.map +1 -1
  15. package/dist/introspect/cli.d.ts +24 -0
  16. package/dist/introspect/cli.d.ts.map +1 -0
  17. package/dist/introspect/cli.js +121 -0
  18. package/dist/introspect/cli.js.map +1 -0
  19. package/dist/introspect/emit.d.ts +30 -0
  20. package/dist/introspect/emit.d.ts.map +1 -0
  21. package/dist/introspect/emit.js +144 -0
  22. package/dist/introspect/emit.js.map +1 -0
  23. package/dist/introspect/index.d.ts +5 -0
  24. package/dist/introspect/index.d.ts.map +1 -0
  25. package/dist/introspect/index.js +5 -0
  26. package/dist/introspect/index.js.map +1 -0
  27. package/dist/introspect/introspect.d.ts +67 -0
  28. package/dist/introspect/introspect.d.ts.map +1 -0
  29. package/dist/introspect/introspect.js +109 -0
  30. package/dist/introspect/introspect.js.map +1 -0
  31. package/dist/introspect/nullability.d.ts +60 -0
  32. package/dist/introspect/nullability.d.ts.map +1 -0
  33. package/dist/introspect/nullability.js +354 -0
  34. package/dist/introspect/nullability.js.map +1 -0
  35. package/dist/type-map.d.ts +42 -14
  36. package/dist/type-map.d.ts.map +1 -1
  37. package/package.json +10 -3
  38. package/src/bin.ts +5 -0
  39. package/src/client.ts +45 -77
  40. package/src/index.ts +14 -14
  41. package/src/introspect/cli.ts +138 -0
  42. package/src/introspect/emit.ts +168 -0
  43. package/src/introspect/index.ts +12 -0
  44. package/src/introspect/introspect.ts +221 -0
  45. package/src/introspect/nullability.ts +356 -0
  46. package/src/type-map.ts +42 -14
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @typesql/pg
2
2
 
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Queries run from the `sql` bound to your client: `createSql<DB>(client)` then `sql("…").execute()` (or `executeTakeFirst`, `executeTakeFirstOrThrow`, `executeCount`), and `sql.transaction(async (tx) => …)` for transactions, nested with savepoints; the `query`, `one`, `maybeOne`, `many`, `execute`, `transaction` and `RowCountError` exports of `@typesql/pg` and `@typesql/postgres`, `query` and `execute` of `@typesql/kysely`, and `queryRaw` and `executeRaw` of `@typesql/prisma` are removed.
8
+
9
+ ### Patch Changes
10
+
11
+ - The README links to the type map tables on the new node-postgres and postgres.js adapter pages of the docs.
12
+
13
+ - Updated dependencies:
14
+ - @typesql/core@0.1.0
15
+
16
+ ## 0.0.4
17
+
18
+ ### Patch Changes
19
+
20
+ - An opt-in `PgCatalog` slice types queries on `pg_stat_activity`, `pg_stat_database`, `pg_tables`, `pg_class`, `information_schema.columns` and other system catalogs: `createSql<DB & PgCatalog>()`.
21
+
22
+ - Queries have `executeCount()`, which resolves to the affected row count: an `Executor` may resolve to `{ rows, rowCount }` instead of the rows, as the `executor()` of `@typesql/pg`, `@typesql/postgres` and `@typesql/kysely` now do.
23
+
24
+ - `createSql(executor, { rowKeys: "camelCase" })` (and the adapters' `createSql(client, { rowKeys: "camelCase" })`) camelCases the top-level row keys the way Kysely's `CamelCasePlugin` does, in the row types and in the rows `execute*` and the `query`/`one`/`maybeOne`/`many` helpers return, leaving JSON values untouched.
25
+
26
+ - Rows with `interval` columns are plain object types, so a package that exports them no longer needs `@typesql/pg` as a dependency for declaration emit (TS2883); `PgInterval` stays exported.
27
+
28
+ - The type maps declare what parameters accept (`PgParamTypeMap`, `PostgresJsParamTypeMap`), so `int8`/`numeric` parameters take numbers and bigints and timestamp parameters take strings; postgres.js timestamp parameters also take epoch milliseconds.
29
+
30
+ - `typesql introspect` (a bin of `@typesql/pg`, also `@typesql/pg/introspect`) writes the schema of a live database: exact column types, domains as their base type, enums, arrays, views with nullability read from their definitions, other schemas nested, and `Json<T>` columns for the TypeScript types `columnTypes` gives json / jsonb columns.
31
+
32
+ - Updated dependencies:
33
+ - @typesql/core@0.0.4
34
+
3
35
  ## 0.0.3
4
36
 
5
37
  ### Patch Changes
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [node-postgres](https://node-postgres.com) (`pg` 8.x) adapter for
4
4
  [`@typesql/core`](https://www.npmjs.com/package/@typesql/core): a `createSql` bound to the type
5
- map of `pg`'s default parsers, and helpers that run a query and return rows typed from it.
5
+ map of `pg`'s default parsers, whose queries run on your pool and return rows typed from the SQL.
6
6
 
7
7
  ```sh
8
8
  pnpm add @typesql/core @typesql/pg pg
@@ -12,21 +12,20 @@ pnpm add @typesql/core @typesql/pg pg
12
12
 
13
13
  ```ts
14
14
  import { Pool } from "pg";
15
- import { createSql, execute, many, maybeOne, one, query, transaction } from "@typesql/pg";
15
+ import { createSql } from "@typesql/pg";
16
16
  import type { DB } from "./schema";
17
17
 
18
18
  const pool = new Pool();
19
- const sql = createSql<DB>();
19
+ const sql = createSql<DB>(pool);
20
20
 
21
- const users = await query(pool, sql("SELECT id, email FROM users")); // { id: number; email: string }[]
22
- const user = await one(pool, sql("SELECT id, email FROM users WHERE id = $1", 7)); // exactly one row, or throws
23
- const maybe = await maybeOne(pool, sql("SELECT id FROM users WHERE email = $1", "x")); // row | null
24
- const some = await many(pool, sql("SELECT id FROM posts")); // at least one row, or throws
25
- const changed = await execute(pool, sql("UPDATE users SET display_name = NULL")); // row count
21
+ const users = await sql("SELECT id, email FROM users").execute(); // { id: number; email: string }[]
22
+ const maybe = await sql("SELECT id FROM users WHERE email = $1", "x").executeTakeFirst(); // row | undefined
23
+ const user = await sql("SELECT id, email FROM users WHERE id = $1", 7).executeTakeFirstOrThrow(); // row, or NoResultError
24
+ const changed = await sql("UPDATE users SET display_name = NULL").executeCount(); // row count
26
25
 
27
- const id = await transaction(pool, async (client) => {
28
- const { id } = await one(client, sql("INSERT INTO users (email) VALUES ($1) RETURNING id", "a@b.c"));
29
- await execute(client, sql("INSERT INTO posts (author_id, title) VALUES ($1, $2)", id, "Hello"));
26
+ const id = await sql.transaction(async (tx) => {
27
+ const { id } = await tx("INSERT INTO users (email) VALUES ($1) RETURNING id", "a@b.c").executeTakeFirstOrThrow();
28
+ await tx("INSERT INTO posts (author_id, title) VALUES ($1, $2)", id, "Hello").execute();
30
29
  return id;
31
30
  });
32
31
  ```
@@ -35,19 +34,34 @@ const id = await transaction(pool, async (client) => {
35
34
 
36
35
  | Export | |
37
36
  |---|---|
38
- | `createSql<DB>()` | core's `createSql<DB, PgTypeMap>()` |
39
- | `query(client, q)` | `Promise<Row[]>` |
40
- | `one(client, q)` | `Promise<Row>`; `RowCountError` unless exactly one row |
41
- | `maybeOne(client, q)` | `Promise<Row \| null>`; `RowCountError` on more than one row |
42
- | `many(client, q)` | `Promise<[Row, ...Row[]]>`; `RowCountError` on zero rows |
43
- | `execute(client, q)` | `Promise<number>`, the affected row count |
44
- | `transaction(pool, fn)` | `BEGIN`, `fn(client)`, `COMMIT`; `ROLLBACK` and rethrow on error |
37
+ | `createSql<DB>(client, options?)` | core's `createSql<DB, PgTypeMap>()` with the queries running on `client` (a `Pool`, `Client` or `PoolClient`); `{ rowKeys: "camelCase" }` camelCases the row keys |
38
+ | `q.execute()`, `q.executeTakeFirst()`, `q.executeTakeFirstOrThrow()`, `q.executeCount()` | `Promise<Row[]>`, `Promise<Row \| undefined>`, `Promise<Row>` (`NoResultError` on 0 rows), `Promise<number>` (`rowCount`) |
39
+ | `sql.transaction(fn)` | on a `Pool`: checks out a client, `BEGIN`, `fn(tx)`, `COMMIT`, releases it; `ROLLBACK` and rethrow on error. On a `Client` or `PoolClient`: the same on that connection. `tx` is `sql` bound to the transaction; `tx.transaction(fn)` uses a savepoint |
40
+ | `executor(client)` | an `Executor` for `q.execute(executor)` and core's `createSql(executor)` (reports `rowCount`) |
45
41
  | `migrate(pool, m)` | runs `m.statements` (e.g. from core's `migrations()`) in one transaction |
46
- | `PgTypeMap`, `PgInterval` | the type map, and the `postgres-interval` object type |
47
- | `RowCountError`, `PgQueryable`, `PgPoolLike`, `PgTransactionClient`, `PgResult`, `MigrationSource` | errors and parameter types |
42
+ | `PgSql<DB, Keys>` | the type `createSql` returns |
43
+ | `PgTypeMap`, `PgParamTypeMap`, `PgInterval` | the type map (rows), what parameters also accept, and the `postgres-interval` object type |
44
+ | `NoResultError`, `PgQueryable`, `PgPoolLike`, `PgTransactionClient`, `PgResult`, `MigrationSource` | errors and parameter types |
48
45
 
49
- `client` is anything with `query(text, values)`: a `Pool`, `Client` or `PoolClient`. The
50
- parameters are structural, so fakes work in tests.
46
+ `client` is anything with `query(text, values)`. The parameters are structural, so fakes work
47
+ in tests. If the `ROLLBACK` of a pool transaction fails, the client is released with the error
48
+ so the pool discards the connection.
49
+
50
+ ## `typesql introspect`
51
+
52
+ Generates the schema from a live database: tables, views, materialized views and enums, with
53
+ the exact Postgres type of every column (domains as their base type), nullability, defaults,
54
+ identity and generated columns, other schemas nested, and TypeScript types for JSON columns
55
+ from a config file.
56
+
57
+ ```sh
58
+ pnpm exec typesql introspect --url postgres://localhost/app --out src/db/schema.ts
59
+ pnpm exec typesql introspect --schema public,auth --config typesql.config.ts
60
+ ```
61
+
62
+ The same is available from code as `introspect(client)` and `generateSource(db)` in
63
+ `@typesql/pg/introspect`. See the
64
+ [Introspection guide](https://github.com/ismailkarsli/typesql/blob/main/packages/docs/guide/introspect.md).
51
65
 
52
66
  ## `PgTypeMap`
53
67
 
@@ -66,4 +80,8 @@ What `pg`'s default parsers return:
66
80
  | text-like and other types | `string` |
67
81
 
68
82
  Arrays map element-wise. The full table, including the array types `pg` leaves as raw text, is
69
- in the [Adapters guide](https://github.com/ismailkarsli/typesql/blob/main/packages/docs/guide/adapters.md).
83
+ on the [node-postgres adapter page](https://github.com/ismailkarsli/typesql/blob/main/packages/docs/adapters/pg.md).
84
+
85
+ Parameters accept the row type and what `pg` serializes for the type (`PgParamTypeMap`):
86
+ `number | bigint | string` for `int8`, `numeric` and `money`, `Date | string` for dates and
87
+ timestamps, `string` for `interval`, `Uint8Array` for `bytea`.
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ /** `typesql`: `typesql introspect` writes the typesql schema of a live database. */
3
+ import { main } from "./introspect/cli.js";
4
+ process.exitCode = await main(process.argv.slice(2));
5
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,oFAAoF;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE3C,OAAO,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { Executor, Query, RowType } from "@typesql/core";
2
- /** The subset of a `pg` query result the helpers rely on. */
1
+ import { type Executor, type SqlDriver } from "@typesql/core";
2
+ /** The subset of a `pg` query result the adapter relies on. */
3
3
  export interface PgResult {
4
4
  readonly rows: unknown[];
5
5
  readonly rowCount: number | null;
@@ -19,34 +19,13 @@ export interface PgTransactionClient extends PgQueryable {
19
19
  export interface PgPoolLike<C extends PgTransactionClient = PgTransactionClient> {
20
20
  connect(): Promise<C>;
21
21
  }
22
- /** Thrown by `one`, `maybeOne` and `many` when the row count does not match. */
23
- export declare class RowCountError extends Error {
24
- readonly code: "NO_ROWS" | "TOO_MANY_ROWS";
25
- readonly expected: string;
26
- readonly actual: number;
27
- readonly text: string;
28
- readonly name = "RowCountError";
29
- constructor(code: "NO_ROWS" | "TOO_MANY_ROWS", expected: string, actual: number, text: string);
30
- }
31
- type AnyQuery = Query<unknown, readonly unknown[]>;
32
- /** An `Executor` for core's `q.execute()`: runs queries on `client` and resolves to the rows. */
33
- export declare function executor(client: PgQueryable): Executor;
34
- /** Run a query and return all rows, typed from the query. */
35
- export declare function query<Q extends AnyQuery>(client: PgQueryable, q: Q): Promise<RowType<Q>[]>;
36
- /** Exactly one row, otherwise throws `RowCountError`. */
37
- export declare function one<Q extends AnyQuery>(client: PgQueryable, q: Q): Promise<RowType<Q>>;
38
- /** Zero or one row (`null` for zero); throws `RowCountError` on more than one. */
39
- export declare function maybeOne<Q extends AnyQuery>(client: PgQueryable, q: Q): Promise<RowType<Q> | null>;
40
- /** At least one row, otherwise throws `RowCountError`. */
41
- export declare function many<Q extends AnyQuery>(client: PgQueryable, q: Q): Promise<[RowType<Q>, ...RowType<Q>[]]>;
42
- /** Run a statement for its side effect and return the affected row count (`rowCount ?? 0`). */
43
- export declare function execute(client: PgQueryable, q: AnyQuery): Promise<number>;
44
22
  /**
45
- * Check out a client, run `fn` inside BEGIN/COMMIT, ROLLBACK on error, and release the
46
- * client. If ROLLBACK itself fails the client is released with the error so the pool
47
- * discards the connection instead of reusing it.
23
+ * An `Executor` for core's `q.execute()`: runs queries on `client` and resolves to
24
+ * `{ rows, rowCount }` (pg's `rowCount`, so `q.executeCount()` works).
48
25
  */
49
- export declare function transaction<C extends PgTransactionClient, T>(pool: PgPoolLike<C>, fn: (client: C) => Promise<T>): Promise<T>;
26
+ export declare function executor(client: PgQueryable): Executor;
27
+ /** How `createSql(client)` runs queries and transactions. */
28
+ export declare const driver: SqlDriver<PgQueryable>;
50
29
  /** Anything carrying an ordered list of DDL statements, e.g. a `migrations()` builder from core. */
51
30
  export interface MigrationSource {
52
31
  readonly statements: readonly string[];
@@ -57,5 +36,4 @@ export interface MigrationSource {
57
36
  * with `$$`-quoted function bodies work.
58
37
  */
59
38
  export declare function migrate<C extends PgTransactionClient>(pool: PgPoolLike<C>, m: MigrationSource): Promise<void>;
60
- export {};
61
39
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE9D,6DAA6D;AAC7D,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC5D;AAED,kFAAkF;AAClF,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,IAAI,CAAC;CACtC;AAED,6CAA6C;AAC7C,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,mBAAmB,GAAG,mBAAmB;IAC7E,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;CACvB;AAED,gFAAgF;AAChF,qBAAa,aAAc,SAAQ,KAAK;IAGpC,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,eAAe;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM;IALvB,SAAkB,IAAI,mBAAmB;IACzC,YACW,IAAI,EAAE,SAAS,GAAG,eAAe,EACjC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAGtB;CACF;AAED,KAAK,QAAQ,GAAG,KAAK,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC;AAOnD,iGAAiG;AACjG,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,QAAQ,CAEtD;AAED,6DAA6D;AAC7D,wBAAsB,KAAK,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAGhG;AAED,yDAAyD;AACzD,wBAAsB,GAAG,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAM5F;AAED,kFAAkF;AAClF,wBAAsB,QAAQ,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAIxG;AAED,0DAA0D;AAC1D,wBAAsB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAIhH;AAED,+FAA+F;AAC/F,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/E;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,CAAC,SAAS,mBAAmB,EAAE,CAAC,EAChE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EACnB,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAC5B,OAAO,CAAC,CAAC,CAAC,CAoBZ;AAED,oGAAoG;AACpG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,CAAC,SAAS,mBAAmB,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAInH"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAE9E,+DAA+D;AAC/D,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC5D;AAED,kFAAkF;AAClF,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,IAAI,CAAC;CACtC;AAED,6CAA6C;AAC7C,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,mBAAmB,GAAG,mBAAmB;IAC7E,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,QAAQ,CAMtD;AA6CD,6DAA6D;AAC7D,eAAO,MAAM,MAAM,EAAE,SAAS,CAAC,WAAW,CAA6B,CAAC;AAExE,oGAAoG;AACpG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,CAAC,SAAS,mBAAmB,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAInH"}
package/dist/client.js CHANGED
@@ -1,94 +1,65 @@
1
- /** Thrown by `one`, `maybeOne` and `many` when the row count does not match. */
2
- export class RowCountError extends Error {
3
- code;
4
- expected;
5
- actual;
6
- text;
7
- name = "RowCountError";
8
- constructor(code, expected, actual, text) {
9
- super(`Expected ${expected} row(s) but the query returned ${actual}`);
10
- this.code = code;
11
- this.expected = expected;
12
- this.actual = actual;
13
- this.text = text;
14
- }
15
- }
16
- function run(client, q) {
17
- // `pg` requires a mutable array (`QueryConfigValues<I>` matches `Array<U>` only).
18
- return client.query(q.text, Array.from(q.values));
19
- }
20
- /** An `Executor` for core's `q.execute()`: runs queries on `client` and resolves to the rows. */
1
+ import { runTransaction } from "@typesql/core";
2
+ /**
3
+ * An `Executor` for core's `q.execute()`: runs queries on `client` and resolves to
4
+ * `{ rows, rowCount }` (pg's `rowCount`, so `q.executeCount()` works).
5
+ */
21
6
  export function executor(client) {
22
- return async (text, values) => (await client.query(text, Array.from(values))).rows;
23
- }
24
- /** Run a query and return all rows, typed from the query. */
25
- export async function query(client, q) {
26
- const result = await run(client, q);
27
- return result.rows;
7
+ return async (text, values) => {
8
+ // `pg` requires a mutable array (`QueryConfigValues<I>` matches `Array<U>` only).
9
+ const { rows, rowCount } = await client.query(text, Array.from(values));
10
+ return { rows, rowCount };
11
+ };
28
12
  }
29
- /** Exactly one row, otherwise throws `RowCountError`. */
30
- export async function one(client, q) {
31
- const rows = await query(client, q);
32
- if (rows.length !== 1) {
33
- throw new RowCountError(rows.length === 0 ? "NO_ROWS" : "TOO_MANY_ROWS", "exactly 1", rows.length, q.text);
34
- }
35
- return rows[0];
13
+ function isPool(client) {
14
+ // `pg.Client` has `connect()` too (it opens the socket), and `processID`; a `PoolClient` has `release()`.
15
+ return typeof client.connect === "function" && !("release" in client) && !("processID" in client);
36
16
  }
37
- /** Zero or one row (`null` for zero); throws `RowCountError` on more than one. */
38
- export async function maybeOne(client, q) {
39
- const rows = await query(client, q);
40
- if (rows.length > 1)
41
- throw new RowCountError("TOO_MANY_ROWS", "at most 1", rows.length, q.text);
42
- return rows.length === 0 ? null : rows[0];
43
- }
44
- /** At least one row, otherwise throws `RowCountError`. */
45
- export async function many(client, q) {
46
- const rows = await query(client, q);
47
- if (rows.length === 0)
48
- throw new RowCountError("NO_ROWS", "at least 1", 0, q.text);
49
- return rows;
50
- }
51
- /** Run a statement for its side effect and return the affected row count (`rowCount ?? 0`). */
52
- export async function execute(client, q) {
53
- const result = await run(client, q);
54
- return result.rowCount ?? 0;
17
+ function isConnection(client) {
18
+ return "release" in client || "processID" in client;
55
19
  }
20
+ const on = (c) => (statement) => c.query(statement);
56
21
  /**
57
- * Check out a client, run `fn` inside BEGIN/COMMIT, ROLLBACK on error, and release the
58
- * client. If ROLLBACK itself fails the client is released with the error so the pool
59
- * discards the connection instead of reusing it.
22
+ * Check out a client, run `fn` with it between `BEGIN` and `COMMIT`, and release it, with the
23
+ * error when `ROLLBACK` fails so the pool discards the connection instead of reusing it.
60
24
  */
61
- export async function transaction(pool, fn) {
62
- const client = await pool.connect();
25
+ async function inPoolTransaction(pool, fn) {
26
+ const conn = await pool.connect();
63
27
  let releaseWith;
64
28
  try {
65
- await client.query("BEGIN");
66
- try {
67
- const result = await fn(client);
68
- await client.query("COMMIT");
69
- return result;
70
- }
71
- catch (err) {
72
- try {
73
- await client.query("ROLLBACK");
74
- }
75
- catch (rollbackErr) {
76
- releaseWith = rollbackErr instanceof Error ? rollbackErr : new Error(String(rollbackErr));
77
- }
78
- throw err;
79
- }
29
+ return await runTransaction(on(conn), () => fn(conn), {
30
+ onRollbackError: (err) => {
31
+ releaseWith = err instanceof Error ? err : new Error(String(err));
32
+ },
33
+ });
80
34
  }
81
35
  finally {
82
- client.release(releaseWith);
36
+ conn.release(releaseWith);
37
+ }
38
+ }
39
+ /**
40
+ * Run `fn` inside a transaction: on a pool, on a client checked out of it; on a `Client` or
41
+ * `PoolClient`, on that connection. With `depth > 0` the client is already in a transaction,
42
+ * and `fn` runs in a savepoint.
43
+ */
44
+ function transaction(client, depth, fn) {
45
+ if (depth > 0)
46
+ return runTransaction(on(client), () => fn(client), { savepoint: `typesql_${depth}` });
47
+ if (isPool(client))
48
+ return inPoolTransaction(client, fn);
49
+ if (!isConnection(client)) {
50
+ return Promise.reject(new Error("typesql: sql.transaction() needs a pg Pool, Client or PoolClient, so that BEGIN and COMMIT reach one connection"));
83
51
  }
52
+ return runTransaction(on(client), () => fn(client));
84
53
  }
54
+ /** How `createSql(client)` runs queries and transactions. */
55
+ export const driver = { executor, transaction };
85
56
  /**
86
57
  * Run a migration's statements in order on one connection, inside a single transaction
87
58
  * (all or nothing). Statements are sent as simple queries without parameters, so scripts
88
59
  * with `$$`-quoted function bodies work.
89
60
  */
90
61
  export async function migrate(pool, m) {
91
- await transaction(pool, async (client) => {
62
+ await inPoolTransaction(pool, async (client) => {
92
63
  for (const statement of m.statements)
93
64
  await client.query(statement);
94
65
  });
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,12 +1,21 @@
1
- import { type Sql } from "@typesql/core";
1
+ import { type RowKeys, type TransactionalSql } from "@typesql/core";
2
2
  import { type PgQueryable } from "./client.js";
3
3
  import type { PgTypeMap } from "./type-map.js";
4
- export { NoResultError, type Executor } from "@typesql/core";
5
- export type { PgInterval, PgTypeMap } from "./type-map.js";
6
- export { query, one, maybeOne, many, execute, executor, transaction, migrate, type MigrationSource, RowCountError, type PgQueryable, type PgResult, type PgTransactionClient, type PgPoolLike, } from "./client.js";
4
+ export { NoResultError, type Executor, type TransactionalSql } from "@typesql/core";
5
+ export type { PgInterval, PgParamTypeMap, PgTypeMap } from "./type-map.js";
6
+ export { executor, migrate, type MigrationSource, type PgQueryable, type PgResult, type PgTransactionClient, type PgPoolLike, } from "./client.js";
7
+ /** What `createSql<DB>(client)` returns: core's `Sql` under `PgTypeMap`, with `transaction(fn)`. */
8
+ export type PgSql<DB, Keys extends RowKeys = "preserve"> = TransactionalSql<DB, PgTypeMap, Keys>;
7
9
  /**
8
10
  * `createSql<DB>()` from core, pre-bound to `PgTypeMap` (`count(*)` is `string`, `int8` is `string`, dates are `Date`).
9
- * With a `client` (a `Pool`, `Client` or `PoolClient`), the queries' `execute*` methods run on it.
11
+ * The queries' `execute*` methods run on `client` (a `Pool`, `Client` or `PoolClient`), and
12
+ * `sql.transaction(fn)` runs `fn` with a `sql` bound to one transaction.
13
+ * `{ rowKeys: "camelCase" }` camelCases the rows' keys, in the types and at runtime.
10
14
  */
11
- export declare function createSql<DB>(client?: PgQueryable): Sql<DB, PgTypeMap>;
15
+ export declare function createSql<DB>(client: PgQueryable | undefined, options: {
16
+ readonly rowKeys: "camelCase";
17
+ }): PgSql<DB, "camelCase">;
18
+ export declare function createSql<DB>(client?: PgQueryable, options?: {
19
+ readonly rowKeys?: "preserve";
20
+ }): PgSql<DB>;
12
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,GAAG,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACL,KAAK,EACL,GAAG,EACH,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,WAAW,EACX,OAAO,EACP,KAAK,eAAe,EACpB,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,mBAAmB,EACxB,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAEtE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC7G,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACpF,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EACL,QAAQ,EACR,OAAO,EACP,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,mBAAmB,EACxB,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC;AAErB,oGAAoG;AACpG,MAAM,MAAM,KAAK,CAAC,EAAE,EAAE,IAAI,SAAS,OAAO,GAAG,UAAU,IAAI,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;AAEjG;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAAG,KAAK,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;AACnI,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC"}
package/dist/index.js CHANGED
@@ -1,12 +1,8 @@
1
- import { createSql as createCoreSql } from "@typesql/core";
2
- import { executor } from "./client.js";
1
+ import { createTransactionalSql } from "@typesql/core";
2
+ import { driver } from "./client.js";
3
3
  export { NoResultError } from "@typesql/core";
4
- export { query, one, maybeOne, many, execute, executor, transaction, migrate, RowCountError, } from "./client.js";
5
- /**
6
- * `createSql<DB>()` from core, pre-bound to `PgTypeMap` (`count(*)` is `string`, `int8` is `string`, dates are `Date`).
7
- * With a `client` (a `Pool`, `Client` or `PoolClient`), the queries' `execute*` methods run on it.
8
- */
9
- export function createSql(client) {
10
- return createCoreSql(client && executor(client));
4
+ export { executor, migrate, } from "./client.js";
5
+ export function createSql(client, options) {
6
+ return createTransactionalSql(client, driver, options);
11
7
  }
12
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,IAAI,aAAa,EAAY,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAoB,MAAM,aAAa,CAAC;AAGzD,OAAO,EAAE,aAAa,EAAiB,MAAM,eAAe,CAAC;AAE7D,OAAO,EACL,KAAK,EACL,GAAG,EACH,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,WAAW,EACX,OAAO,EAEP,aAAa,GAKd,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAK,MAAoB;IAChD,OAAO,aAAa,CAAgB,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AAClE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAwD,MAAM,eAAe,CAAC;AAC7G,OAAO,EAAE,MAAM,EAAoB,MAAM,aAAa,CAAC;AAGvD,OAAO,EAAE,aAAa,EAAwC,MAAM,eAAe,CAAC;AAEpF,OAAO,EACL,QAAQ,EACR,OAAO,GAMR,MAAM,aAAa,CAAC;AAarB,MAAM,UAAU,SAAS,CAAK,MAAoB,EAAE,OAAoB;IACtE,OAAO,sBAAsB,CAA6B,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AACrF,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { PgQueryable } from "../client.js";
2
+ import { type GenerateOptions } from "./emit.js";
3
+ import { type IntrospectOptions } from "./introspect.js";
4
+ /** What a `--config` module exports as its default: CLI settings plus every generator option. */
5
+ export interface IntrospectConfig extends GenerateOptions, IntrospectOptions {
6
+ /** Connection string. Default: `--url`, then `$DATABASE_URL`. */
7
+ readonly url?: string;
8
+ /** Output file, relative to the working directory. Default: stdout. */
9
+ readonly out?: string;
10
+ }
11
+ interface Io {
12
+ readonly stdout: (s: string) => void;
13
+ readonly stderr: (s: string) => void;
14
+ readonly env: Readonly<Record<string, string | undefined>>;
15
+ readonly cwd: string;
16
+ /** Opens a client for a connection string; default: a `pg.Client`. */
17
+ readonly connect?: (url: string) => Promise<PgQueryable & {
18
+ end(): Promise<void>;
19
+ }>;
20
+ }
21
+ /** Runs the `typesql` CLI with `argv` (without `node` and the script). Returns the exit code. */
22
+ export declare function main(argv: readonly string[], io?: Io): Promise<number>;
23
+ export {};
24
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/introspect/cli.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAErE,iGAAiG;AACjG,MAAM,WAAW,gBAAiB,SAAQ,eAAe,EAAE,iBAAiB;IAC1E,iEAAiE;IACjE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAmBD,UAAU,EAAE;IACV,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG;QAAE,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC,CAAC;CACrF;AAqBD,iGAAiG;AACjG,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,GAAE,EAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2EzF"}
@@ -0,0 +1,121 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { parseArgs } from "node:util";
5
+ import { generateSource } from "./emit.js";
6
+ import { introspect } from "./introspect.js";
7
+ const USAGE = `Usage: typesql introspect [options]
8
+
9
+ Reads a live Postgres database and writes its typesql schema (tables, views, enums).
10
+
11
+ Options:
12
+ --url <url> connection string (default: $DATABASE_URL)
13
+ --out <file> write the schema to <file> instead of stdout
14
+ --schema <name> schema to read; repeat or comma-separate (default: all but system schemas)
15
+ --exclude <pattern> relation to leave out (name or schema.name, * wildcard); repeat or comma-separate
16
+ --type-name <name> name of the schema interface (default: DB)
17
+ --import-from <mod> module the column helpers come from (default: @typesql/core)
18
+ --config <file> module whose default export holds these options and more
19
+ (columnTypes for JSON columns, imports, column(...) hook)
20
+ --no-comments omit JSDoc from comments, domains and generated columns
21
+ -h, --help show this help
22
+ `;
23
+ const defaultIo = () => ({
24
+ stdout: (s) => process.stdout.write(s),
25
+ stderr: (s) => process.stderr.write(s),
26
+ env: process.env,
27
+ cwd: process.cwd(),
28
+ });
29
+ async function pgConnect(url) {
30
+ let Client;
31
+ try {
32
+ ({ Client } = (await import("pg")).default);
33
+ }
34
+ catch {
35
+ throw new Error('typesql introspect needs the "pg" package: npm install pg');
36
+ }
37
+ const client = new Client({ connectionString: url });
38
+ await client.connect();
39
+ return client;
40
+ }
41
+ /** Runs the `typesql` CLI with `argv` (without `node` and the script). Returns the exit code. */
42
+ export async function main(argv, io = defaultIo()) {
43
+ let parsed;
44
+ try {
45
+ parsed = parseArgs({
46
+ args: [...argv],
47
+ allowPositionals: true,
48
+ options: {
49
+ url: { type: "string" },
50
+ out: { type: "string" },
51
+ schema: { type: "string", multiple: true },
52
+ exclude: { type: "string", multiple: true },
53
+ "type-name": { type: "string" },
54
+ "import-from": { type: "string" },
55
+ config: { type: "string" },
56
+ "no-comments": { type: "boolean" },
57
+ help: { type: "boolean", short: "h" },
58
+ },
59
+ });
60
+ }
61
+ catch (err) {
62
+ io.stderr(`${err.message}\n\n${USAGE}`);
63
+ return 2;
64
+ }
65
+ const { values, positionals } = parsed;
66
+ if (values.help || positionals.length === 0) {
67
+ (values.help ? io.stdout : io.stderr)(USAGE);
68
+ return values.help ? 0 : 2;
69
+ }
70
+ if (positionals[0] !== "introspect" || positionals.length > 1) {
71
+ io.stderr(`unknown command: ${positionals.join(" ")}\n\n${USAGE}`);
72
+ return 2;
73
+ }
74
+ try {
75
+ let config = {};
76
+ if (values.config) {
77
+ const mod = (await import(pathToFileURL(resolve(io.cwd, values.config)).href));
78
+ config = mod.default ?? {};
79
+ }
80
+ const url = values.url ?? config.url ?? io.env["DATABASE_URL"];
81
+ if (!url) {
82
+ io.stderr("typesql introspect: pass --url or set DATABASE_URL\n");
83
+ return 2;
84
+ }
85
+ const list = (v) => v?.flatMap((s) => s.split(",").map((x) => x.trim()).filter(Boolean));
86
+ const schemas = list(values.schema) ?? config.schemas;
87
+ const exclude = list(values.exclude) ?? config.exclude;
88
+ const options = {
89
+ ...config,
90
+ ...(schemas !== undefined && { schemas }),
91
+ ...(exclude !== undefined && { exclude }),
92
+ ...(values["type-name"] !== undefined && { typeName: values["type-name"] }),
93
+ ...(values["import-from"] !== undefined && { importFrom: values["import-from"] }),
94
+ ...(values["no-comments"] && { comments: false }),
95
+ };
96
+ const client = await (io.connect ?? pgConnect)(url);
97
+ let source;
98
+ try {
99
+ source = generateSource(await introspect(client, options), options);
100
+ }
101
+ finally {
102
+ await client.end();
103
+ }
104
+ const out = values.out ?? config.out;
105
+ if (out === undefined) {
106
+ io.stdout(source);
107
+ }
108
+ else {
109
+ const file = resolve(io.cwd, out);
110
+ await mkdir(dirname(file), { recursive: true });
111
+ await writeFile(file, source);
112
+ io.stderr(`typesql introspect: wrote ${out}\n`);
113
+ }
114
+ return 0;
115
+ }
116
+ catch (err) {
117
+ io.stderr(`typesql introspect: ${err.message}\n`);
118
+ return 1;
119
+ }
120
+ }
121
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/introspect/cli.ts"],"names":[],"mappings":"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"}