@deterministic-code/datasources-postgres 0.1.0 → 0.1.2

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 (70) hide show
  1. package/dist/PostgresAlterTableStatementRenderer.d.ts +6 -0
  2. package/dist/PostgresAlterTableStatementRenderer.js +20 -0
  3. package/dist/PostgresBulkUpdateStatementTextRenderer.d.ts +4 -0
  4. package/dist/PostgresBulkUpdateStatementTextRenderer.js +24 -0
  5. package/dist/PostgresCreateRoutineStatementRenderer.d.ts +4 -0
  6. package/dist/PostgresCreateTableStatementRenderer.d.ts +6 -0
  7. package/dist/PostgresCreateTableStatementRenderer.js +26 -0
  8. package/dist/PostgresCreateTriggerStatementRenderer.d.ts +4 -0
  9. package/dist/PostgresCreateTriggerStatementRenderer.js +13 -0
  10. package/dist/PostgresDriver.d.ts +16 -0
  11. package/dist/PostgresDriver.js +75 -0
  12. package/dist/PostgresDropRoutineStatementRenderer.d.ts +4 -0
  13. package/dist/PostgresDropRoutineStatementRenderer.js +6 -0
  14. package/dist/PostgresDropTriggerStatementRenderer.d.ts +4 -0
  15. package/dist/PostgresDropTriggerStatementRenderer.js +6 -0
  16. package/dist/PostgresIdentityInsertStatementRenderer.d.ts +4 -0
  17. package/dist/PostgresIdentityInsertStatementRenderer.js +11 -0
  18. package/dist/PostgresStatementRenderer.d.ts +19 -0
  19. package/dist/PostgresStatementRenderer.js +64 -0
  20. package/dist/PostgresStoredProcedureStatementRenderer.d.ts +10 -0
  21. package/dist/PostgresStoredProcedureStatementRenderer.js +111 -0
  22. package/dist/bind.d.ts +7 -0
  23. package/dist/bind.js +35 -0
  24. package/dist/columnTypes.d.ts +1 -0
  25. package/dist/columnTypes.js +10 -0
  26. package/dist/command.d.ts +14 -0
  27. package/dist/command.js +92 -0
  28. package/dist/connection-options.d.ts +6 -0
  29. package/dist/connection-options.js +1 -0
  30. package/dist/connection.d.ts +21 -0
  31. package/dist/connection.js +72 -0
  32. package/dist/converters/BinaryConverter.d.ts +6 -0
  33. package/dist/converters/BinaryConverter.js +14 -0
  34. package/dist/converters/BoolConverter.d.ts +5 -0
  35. package/dist/converters/BoolConverter.js +5 -0
  36. package/dist/converters/DateTimeConverter.d.ts +6 -0
  37. package/dist/converters/DateTimeConverter.js +6 -0
  38. package/dist/converters/DecimalConverter.d.ts +5 -0
  39. package/dist/converters/DecimalConverter.js +5 -0
  40. package/dist/converters/PostgresRowTypeConverters.d.ts +3 -0
  41. package/dist/converters/PostgresRowTypeConverters.js +19 -0
  42. package/dist/converters/UuidConverter.d.ts +5 -0
  43. package/dist/converters/UuidConverter.js +5 -0
  44. package/dist/i-postgres-driver.d.ts +38 -0
  45. package/dist/i-postgres-driver.js +22 -0
  46. package/dist/index.d.ts +1 -0
  47. package/dist/index.js +1 -0
  48. package/dist/scalar.js +1 -0
  49. package/dist/transaction.d.ts +9 -0
  50. package/dist/transaction.js +15 -0
  51. package/package.json +10 -7
  52. package/src/PostgresBulkUpdateStatementTextRenderer.ts +0 -27
  53. package/src/PostgresCreateTableStatementRenderer.ts +0 -33
  54. package/src/PostgresDriver.ts +0 -55
  55. package/src/PostgresStatementRenderer.ts +0 -34
  56. package/src/bind.ts +0 -50
  57. package/src/columnTypes.ts +0 -10
  58. package/src/command.ts +0 -129
  59. package/src/connection-options.ts +0 -7
  60. package/src/connection.ts +0 -95
  61. package/src/converters/BinaryConverter.ts +0 -20
  62. package/src/converters/BoolConverter.ts +0 -6
  63. package/src/converters/DateTimeConverter.ts +0 -11
  64. package/src/converters/DecimalConverter.ts +0 -7
  65. package/src/converters/PostgresRowTypeConverters.ts +0 -24
  66. package/src/converters/UuidConverter.ts +0 -6
  67. package/src/i-postgres-driver.ts +0 -61
  68. package/src/index.ts +0 -1
  69. package/src/transaction.ts +0 -21
  70. /package/{src/scalar.ts → dist/scalar.d.ts} +0 -0
package/src/command.ts DELETED
@@ -1,129 +0,0 @@
1
- import {
2
- ArrayReader,
3
- CommandMiddlewareHost,
4
- FirstResultReader,
5
- DatasourceError,
6
- Native,
7
- ParameterDirection,
8
- ReturnStatement,
9
- SelectStatement,
10
- StatementTextRenderer,
11
- Response,
12
- splitStatements,
13
- statementParameters,
14
- statementReader,
15
- type Cells,
16
- type ICommand,
17
- type IReader,
18
- type IStatement,
19
- type Parameter,
20
- } from "@deterministic-code/datasources";
21
- import { bindParameters, toPostgres } from "./bind.ts";
22
- import type { PostgresConnection } from "./connection.ts";
23
- import type { PostgresExecuteResult } from "./i-postgres-driver.ts";
24
- import type { Scalar } from "./scalar.ts";
25
- import { PostgresStatementRenderer } from "./PostgresStatementRenderer.ts";
26
-
27
- export class PostgresCommand extends CommandMiddlewareHost implements ICommand {
28
- private readonly statements: StatementTextRenderer;
29
-
30
- constructor(readonly connection: PostgresConnection, statements?: StatementTextRenderer) {
31
- super();
32
- this.statements = statements ?? new StatementTextRenderer(t => new PostgresStatementRenderer(t));
33
- }
34
-
35
- async executeReaderNative(
36
- text: Native,
37
- parameters?: Parameter[],
38
- ): Promise<IReader<Cells>> {
39
- return this.run(text.text, parameters, async (query, params) => {
40
- if (!query.trim()) return { value: new ArrayReader([]), rows: [] };
41
- this.connection.ensureOpen();
42
- const statements = splitStatements(query);
43
- if (statements.length === 0) return { value: new ArrayReader([]), rows: [] };
44
- const bound = bindParameters(params);
45
- return FirstResultReader.capture(statementReader(statements, (sql) => this.query(sql, bound)));
46
- });
47
- }
48
-
49
- async executeReaderStatement(
50
- statement: IStatement,
51
- parameters?: Parameter[],
52
- ): Promise<IReader<Cells>> {
53
- return this.executeReaderNative(new Native(this.statements.render(statement)), parameters);
54
- }
55
-
56
- async executeStatement(statement: IStatement, parameters?: Parameter[]): Promise<Response> {
57
- return statement instanceof SelectStatement || statement instanceof ReturnStatement
58
- ? this.firstCell(statement, parameters)
59
- : this.executeNative(new Native(this.statements.render(statement)), parameters);
60
- }
61
-
62
- private async firstCell(statement: IStatement, parameters?: Parameter[]): Promise<Response> {
63
- const reader = await this.executeReaderStatement(statement, parameters);
64
- try {
65
- if (!(await reader.next())) return new Response(null, 0, parameters);
66
- const row = reader.current;
67
- /* v8 ignore next */
68
- if (!row) throw new DatasourceError("Reader current must be a row");
69
- const values = Object.values(row);
70
- return new Response(values.length === 0 ? null : values[0], 1, parameters);
71
- } finally {
72
- await reader.dispose();
73
- }
74
- }
75
-
76
- async executeNative(text: Native, parameters?: Parameter[]): Promise<Response> {
77
- return this.run(text.text, parameters, async (query, params) => {
78
- if (!query.trim())
79
- return { value: new Response(undefined, 0, params), rows: [] };
80
- this.connection.ensureOpen();
81
- const named = bindParameters(params);
82
- let rowsAffected = 0;
83
- let parameters = params;
84
- for (const part of splitStatements(query)) {
85
- const names = new Set(statementParameters(part));
86
- const used = Object.fromEntries(
87
- Object.entries(named).filter(([name]) => names.has(name.replace(/^[$:@]/, ""))),
88
- );
89
- const result = await this.runSql(part, used, params);
90
- rowsAffected += result.rowsAffected;
91
- parameters = result.parameters ?? params;
92
- }
93
- return {
94
- value: new Response(null, rowsAffected, parameters),
95
- rows: [],
96
- };
97
- });
98
- }
99
-
100
- private async runSql(
101
- sql: string,
102
- params?: Record<string, Scalar>,
103
- parameters?: Parameter[],
104
- ): Promise<PostgresExecuteResult> {
105
- const { text, values } = toPostgres(sql, params);
106
- const queried = await this.connection.require().query(text, values);
107
- const row = queried.rows[0];
108
- return {
109
- rowsAffected: queried.rowCount ?? queried.rows.length,
110
- result: null,
111
- parameters: parameters?.map((parameter) => {
112
- if (!parameter.direction || parameter.direction === ParameterDirection.Input || !row)
113
- return parameter;
114
- const cells = row as Record<string, Scalar | object>;
115
- const cell = cells[parameter.name] ?? cells[parameter.name.toLowerCase()];
116
- if (cell === undefined) return parameter;
117
- return { ...parameter, value: cellValue(cell) };
118
- }),
119
- };
120
- }
121
-
122
- private query(sql: string, params?: Record<string, Scalar>): AsyncIterable<Cells> {
123
- const { text, values } = toPostgres(sql, params);
124
- return this.connection.require().rows(text, values);
125
- }
126
- }
127
-
128
- const cellValue = (cell: Scalar | object): Scalar =>
129
- cell !== null && typeof cell === "object" ? JSON.stringify(cell) : cell;
@@ -1,7 +0,0 @@
1
- import type { PgClientCtor } from "./i-postgres-driver.ts";
2
-
3
- export interface PostgresConnectionOptions {
4
- url?: string;
5
- schema?: string;
6
- Client?: PgClientCtor;
7
- }
package/src/connection.ts DELETED
@@ -1,95 +0,0 @@
1
- import {
2
- DatasourceError,
3
- DatasourceUrlParser,
4
- IsolationLevel,
5
- StatementTextRenderer,
6
- type DatasourceOptions,
7
- type ICommand,
8
- type IConnection,
9
- type IsolationLevelName,
10
- type ITransaction,
11
- } from "@deterministic-code/datasources";
12
- import { createRequire } from "node:module";
13
- import { PostgresCommand } from "./command.ts";
14
- import type { PostgresConnectionOptions } from "./connection-options.ts";
15
- import { pgClient, type IPgClient, type PgClientCtor, type PgModule } from "./i-postgres-driver.ts";
16
- import { PostgresStatementRenderer } from "./PostgresStatementRenderer.ts";
17
- import { PostgresTransaction } from "./transaction.ts";
18
-
19
- const require = createRequire(import.meta.url);
20
-
21
- const isoSql = (isolation: IsolationLevelName): string =>
22
- isolation === IsolationLevel.ReadUncommitted
23
- ? "READ UNCOMMITTED"
24
- : isolation === IsolationLevel.ReadCommitted
25
- ? "READ COMMITTED"
26
- : isolation === IsolationLevel.RepeatableRead
27
- ? "REPEATABLE READ"
28
- : "SERIALIZABLE";
29
-
30
- export class PostgresConnection implements IConnection {
31
- readonly provider = "postgres";
32
- url: string;
33
- schema?: string;
34
- isOpen = false;
35
- private client?: IPgClient;
36
- private readonly Client?: PgClientCtor;
37
-
38
- static from = (options?: DatasourceOptions): PostgresConnection => {
39
- const url = options?.DATASOURCE_URL ?? "";
40
- return new PostgresConnection({
41
- url,
42
- schema: DatasourceUrlParser.parse(url)?.schema,
43
- Client: pgClient(require("pg") as PgModule),
44
- });
45
- };
46
-
47
- constructor(options: PostgresConnectionOptions = {}) {
48
- this.url = options.url ?? "";
49
- this.schema = options.schema;
50
- this.Client = options.Client;
51
- }
52
-
53
- createCommand = (): ICommand =>
54
- new PostgresCommand(this, new StatementTextRenderer(t => new PostgresStatementRenderer(t)));
55
-
56
- async open(): Promise<void> {
57
- if (this.isOpen) throw new DatasourceError("Connection is already open");
58
- if (!this.client) {
59
- if (!this.Client) throw new DatasourceError("Postgres driver is required");
60
- this.client = new this.Client({ connectionString: this.url });
61
- }
62
- await this.client.connect();
63
- if (this.schema) await this.client.query(`SET search_path TO ${this.schema}`);
64
- this.isOpen = true;
65
- }
66
-
67
- async close(): Promise<void> {
68
- await this.client?.end();
69
- this.client = undefined;
70
- this.isOpen = false;
71
- }
72
-
73
- [Symbol.asyncDispose] = (): Promise<void> => this.close();
74
-
75
- async startTransaction(
76
- isolation: IsolationLevelName = IsolationLevel.ReadCommitted,
77
- ): Promise<ITransaction> {
78
- this.ensureOpen();
79
- await this.exec(`BEGIN ISOLATION LEVEL ${isoSql(isolation)}`);
80
- return new PostgresTransaction(this, isolation);
81
- }
82
-
83
- ensureOpen(): void {
84
- if (!this.isOpen) throw new DatasourceError("Connection is not open");
85
- }
86
-
87
- require(): IPgClient {
88
- if (!this.client) throw new DatasourceError("Connection is not open");
89
- return this.client;
90
- }
91
-
92
- async exec(sql: string): Promise<void> {
93
- await this.require().query(sql);
94
- }
95
- }
@@ -1,20 +0,0 @@
1
- import { TypeConverter, type Cell } from "@deterministic-code/datasources";
2
-
3
- export const isBase64 = (value: string): boolean => {
4
- const text = value.trim();
5
- return (
6
- text.length >= 4 &&
7
- text.length % 4 === 0 &&
8
- text.includes("=") &&
9
- /^[A-Za-z0-9+/]+=*$/.test(text) &&
10
- Buffer.from(text, "base64").toString("base64") === text
11
- );
12
- };
13
-
14
- const bytes = (value: Cell): Cell =>
15
- typeof value === "string" ? Uint8Array.from(Buffer.from(value, "base64")) : value;
16
-
17
- export class BinaryConverter extends TypeConverter<Cell, Cell> {
18
- convert = (from: Cell): Cell => bytes(from);
19
- reverseConvert = (to: Cell): Cell => bytes(to);
20
- }
@@ -1,6 +0,0 @@
1
- import { TypeConverter, type Cell } from "@deterministic-code/datasources";
2
-
3
- export class BoolConverter extends TypeConverter<Cell, Cell> {
4
- convert = (from: Cell): Cell => (typeof from === "number" ? from !== 0 : from);
5
- reverseConvert = (to: Cell): Cell => to;
6
- }
@@ -1,11 +0,0 @@
1
- import { TypeConverter, type Cell } from "@deterministic-code/datasources";
2
-
3
- export const isIsoDate = (value: string): boolean =>
4
- /^\d{4}-\d{2}-\d{2}T/.test(value) && !Number.isNaN(Date.parse(value));
5
-
6
- export class DateTimeConverter extends TypeConverter<Cell, Cell> {
7
- convert = (from: Cell): Cell =>
8
- typeof from === "string" ? new Date(from) : from;
9
- reverseConvert = (to: Cell): Cell =>
10
- to instanceof Date ? to.toISOString() : to;
11
- }
@@ -1,7 +0,0 @@
1
- import { TypeConverter, type Cell } from "@deterministic-code/datasources";
2
-
3
- export class DecimalConverter extends TypeConverter<Cell, Cell> {
4
- convert = (from: Cell): Cell => from;
5
- reverseConvert = (to: Cell): Cell =>
6
- typeof to === "number" ? String(to) : to;
7
- }
@@ -1,24 +0,0 @@
1
- import { type Cell, type TypeConverter } from "@deterministic-code/datasources";
2
- import { BinaryConverter } from "./BinaryConverter.ts";
3
- import { BoolConverter } from "./BoolConverter.ts";
4
- import { DateTimeConverter } from "./DateTimeConverter.ts";
5
- import { DecimalConverter } from "./DecimalConverter.ts";
6
- import { UuidConverter } from "./UuidConverter.ts";
7
-
8
- export const PostgresRowTypeConverters: Record<string, TypeConverter<Cell, Cell>> = {
9
- bool: new BoolConverter(),
10
- datetime: new DateTimeConverter(),
11
- uuid: new UuidConverter(),
12
- decimal: new DecimalConverter(),
13
- binary: new BinaryConverter(),
14
- };
15
-
16
- export const reverse = (value: Cell): Cell =>
17
- typeof value === "boolean"
18
- ? PostgresRowTypeConverters.bool.reverseConvert(value)
19
- : value instanceof Date
20
- ? PostgresRowTypeConverters.datetime.reverseConvert(value)
21
- : value instanceof Uint8Array
22
- ? PostgresRowTypeConverters.binary.reverseConvert(value)
23
- : value;
24
-
@@ -1,6 +0,0 @@
1
- import { TypeConverter, type Cell } from "@deterministic-code/datasources";
2
-
3
- export class UuidConverter extends TypeConverter<Cell, Cell> {
4
- convert = (from: Cell): Cell => from;
5
- reverseConvert = (to: Cell): Cell => to;
6
- }
@@ -1,61 +0,0 @@
1
- import type { Parameter } from "@deterministic-code/datasources";
2
- import QueryStream from "pg-query-stream";
3
- import type { Cells, Scalar, Wire } from "./scalar.ts";
4
-
5
- export interface PostgresExecuteResult {
6
- rowsAffected: number;
7
- result?: Scalar;
8
- parameters?: Parameter[];
9
- }
10
-
11
- export interface PgQueryResult {
12
- rowCount: number | null;
13
- rows: Cells[];
14
- }
15
-
16
- export interface IPgClient {
17
- connect(): Promise<void>;
18
- query(text: string, values?: Wire[]): Promise<PgQueryResult>;
19
- rows(text: string, values?: Wire[]): AsyncIterable<Cells>;
20
- end(): Promise<void>;
21
- }
22
-
23
- interface PgNativeClient {
24
- connect(): Promise<void>;
25
- query(text: string, values?: Wire[]): Promise<PgQueryResult>;
26
- query(query: QueryStream): AsyncIterable<Cells>;
27
- end(): Promise<void>;
28
- }
29
-
30
- export type PgClientCtor = new (options: {
31
- connectionString: string;
32
- }) => IPgClient;
33
-
34
- type PgNativeCtor = new (options: { connectionString: string }) => PgNativeClient;
35
-
36
- export type PgModule = {
37
- Client: PgNativeCtor;
38
- default?: { Client: PgNativeCtor };
39
- };
40
-
41
- export const pgClient = (imported: PgModule): PgClientCtor => {
42
- const Client = imported.default?.Client ?? imported.Client;
43
- return class implements IPgClient {
44
- private readonly inner: PgNativeClient;
45
- constructor(options: { connectionString: string }) {
46
- this.inner = new Client(options);
47
- }
48
- connect(): Promise<void> {
49
- return this.inner.connect();
50
- }
51
- query(text: string, values?: Wire[]): Promise<PgQueryResult> {
52
- return this.inner.query(text, values);
53
- }
54
- rows(text: string, values?: Wire[]): AsyncIterable<Cells> {
55
- return this.inner.query(new QueryStream(text, values ?? []));
56
- }
57
- end(): Promise<void> {
58
- return this.inner.end();
59
- }
60
- };
61
- };
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export { PostgresDriver } from "./PostgresDriver.ts";
@@ -1,21 +0,0 @@
1
- import {
2
- IsolationLevel,
3
- type ITransaction,
4
- type IsolationLevelName,
5
- } from "@deterministic-code/datasources";
6
- import type { PostgresConnection } from "./connection.ts";
7
-
8
- export class PostgresTransaction implements ITransaction {
9
- constructor(
10
- readonly connection: PostgresConnection,
11
- readonly isolation: IsolationLevelName = IsolationLevel.ReadCommitted,
12
- ) {}
13
-
14
- async commit(): Promise<void> {
15
- await this.connection.exec("COMMIT");
16
- }
17
-
18
- async abort(): Promise<void> {
19
- await this.connection.exec("ROLLBACK");
20
- }
21
- }
File without changes