@snowtop/ent 0.2.9 → 0.2.11
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/action/index.d.ts +7 -4
- package/action/index.js +1 -0
- package/auth/index.d.ts +2 -1
- package/core/base.d.ts +1 -1
- package/core/config.d.ts +4 -0
- package/core/config.js +5 -1
- package/core/convert.d.ts +4 -0
- package/core/convert.js +70 -2
- package/core/date.js +5 -2
- package/core/db.d.ts +45 -3
- package/core/db.js +260 -24
- package/core/ent.js +9 -5
- package/core/extensions.d.ts +8 -3
- package/core/extensions.js +10 -1
- package/core/global_schema.js +1 -1
- package/core/loaders/loader.d.ts +4 -4
- package/core/logger.js +4 -2
- package/core/privacy.d.ts +2 -6
- package/core/privacy.js +8 -2
- package/core/query/index.d.ts +4 -2
- package/graphql/graphql.d.ts +2 -0
- package/graphql/graphql.js +91 -22
- package/graphql/index.d.ts +6 -3
- package/index.d.ts +10 -5
- package/package.json +15 -15
- package/schema/base_schema.d.ts +1 -1
- package/schema/index.d.ts +5 -4
- package/schema/schema.d.ts +3 -1
- package/scripts/custom_graphql.js +71 -53
- package/scripts/read_schema.js +6 -11
- package/scripts/stdout.d.ts +1 -0
- package/scripts/stdout.js +18 -0
- package/testutils/ent-graphql-tests/index.d.ts +6 -0
- package/testutils/ent-graphql-tests/index.js +142 -54
package/action/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
export { WriteOperation,
|
|
2
|
-
export {
|
|
1
|
+
export { WriteOperation, saveBuilder, saveBuilderX, setEdgeTypeInGroup, } from "./action";
|
|
2
|
+
export { Orchestrator, EntChangeset } from "./orchestrator";
|
|
3
|
+
export type { Action, Builder, Changeset, ChangesetOptions, Observer, Trigger, TriggerReturn, Validator, } from "./action";
|
|
4
|
+
export type { OrchestratorOptions, EdgeInputData } from "./orchestrator";
|
|
3
5
|
export { DenyIfBuilder, AllowIfBuilder } from "./privacy";
|
|
4
|
-
export {
|
|
6
|
+
export { NumberOps, convertRelativeInput, maybeConvertRelativeInputPlusExpressions, } from "./relative_value";
|
|
7
|
+
export type { RelativeFieldValue, RelativeNumberValue, } from "./relative_value";
|
|
5
8
|
export { Transaction } from "./transaction";
|
|
6
|
-
export { AssocEdgeOptions } from "./operations";
|
|
9
|
+
export type { AssocEdgeOptions } from "./operations";
|
package/action/index.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Transaction = exports.maybeConvertRelativeInputPlusExpressions = exports.convertRelativeInput = exports.NumberOps = exports.AllowIfBuilder = exports.DenyIfBuilder = exports.EntChangeset = exports.Orchestrator = exports.setEdgeTypeInGroup = exports.saveBuilderX = exports.saveBuilder = exports.WriteOperation = void 0;
|
|
4
4
|
var action_1 = require("./action");
|
|
5
5
|
Object.defineProperty(exports, "WriteOperation", { enumerable: true, get: function () { return action_1.WriteOperation; } });
|
|
6
|
+
// make sure not to expose Executor...
|
|
6
7
|
Object.defineProperty(exports, "saveBuilder", { enumerable: true, get: function () { return action_1.saveBuilder; } });
|
|
7
8
|
Object.defineProperty(exports, "saveBuilderX", { enumerable: true, get: function () { return action_1.saveBuilderX; } });
|
|
8
9
|
Object.defineProperty(exports, "setEdgeTypeInGroup", { enumerable: true, get: function () { return action_1.setEdgeTypeInGroup; } });
|
package/auth/index.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { registerAuthHandler, clearAuthHandlers, getLoggedInViewer, buildContext, } from "./auth";
|
|
2
|
+
export type { AuthHandler, AuthViewer } from "./auth";
|
package/core/base.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ export interface Ent<TViewer extends Viewer = Viewer> {
|
|
|
53
53
|
viewer: TViewer;
|
|
54
54
|
getPrivacyPolicy(): PrivacyPolicy<this, TViewer>;
|
|
55
55
|
nodeType: string;
|
|
56
|
-
__setRawDBData<T extends Data = Data>(data: T):
|
|
56
|
+
__setRawDBData<T extends Data = Data>(data: T): void;
|
|
57
57
|
}
|
|
58
58
|
export declare type Data = {
|
|
59
59
|
[key: string]: any;
|
package/core/config.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ declare enum fieldPrivacyEvaluated {
|
|
|
12
12
|
AT_ENT_LOAD = "at_ent_load",
|
|
13
13
|
ON_DEMAND = "on_demand"
|
|
14
14
|
}
|
|
15
|
+
export type RuntimeMode = "node" | "bun";
|
|
16
|
+
export type PostgresDriver = "pg" | "bun";
|
|
15
17
|
export interface RuntimeDBExtension {
|
|
16
18
|
name: string;
|
|
17
19
|
provisionedBy?: "ent" | "external";
|
|
@@ -21,6 +23,8 @@ export interface RuntimeDBExtension {
|
|
|
21
23
|
dropCascade?: boolean;
|
|
22
24
|
}
|
|
23
25
|
export interface Config {
|
|
26
|
+
runtime?: RuntimeMode;
|
|
27
|
+
postgresDriver?: PostgresDriver;
|
|
24
28
|
dbConnectionString?: string;
|
|
25
29
|
dbFile?: string;
|
|
26
30
|
db?: Database | DBDict;
|
package/core/config.js
CHANGED
|
@@ -70,8 +70,12 @@ function setConfig(cfg) {
|
|
|
70
70
|
cfg.dbFile ||
|
|
71
71
|
cfg.db ||
|
|
72
72
|
cfg.devSchema ||
|
|
73
|
-
cfg.extensions
|
|
73
|
+
cfg.extensions ||
|
|
74
|
+
cfg.runtime ||
|
|
75
|
+
cfg.postgresDriver) {
|
|
74
76
|
db_1.default.initDB({
|
|
77
|
+
runtime: cfg.runtime,
|
|
78
|
+
postgresDriver: cfg.postgresDriver,
|
|
75
79
|
connectionString: cfg.dbConnectionString,
|
|
76
80
|
dbFile: cfg.dbFile,
|
|
77
81
|
db: cfg.db,
|
package/core/convert.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export declare function convertDBDate(val: any): string;
|
|
2
|
+
export declare function convertNullableDBDate(val: any): string | null;
|
|
3
|
+
export declare function convertDBDateList(val: any): string[];
|
|
4
|
+
export declare function convertNullableDBDateList(val: any): string[] | null;
|
|
1
5
|
export declare function convertDate(val: any): Date;
|
|
2
6
|
export declare function convertNullableDate(val: any): Date | null;
|
|
3
7
|
export declare function convertBool(val: any): boolean;
|
package/core/convert.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.convertDBDate = convertDBDate;
|
|
7
|
+
exports.convertNullableDBDate = convertNullableDBDate;
|
|
8
|
+
exports.convertDBDateList = convertDBDateList;
|
|
9
|
+
exports.convertNullableDBDateList = convertNullableDBDateList;
|
|
3
10
|
exports.convertDate = convertDate;
|
|
4
11
|
exports.convertNullableDate = convertNullableDate;
|
|
5
12
|
exports.convertBool = convertBool;
|
|
@@ -16,7 +23,49 @@ exports.convertJSONList = convertJSONList;
|
|
|
16
23
|
exports.convertNullableJSONList = convertNullableJSONList;
|
|
17
24
|
exports.convertTextToBuffer = convertTextToBuffer;
|
|
18
25
|
exports.convertNullableTextToBuffer = convertNullableTextToBuffer;
|
|
26
|
+
const pg_1 = __importDefault(require("pg"));
|
|
19
27
|
const luxon_1 = require("luxon");
|
|
28
|
+
const TEXT_ARRAY_OID = 1009;
|
|
29
|
+
const parseTextArray = pg_1.default.types.getTypeParser(TEXT_ARRAY_OID);
|
|
30
|
+
function normalizeArrayLikeObject(val) {
|
|
31
|
+
// This only runs for list-typed fields. Bun's native Postgres client can return
|
|
32
|
+
// some arrays as `{0: ..., 1: ...}` objects instead of real JS arrays.
|
|
33
|
+
const keys = Object.keys(val);
|
|
34
|
+
if (!keys.length) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
if (keys.every((key) => /^\d+$/.test(key))) {
|
|
38
|
+
return keys
|
|
39
|
+
.sort((a, b) => parseInt(a, 10) - parseInt(b, 10))
|
|
40
|
+
.map((key) => val[key]);
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`got a non-array from the db: ${JSON.stringify(val)}`);
|
|
43
|
+
}
|
|
44
|
+
function convertDBDate(val) {
|
|
45
|
+
if (typeof val === "string") {
|
|
46
|
+
return val.slice(0, 10);
|
|
47
|
+
}
|
|
48
|
+
const dt = luxon_1.DateTime.fromJSDate(new Date(val), { zone: "utc" });
|
|
49
|
+
if (dt.isValid) {
|
|
50
|
+
const date = dt.toISODate();
|
|
51
|
+
if (date) {
|
|
52
|
+
return date;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return new Date(val).toISOString().slice(0, 10);
|
|
56
|
+
}
|
|
57
|
+
function convertNullableDBDate(val) {
|
|
58
|
+
if (val === null || val === undefined) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
return convertDBDate(val);
|
|
62
|
+
}
|
|
63
|
+
function convertDBDateList(val) {
|
|
64
|
+
return convertList(val, convertDBDate);
|
|
65
|
+
}
|
|
66
|
+
function convertNullableDBDateList(val) {
|
|
67
|
+
return convertNullableList(val, convertDBDate);
|
|
68
|
+
}
|
|
20
69
|
// these are needed to deal with SQLite having different types stored in the db vs the representation
|
|
21
70
|
// gotten back from the db/needed in ent land
|
|
22
71
|
// see Sqlite.execSync
|
|
@@ -53,10 +102,29 @@ function convertNullableBool(val) {
|
|
|
53
102
|
return convertBool(val);
|
|
54
103
|
}
|
|
55
104
|
function convertList(val, conv) {
|
|
105
|
+
let res;
|
|
56
106
|
if (Array.isArray(val)) {
|
|
57
|
-
|
|
107
|
+
res = [...val];
|
|
108
|
+
}
|
|
109
|
+
else if (val && typeof val === "object") {
|
|
110
|
+
res = normalizeArrayLikeObject(val);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
try {
|
|
114
|
+
res = JSON.parse(val);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
if (typeof val === "string" && val.startsWith("{") && val.endsWith("}")) {
|
|
118
|
+
res = parseTextArray(val);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (res && typeof res === "object" && !Array.isArray(res)) {
|
|
126
|
+
res = normalizeArrayLikeObject(res);
|
|
58
127
|
}
|
|
59
|
-
let res = JSON.parse(val);
|
|
60
128
|
if (!conv) {
|
|
61
129
|
return res;
|
|
62
130
|
}
|
package/core/date.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseDate = parseDate;
|
|
4
4
|
const luxon_1 = require("luxon");
|
|
5
|
+
function isDateLike(val) {
|
|
6
|
+
return !!val && typeof val === "object" && typeof val.getTime === "function";
|
|
7
|
+
}
|
|
5
8
|
function parseDate(val, throwErr) {
|
|
6
9
|
let dt;
|
|
7
10
|
if (typeof val === "number") {
|
|
@@ -13,8 +16,8 @@ function parseDate(val, throwErr) {
|
|
|
13
16
|
dt = luxon_1.DateTime.fromMillis(Date.parse(val));
|
|
14
17
|
}
|
|
15
18
|
}
|
|
16
|
-
else if (val instanceof Date) {
|
|
17
|
-
dt = luxon_1.DateTime.fromJSDate(val);
|
|
19
|
+
else if (val instanceof Date || isDateLike(val)) {
|
|
20
|
+
dt = luxon_1.DateTime.fromJSDate(val instanceof Date ? val : new Date(val.getTime()));
|
|
18
21
|
}
|
|
19
22
|
else if (val instanceof luxon_1.DateTime) {
|
|
20
23
|
dt = val;
|
package/core/db.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Pool, PoolClient, PoolConfig } from "pg";
|
|
2
|
-
import type { RuntimeDBExtension, RuntimeDevSchemaConfig } from "./config";
|
|
2
|
+
import type { PostgresDriver, RuntimeDBExtension, RuntimeDevSchemaConfig, RuntimeMode } from "./config";
|
|
3
3
|
export interface Database extends PoolConfig {
|
|
4
4
|
database?: string;
|
|
5
5
|
user?: string;
|
|
@@ -10,6 +10,22 @@ export interface Database extends PoolConfig {
|
|
|
10
10
|
}
|
|
11
11
|
export type env = "production" | "test" | "development";
|
|
12
12
|
export declare type DBDict = Partial<Record<env, Database>>;
|
|
13
|
+
interface BunSQLResult extends Array<QueryResultRow> {
|
|
14
|
+
count?: number;
|
|
15
|
+
affectedRows?: number;
|
|
16
|
+
}
|
|
17
|
+
interface BunSQLClientLike {
|
|
18
|
+
unsafe(query: string, values?: any[]): Promise<BunSQLResult>;
|
|
19
|
+
}
|
|
20
|
+
interface BunSQLReservedClient extends BunSQLClientLike {
|
|
21
|
+
release(): void | Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
interface BunSQLPool extends BunSQLClientLike {
|
|
24
|
+
reserve(): Promise<BunSQLReservedClient>;
|
|
25
|
+
close(options?: {
|
|
26
|
+
timeout?: number;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
}
|
|
13
29
|
export declare enum Dialect {
|
|
14
30
|
Postgres = "postgres",
|
|
15
31
|
SQLite = "sqlite"
|
|
@@ -17,11 +33,15 @@ export declare enum Dialect {
|
|
|
17
33
|
interface DatabaseInfo {
|
|
18
34
|
dialect: Dialect;
|
|
19
35
|
config: PoolConfig;
|
|
36
|
+
runtime?: RuntimeMode;
|
|
37
|
+
postgresDriver?: PostgresDriver;
|
|
20
38
|
filePath?: string;
|
|
21
39
|
devSchema?: RuntimeDevSchemaConfig;
|
|
22
40
|
extensions?: RuntimeDBExtension[];
|
|
23
41
|
}
|
|
24
42
|
interface clientConfigArgs {
|
|
43
|
+
runtime?: RuntimeMode;
|
|
44
|
+
postgresDriver?: PostgresDriver;
|
|
25
45
|
connectionString?: string;
|
|
26
46
|
dbFile?: string;
|
|
27
47
|
db?: Database | DBDict;
|
|
@@ -33,7 +53,6 @@ export default class DB {
|
|
|
33
53
|
db: DatabaseInfo;
|
|
34
54
|
static instance: DB;
|
|
35
55
|
static dialect: Dialect;
|
|
36
|
-
private pool;
|
|
37
56
|
private q;
|
|
38
57
|
private constructor();
|
|
39
58
|
getConnection(): Connection;
|
|
@@ -61,7 +80,7 @@ export interface Connection extends Queryer {
|
|
|
61
80
|
self(): Queryer;
|
|
62
81
|
newClient(): Promise<Client>;
|
|
63
82
|
close(): Promise<void>;
|
|
64
|
-
runInTransaction?(cb: () => void | Promise<void>):
|
|
83
|
+
runInTransaction?(cb: () => void | Promise<void>): void | Promise<void>;
|
|
65
84
|
}
|
|
66
85
|
export interface QueryResultRow {
|
|
67
86
|
[column: string]: any;
|
|
@@ -138,4 +157,27 @@ export declare class PostgresClient implements Client {
|
|
|
138
157
|
exec(query: string, values?: any[]): Promise<ExecResult>;
|
|
139
158
|
release(err?: Error | boolean): Promise<void>;
|
|
140
159
|
}
|
|
160
|
+
export declare class BunPostgres implements Connection {
|
|
161
|
+
private sql;
|
|
162
|
+
private ready?;
|
|
163
|
+
private closePromise?;
|
|
164
|
+
constructor(sql: BunSQLPool, ready?: Promise<void> | undefined);
|
|
165
|
+
private ensureReady;
|
|
166
|
+
self(): this;
|
|
167
|
+
newClient(): Promise<BunPostgresClient>;
|
|
168
|
+
query(query: string, values?: any[]): Promise<QueryResult<QueryResultRow>>;
|
|
169
|
+
queryAll(query: string, values?: any[]): Promise<QueryResult<QueryResultRow>>;
|
|
170
|
+
exec(query: string, values?: any[]): Promise<ExecResult>;
|
|
171
|
+
close(): Promise<void>;
|
|
172
|
+
}
|
|
173
|
+
export declare class BunPostgresClient implements Client {
|
|
174
|
+
private client;
|
|
175
|
+
private ready?;
|
|
176
|
+
constructor(client: BunSQLReservedClient, ready?: Promise<void> | undefined);
|
|
177
|
+
private ensureReady;
|
|
178
|
+
query(query: string, values?: any[]): Promise<QueryResult<QueryResultRow>>;
|
|
179
|
+
queryAll(query: string, values?: any[]): Promise<QueryResult<QueryResultRow>>;
|
|
180
|
+
exec(query: string, values?: any[]): Promise<ExecResult>;
|
|
181
|
+
release(err?: Error | boolean): Promise<void>;
|
|
182
|
+
}
|
|
141
183
|
export {};
|
package/core/db.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.PostgresClient = exports.Postgres = exports.Sqlite = exports.defaultTimestampParser = exports.Dialect = void 0;
|
|
36
|
+
exports.BunPostgresClient = exports.BunPostgres = exports.PostgresClient = exports.Postgres = exports.Sqlite = exports.defaultTimestampParser = exports.Dialect = void 0;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const js_yaml_1 = require("js-yaml");
|
|
39
39
|
const luxon_1 = require("luxon");
|
|
@@ -41,16 +41,42 @@ const pg_1 = __importStar(require("pg"));
|
|
|
41
41
|
const logger_1 = require("./logger");
|
|
42
42
|
const dev_schema_1 = require("./dev_schema");
|
|
43
43
|
const extensions_1 = require("./extensions");
|
|
44
|
+
const knownEnvs = ["production", "development", "test"];
|
|
45
|
+
function isEnv(value) {
|
|
46
|
+
return knownEnvs.includes(value);
|
|
47
|
+
}
|
|
44
48
|
function isDbDict(v) {
|
|
45
|
-
return (
|
|
46
|
-
v["development"] !== undefined ||
|
|
47
|
-
v["test"] !== undefined);
|
|
49
|
+
return knownEnvs.some((key) => key in v);
|
|
48
50
|
}
|
|
49
51
|
var Dialect;
|
|
50
52
|
(function (Dialect) {
|
|
51
53
|
Dialect["Postgres"] = "postgres";
|
|
52
54
|
Dialect["SQLite"] = "sqlite";
|
|
53
55
|
})(Dialect || (exports.Dialect = Dialect = {}));
|
|
56
|
+
function normalizeRuntimeMode(runtime) {
|
|
57
|
+
switch (runtime) {
|
|
58
|
+
case undefined:
|
|
59
|
+
case "":
|
|
60
|
+
case "node":
|
|
61
|
+
return "node";
|
|
62
|
+
case "bun":
|
|
63
|
+
return "bun";
|
|
64
|
+
default:
|
|
65
|
+
throw new Error(`invalid runtime "${runtime}". valid values: node, bun`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function normalizePostgresDriver(driver) {
|
|
69
|
+
switch (driver) {
|
|
70
|
+
case undefined:
|
|
71
|
+
case "":
|
|
72
|
+
case "pg":
|
|
73
|
+
return "pg";
|
|
74
|
+
case "bun":
|
|
75
|
+
return "bun";
|
|
76
|
+
default:
|
|
77
|
+
throw new Error(`invalid postgresDriver "${driver}". valid values: pg, bun`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
54
80
|
function parseConnectionString(str, args) {
|
|
55
81
|
if (str.startsWith("sqlite:///")) {
|
|
56
82
|
let filePath = str.substr(10);
|
|
@@ -79,10 +105,15 @@ function parseConnectionString(str, args) {
|
|
|
79
105
|
// database/config.yml
|
|
80
106
|
function getClientConfig(args) {
|
|
81
107
|
const extensions = (0, extensions_1.resolveExtensions)(args?.extensions);
|
|
108
|
+
const runtime = normalizeRuntimeMode(args?.runtime ?? process.env.ENT_RUNTIME);
|
|
109
|
+
const postgresDriver = normalizePostgresDriver(args?.postgresDriver ??
|
|
110
|
+
process.env.ENT_POSTGRES_DRIVER);
|
|
82
111
|
// if there's a db connection string, use that first
|
|
83
112
|
const str = process.env.DB_CONNECTION_STRING;
|
|
84
113
|
if (str) {
|
|
85
114
|
const info = parseConnectionString(str, args);
|
|
115
|
+
info.runtime = runtime;
|
|
116
|
+
info.postgresDriver = postgresDriver;
|
|
86
117
|
info.devSchema = args?.devSchema;
|
|
87
118
|
info.extensions = extensions;
|
|
88
119
|
return info;
|
|
@@ -91,6 +122,8 @@ function getClientConfig(args) {
|
|
|
91
122
|
if (args) {
|
|
92
123
|
if (args.connectionString) {
|
|
93
124
|
const info = parseConnectionString(args.connectionString, args);
|
|
125
|
+
info.runtime = runtime;
|
|
126
|
+
info.postgresDriver = postgresDriver;
|
|
94
127
|
info.devSchema = args?.devSchema;
|
|
95
128
|
info.extensions = extensions;
|
|
96
129
|
return info;
|
|
@@ -98,10 +131,18 @@ function getClientConfig(args) {
|
|
|
98
131
|
if (args.db) {
|
|
99
132
|
let db;
|
|
100
133
|
if (isDbDict(args.db)) {
|
|
101
|
-
|
|
134
|
+
const nodeEnv = process.env.NODE_ENV;
|
|
135
|
+
if (!nodeEnv) {
|
|
102
136
|
throw new Error(`process.env.NODE_ENV is undefined`);
|
|
103
137
|
}
|
|
104
|
-
|
|
138
|
+
if (!isEnv(nodeEnv)) {
|
|
139
|
+
throw new Error(`unsupported process.env.NODE_ENV value: ${nodeEnv}`);
|
|
140
|
+
}
|
|
141
|
+
const envDB = args.db[nodeEnv];
|
|
142
|
+
if (!envDB) {
|
|
143
|
+
throw new Error(`database config missing for environment ${nodeEnv}`);
|
|
144
|
+
}
|
|
145
|
+
db = envDB;
|
|
105
146
|
}
|
|
106
147
|
else {
|
|
107
148
|
db = args.db;
|
|
@@ -109,6 +150,8 @@ function getClientConfig(args) {
|
|
|
109
150
|
return {
|
|
110
151
|
dialect: Dialect.Postgres,
|
|
111
152
|
config: db,
|
|
153
|
+
runtime,
|
|
154
|
+
postgresDriver,
|
|
112
155
|
devSchema: args?.devSchema,
|
|
113
156
|
extensions,
|
|
114
157
|
};
|
|
@@ -139,6 +182,8 @@ function getClientConfig(args) {
|
|
|
139
182
|
// max, min, etc
|
|
140
183
|
...cfg,
|
|
141
184
|
},
|
|
185
|
+
runtime,
|
|
186
|
+
postgresDriver,
|
|
142
187
|
devSchema: args?.devSchema,
|
|
143
188
|
extensions,
|
|
144
189
|
};
|
|
@@ -146,10 +191,115 @@ function getClientConfig(args) {
|
|
|
146
191
|
throw new Error(`invalid yaml configuration in file`);
|
|
147
192
|
}
|
|
148
193
|
catch (e) {
|
|
149
|
-
|
|
194
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
195
|
+
console.error("error reading file" + message);
|
|
150
196
|
return null;
|
|
151
197
|
}
|
|
152
198
|
}
|
|
199
|
+
function getBunSQLConstructor() {
|
|
200
|
+
const BunRuntime = globalThis.Bun;
|
|
201
|
+
const SQL = BunRuntime?.SQL;
|
|
202
|
+
if (!SQL) {
|
|
203
|
+
throw new Error(`postgresDriver "bun" requires running under Bun`);
|
|
204
|
+
}
|
|
205
|
+
return SQL;
|
|
206
|
+
}
|
|
207
|
+
function createBunSQLConfig(config, searchPath) {
|
|
208
|
+
const cfg = config;
|
|
209
|
+
const bunConfig = {};
|
|
210
|
+
if (config.connectionString) {
|
|
211
|
+
bunConfig.url = config.connectionString;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
if (cfg.host) {
|
|
215
|
+
bunConfig.hostname = cfg.host;
|
|
216
|
+
}
|
|
217
|
+
if (cfg.port) {
|
|
218
|
+
bunConfig.port = cfg.port;
|
|
219
|
+
}
|
|
220
|
+
if (cfg.database) {
|
|
221
|
+
bunConfig.database = cfg.database;
|
|
222
|
+
}
|
|
223
|
+
if (cfg.user) {
|
|
224
|
+
bunConfig.username = cfg.user;
|
|
225
|
+
}
|
|
226
|
+
if (cfg.password) {
|
|
227
|
+
bunConfig.password = cfg.password;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (typeof config.max === "number") {
|
|
231
|
+
bunConfig.max = config.max;
|
|
232
|
+
}
|
|
233
|
+
if (cfg.sslmode) {
|
|
234
|
+
bunConfig.tls = cfg.sslmode !== "disable";
|
|
235
|
+
}
|
|
236
|
+
else if (config.ssl !== undefined) {
|
|
237
|
+
bunConfig.tls = config.ssl;
|
|
238
|
+
}
|
|
239
|
+
if (searchPath) {
|
|
240
|
+
bunConfig.onconnect = async (client) => {
|
|
241
|
+
await client.unsafe("SELECT set_config('search_path', $1, false)", [
|
|
242
|
+
searchPath,
|
|
243
|
+
]);
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return bunConfig;
|
|
247
|
+
}
|
|
248
|
+
function normalizeBunResult(result) {
|
|
249
|
+
const rows = Array.isArray(result) ? [...result] : [];
|
|
250
|
+
const rowCount = typeof result?.count === "number"
|
|
251
|
+
? result.count
|
|
252
|
+
: typeof result?.affectedRows === "number"
|
|
253
|
+
? result.affectedRows
|
|
254
|
+
: rows.length;
|
|
255
|
+
return {
|
|
256
|
+
rows,
|
|
257
|
+
rowCount,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function isPlainObject(value) {
|
|
261
|
+
if (value === null || typeof value !== "object") {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
const proto = Object.getPrototypeOf(value);
|
|
265
|
+
return proto === Object.prototype || proto === null;
|
|
266
|
+
}
|
|
267
|
+
function serializePostgresArray(values) {
|
|
268
|
+
return `{${values.map((entry) => serializePostgresArrayElement(entry)).join(",")}}`;
|
|
269
|
+
}
|
|
270
|
+
function serializePostgresArrayElement(value) {
|
|
271
|
+
if (value === null || value === undefined) {
|
|
272
|
+
return "NULL";
|
|
273
|
+
}
|
|
274
|
+
if (Array.isArray(value)) {
|
|
275
|
+
return serializePostgresArray(value);
|
|
276
|
+
}
|
|
277
|
+
const str = value instanceof Date
|
|
278
|
+
? value.toISOString()
|
|
279
|
+
: isPlainObject(value)
|
|
280
|
+
? JSON.stringify(value)
|
|
281
|
+
: String(value);
|
|
282
|
+
return `"${str.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
283
|
+
}
|
|
284
|
+
function serializeBunValue(value) {
|
|
285
|
+
if (Array.isArray(value)) {
|
|
286
|
+
return serializePostgresArray(value);
|
|
287
|
+
}
|
|
288
|
+
if (isPlainObject(value)) {
|
|
289
|
+
return JSON.stringify(value);
|
|
290
|
+
}
|
|
291
|
+
return value;
|
|
292
|
+
}
|
|
293
|
+
function serializeBunValues(values) {
|
|
294
|
+
return values?.map((value) => serializeBunValue(value));
|
|
295
|
+
}
|
|
296
|
+
function createBunQueryable(sql) {
|
|
297
|
+
return {
|
|
298
|
+
async query(query, values) {
|
|
299
|
+
return normalizeBunResult(await sql.unsafe(query, serializeBunValues(values)));
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
}
|
|
153
303
|
class DB {
|
|
154
304
|
constructor(db) {
|
|
155
305
|
this.db = db;
|
|
@@ -163,7 +313,10 @@ class DB {
|
|
|
163
313
|
const extensions = db.extensions || [];
|
|
164
314
|
if (db.dialect === Dialect.Postgres) {
|
|
165
315
|
const searchPath = (0, extensions_1.buildExtensionSearchPath)(resolvedDevSchema, extensions);
|
|
166
|
-
|
|
316
|
+
const postgresDriver = normalizePostgresDriver(db.postgresDriver);
|
|
317
|
+
db.runtime = normalizeRuntimeMode(db.runtime);
|
|
318
|
+
db.postgresDriver = postgresDriver;
|
|
319
|
+
if (postgresDriver === "pg" && searchPath) {
|
|
167
320
|
const option = `-c search_path=${searchPath}`;
|
|
168
321
|
db.config = {
|
|
169
322
|
...db.config,
|
|
@@ -172,23 +325,42 @@ class DB {
|
|
|
172
325
|
: option,
|
|
173
326
|
};
|
|
174
327
|
}
|
|
175
|
-
this.pool = new pg_1.Pool(db.config);
|
|
176
328
|
const schemaName = resolvedDevSchema.schemaName;
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
329
|
+
if (postgresDriver === "bun") {
|
|
330
|
+
const SQL = getBunSQLConstructor();
|
|
331
|
+
const sql = new SQL(createBunSQLConfig(db.config, searchPath));
|
|
332
|
+
const queryable = createBunQueryable(sql);
|
|
333
|
+
const readyTasks = [];
|
|
334
|
+
if (resolvedDevSchema.enabled && schemaName) {
|
|
335
|
+
readyTasks.push(validateDevSchema(queryable, schemaName).then(() => touchDevSchemaRegistry(queryable, schemaName, resolvedDevSchema.branchName).catch(() => { })));
|
|
336
|
+
}
|
|
337
|
+
readyTasks.push((0, extensions_1.initializeExtensions)(queryable, extensions, postgresDriver));
|
|
338
|
+
const ready = readyTasks.length > 0
|
|
339
|
+
? Promise.all(readyTasks).then(() => undefined)
|
|
340
|
+
: undefined;
|
|
341
|
+
if (ready) {
|
|
342
|
+
ready.catch(() => { });
|
|
343
|
+
}
|
|
344
|
+
this.q = new BunPostgres(sql, ready);
|
|
180
345
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
346
|
+
else {
|
|
347
|
+
const pool = new pg_1.Pool(db.config);
|
|
348
|
+
const readyTasks = [];
|
|
349
|
+
if (resolvedDevSchema.enabled && schemaName) {
|
|
350
|
+
readyTasks.push(validateDevSchema(pool, schemaName).then(() => touchDevSchemaRegistry(pool, schemaName, resolvedDevSchema.branchName).catch(() => { })));
|
|
351
|
+
}
|
|
352
|
+
readyTasks.push((0, extensions_1.initializeExtensions)(pool, extensions, postgresDriver));
|
|
353
|
+
const ready = readyTasks.length > 0
|
|
354
|
+
? Promise.all(readyTasks).then(() => undefined)
|
|
355
|
+
: undefined;
|
|
356
|
+
if (ready) {
|
|
357
|
+
ready.catch(() => { });
|
|
358
|
+
}
|
|
359
|
+
this.q = new Postgres(pool, ready);
|
|
360
|
+
pool.on("error", (err) => {
|
|
361
|
+
(0, logger_1.log)("error", err);
|
|
362
|
+
});
|
|
187
363
|
}
|
|
188
|
-
this.q = new Postgres(this.pool, ready);
|
|
189
|
-
this.pool.on("error", (err, client) => {
|
|
190
|
-
(0, logger_1.log)("error", err);
|
|
191
|
-
});
|
|
192
364
|
}
|
|
193
365
|
else {
|
|
194
366
|
let sqlite = require("better-sqlite3");
|
|
@@ -447,6 +619,71 @@ class PostgresClient {
|
|
|
447
619
|
}
|
|
448
620
|
}
|
|
449
621
|
exports.PostgresClient = PostgresClient;
|
|
622
|
+
class BunPostgres {
|
|
623
|
+
constructor(sql, ready) {
|
|
624
|
+
this.sql = sql;
|
|
625
|
+
this.ready = ready;
|
|
626
|
+
}
|
|
627
|
+
async ensureReady() {
|
|
628
|
+
if (this.ready) {
|
|
629
|
+
await this.ready;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
self() {
|
|
633
|
+
return this;
|
|
634
|
+
}
|
|
635
|
+
async newClient() {
|
|
636
|
+
await this.ensureReady();
|
|
637
|
+
const client = await this.sql.reserve();
|
|
638
|
+
return new BunPostgresClient(client, this.ready);
|
|
639
|
+
}
|
|
640
|
+
async query(query, values) {
|
|
641
|
+
await this.ensureReady();
|
|
642
|
+
return normalizeBunResult(await this.sql.unsafe(query, serializeBunValues(values)));
|
|
643
|
+
}
|
|
644
|
+
async queryAll(query, values) {
|
|
645
|
+
await this.ensureReady();
|
|
646
|
+
return normalizeBunResult(await this.sql.unsafe(query, serializeBunValues(values)));
|
|
647
|
+
}
|
|
648
|
+
async exec(query, values) {
|
|
649
|
+
await this.ensureReady();
|
|
650
|
+
return normalizeBunResult(await this.sql.unsafe(query, serializeBunValues(values)));
|
|
651
|
+
}
|
|
652
|
+
async close() {
|
|
653
|
+
if (!this.closePromise) {
|
|
654
|
+
this.closePromise = this.sql.close();
|
|
655
|
+
}
|
|
656
|
+
return this.closePromise;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
exports.BunPostgres = BunPostgres;
|
|
660
|
+
class BunPostgresClient {
|
|
661
|
+
constructor(client, ready) {
|
|
662
|
+
this.client = client;
|
|
663
|
+
this.ready = ready;
|
|
664
|
+
}
|
|
665
|
+
async ensureReady() {
|
|
666
|
+
if (this.ready) {
|
|
667
|
+
await this.ready;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
async query(query, values) {
|
|
671
|
+
await this.ensureReady();
|
|
672
|
+
return normalizeBunResult(await this.client.unsafe(query, serializeBunValues(values)));
|
|
673
|
+
}
|
|
674
|
+
async queryAll(query, values) {
|
|
675
|
+
await this.ensureReady();
|
|
676
|
+
return normalizeBunResult(await this.client.unsafe(query, serializeBunValues(values)));
|
|
677
|
+
}
|
|
678
|
+
async exec(query, values) {
|
|
679
|
+
await this.ensureReady();
|
|
680
|
+
return normalizeBunResult(await this.client.unsafe(query, serializeBunValues(values)));
|
|
681
|
+
}
|
|
682
|
+
async release(err) {
|
|
683
|
+
await this.client.release();
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
exports.BunPostgresClient = BunPostgresClient;
|
|
450
687
|
async function validateDevSchema(pool, schemaName) {
|
|
451
688
|
const res = await pool.query("SELECT EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = $1) AS ok", [schemaName]);
|
|
452
689
|
if (!res.rows?.[0]?.ok) {
|
|
@@ -465,8 +702,7 @@ async function touchDevSchemaRegistry(pool, schemaName, branchName) {
|
|
|
465
702
|
`, [schemaName, branch]);
|
|
466
703
|
}
|
|
467
704
|
catch (err) {
|
|
468
|
-
if (err &&
|
|
469
|
-
typeof err.message === "string" &&
|
|
705
|
+
if (err instanceof Error &&
|
|
470
706
|
err.message.includes("ent_dev_schema_registry")) {
|
|
471
707
|
return;
|
|
472
708
|
}
|