@snowtop/ent 0.2.6 → 0.2.8
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/executor.js +4 -4
- package/action/operations.js +3 -0
- package/action/orchestrator.js +10 -12
- package/action/topological_sort.d.ts +9 -0
- package/action/topological_sort.js +46 -0
- package/core/async_utils.d.ts +1 -0
- package/core/async_utils.js +29 -0
- package/core/base.d.ts +12 -5
- package/core/clause.d.ts +3 -5
- package/core/clause.js +32 -0
- package/core/config.d.ts +28 -2
- package/core/config.js +14 -1
- package/core/context.d.ts +3 -1
- package/core/context.js +90 -26
- package/core/db.d.ts +12 -2
- package/core/db.js +102 -7
- package/core/dev_schema.d.ts +9 -0
- package/core/dev_schema.js +306 -0
- package/core/ent.d.ts +5 -7
- package/core/ent.js +33 -48
- package/core/extensions.d.ts +25 -0
- package/core/extensions.js +220 -0
- package/core/loaders/assoc_count_loader.js +3 -6
- package/core/loaders/assoc_edge_loader.d.ts +3 -0
- package/core/loaders/assoc_edge_loader.js +48 -19
- package/core/loaders/index.d.ts +2 -1
- package/core/loaders/index.js +5 -1
- package/core/loaders/loader.d.ts +31 -0
- package/core/loaders/loader.js +141 -2
- package/core/loaders/object_loader.d.ts +2 -2
- package/core/loaders/object_loader.js +39 -57
- package/core/loaders/query_loader.d.ts +2 -5
- package/core/loaders/query_loader.js +45 -24
- package/core/loaders/raw_count_loader.d.ts +2 -2
- package/core/loaders/raw_count_loader.js +12 -14
- package/core/memoize.d.ts +1 -0
- package/core/memoize.js +15 -0
- package/core/metrics.d.ts +22 -0
- package/core/metrics.js +31 -0
- package/core/query/custom_clause_query.js +5 -1
- package/core/query/query.d.ts +1 -1
- package/core/query/query.js +10 -7
- package/core/query_expression.d.ts +6 -0
- package/core/query_expression.js +2 -0
- package/core/query_impl.d.ts +19 -3
- package/core/query_impl.js +148 -35
- package/index.d.ts +7 -2
- package/index.js +12 -2
- package/package.json +1 -7
- package/parse_schema/parse.d.ts +2 -12
- package/parse_schema/parse.js +22 -41
- package/schema/index.d.ts +1 -1
- package/schema/schema.d.ts +20 -1
- package/scripts/custom_graphql.js +12 -5
- package/scripts/fix_action_exports.js +1 -1
- package/scripts/migrate_v0.1.js +2 -5
- package/scripts/move_types.js +1 -1
- package/scripts/read_schema.js +2 -5
- package/testutils/builder.js +1 -2
- package/testutils/parse_sql.js +1 -1
- package/tsc/compilerOptions.d.ts +2 -2
- package/tsc/compilerOptions.js +12 -18
- package/tsc/move_generated.js +2 -2
- package/tsc/transform.d.ts +1 -1
- package/tsc/transform.js +16 -2
- package/tsc/transform_action.d.ts +1 -1
- package/tsc/transform_action.js +1 -1
- package/tsc/transform_ent.d.ts +1 -1
- package/tsc/transform_ent.js +1 -1
- package/tsc/transform_schema.d.ts +1 -1
- package/tsc/transform_schema.js +2 -2
- /package/core/{loaders/cache_utils.d.ts → cache_utils.d.ts} +0 -0
- /package/core/{loaders/cache_utils.js → cache_utils.js} +0 -0
package/core/db.js
CHANGED
|
@@ -39,6 +39,8 @@ const js_yaml_1 = require("js-yaml");
|
|
|
39
39
|
const luxon_1 = require("luxon");
|
|
40
40
|
const pg_1 = __importStar(require("pg"));
|
|
41
41
|
const logger_1 = require("./logger");
|
|
42
|
+
const dev_schema_1 = require("./dev_schema");
|
|
43
|
+
const extensions_1 = require("./extensions");
|
|
42
44
|
function isDbDict(v) {
|
|
43
45
|
return (v["production"] !== undefined ||
|
|
44
46
|
v["development"] !== undefined ||
|
|
@@ -76,15 +78,22 @@ function parseConnectionString(str, args) {
|
|
|
76
78
|
// database file in yml file
|
|
77
79
|
// database/config.yml
|
|
78
80
|
function getClientConfig(args) {
|
|
81
|
+
const extensions = (0, extensions_1.resolveExtensions)(args?.extensions);
|
|
79
82
|
// if there's a db connection string, use that first
|
|
80
83
|
const str = process.env.DB_CONNECTION_STRING;
|
|
81
84
|
if (str) {
|
|
82
|
-
|
|
85
|
+
const info = parseConnectionString(str, args);
|
|
86
|
+
info.devSchema = args?.devSchema;
|
|
87
|
+
info.extensions = extensions;
|
|
88
|
+
return info;
|
|
83
89
|
}
|
|
84
90
|
let file = "config/database.yml";
|
|
85
91
|
if (args) {
|
|
86
92
|
if (args.connectionString) {
|
|
87
|
-
|
|
93
|
+
const info = parseConnectionString(args.connectionString, args);
|
|
94
|
+
info.devSchema = args?.devSchema;
|
|
95
|
+
info.extensions = extensions;
|
|
96
|
+
return info;
|
|
88
97
|
}
|
|
89
98
|
if (args.db) {
|
|
90
99
|
let db;
|
|
@@ -100,6 +109,8 @@ function getClientConfig(args) {
|
|
|
100
109
|
return {
|
|
101
110
|
dialect: Dialect.Postgres,
|
|
102
111
|
config: db,
|
|
112
|
+
devSchema: args?.devSchema,
|
|
113
|
+
extensions,
|
|
103
114
|
};
|
|
104
115
|
}
|
|
105
116
|
if (args.dbFile) {
|
|
@@ -128,6 +139,8 @@ function getClientConfig(args) {
|
|
|
128
139
|
// max, min, etc
|
|
129
140
|
...cfg,
|
|
130
141
|
},
|
|
142
|
+
devSchema: args?.devSchema,
|
|
143
|
+
extensions,
|
|
131
144
|
};
|
|
132
145
|
}
|
|
133
146
|
throw new Error(`invalid yaml configuration in file`);
|
|
@@ -140,9 +153,39 @@ function getClientConfig(args) {
|
|
|
140
153
|
class DB {
|
|
141
154
|
constructor(db) {
|
|
142
155
|
this.db = db;
|
|
156
|
+
const devSchemaEnabled = (0, dev_schema_1.isDevSchemaEnabled)(db.devSchema);
|
|
157
|
+
if (devSchemaEnabled && db.dialect === Dialect.SQLite) {
|
|
158
|
+
throw new Error("dev branch schemas are only supported for postgres");
|
|
159
|
+
}
|
|
160
|
+
const resolvedDevSchema = devSchemaEnabled
|
|
161
|
+
? (0, dev_schema_1.resolveDevSchema)(db.devSchema)
|
|
162
|
+
: { enabled: false };
|
|
163
|
+
const extensions = db.extensions || [];
|
|
143
164
|
if (db.dialect === Dialect.Postgres) {
|
|
165
|
+
const searchPath = (0, extensions_1.buildExtensionSearchPath)(resolvedDevSchema, extensions);
|
|
166
|
+
if (searchPath) {
|
|
167
|
+
const option = `-c search_path=${searchPath}`;
|
|
168
|
+
db.config = {
|
|
169
|
+
...db.config,
|
|
170
|
+
options: db.config.options
|
|
171
|
+
? `${db.config.options} ${option}`
|
|
172
|
+
: option,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
144
175
|
this.pool = new pg_1.Pool(db.config);
|
|
145
|
-
|
|
176
|
+
const schemaName = resolvedDevSchema.schemaName;
|
|
177
|
+
const readyTasks = [];
|
|
178
|
+
if (resolvedDevSchema.enabled && schemaName) {
|
|
179
|
+
readyTasks.push(validateDevSchema(this.pool, schemaName).then(() => touchDevSchemaRegistry(this.pool, schemaName, resolvedDevSchema.branchName).catch(() => { })));
|
|
180
|
+
}
|
|
181
|
+
readyTasks.push((0, extensions_1.initializeExtensions)(this.pool, extensions));
|
|
182
|
+
const ready = readyTasks.length > 0
|
|
183
|
+
? Promise.all(readyTasks).then(() => undefined)
|
|
184
|
+
: undefined;
|
|
185
|
+
if (ready) {
|
|
186
|
+
ready.catch(() => { });
|
|
187
|
+
}
|
|
188
|
+
this.q = new Postgres(this.pool, ready);
|
|
146
189
|
this.pool.on("error", (err, client) => {
|
|
147
190
|
(0, logger_1.log)("error", err);
|
|
148
191
|
});
|
|
@@ -203,6 +246,10 @@ class DB {
|
|
|
203
246
|
static initDB(args) {
|
|
204
247
|
const config = getClientConfig(args);
|
|
205
248
|
if (config) {
|
|
249
|
+
const existing = DB.instance;
|
|
250
|
+
if (existing) {
|
|
251
|
+
void existing.endPool().catch(() => { });
|
|
252
|
+
}
|
|
206
253
|
DB.instance = new DB(config);
|
|
207
254
|
DB.dialect = DB.instance.db.dialect;
|
|
208
255
|
}
|
|
@@ -320,29 +367,39 @@ class Sqlite {
|
|
|
320
367
|
}
|
|
321
368
|
exports.Sqlite = Sqlite;
|
|
322
369
|
class Postgres {
|
|
323
|
-
constructor(pool) {
|
|
370
|
+
constructor(pool, ready) {
|
|
324
371
|
this.pool = pool;
|
|
372
|
+
this.ready = ready;
|
|
373
|
+
}
|
|
374
|
+
async ensureReady() {
|
|
375
|
+
if (this.ready) {
|
|
376
|
+
await this.ready;
|
|
377
|
+
}
|
|
325
378
|
}
|
|
326
379
|
self() {
|
|
327
380
|
return this;
|
|
328
381
|
}
|
|
329
382
|
// returns new Pool client
|
|
330
383
|
async newClient() {
|
|
384
|
+
await this.ensureReady();
|
|
331
385
|
const client = await this.pool.connect();
|
|
332
386
|
if (!client) {
|
|
333
387
|
throw new Error(`couldn't get new client`);
|
|
334
388
|
}
|
|
335
|
-
return new PostgresClient(client);
|
|
389
|
+
return new PostgresClient(client, this.ready);
|
|
336
390
|
}
|
|
337
391
|
async query(query, values) {
|
|
392
|
+
await this.ensureReady();
|
|
338
393
|
const r = await this.pool.query(query, values);
|
|
339
394
|
return r;
|
|
340
395
|
}
|
|
341
396
|
async queryAll(query, values) {
|
|
397
|
+
await this.ensureReady();
|
|
342
398
|
const r = await this.pool.query(query, values);
|
|
343
399
|
return r;
|
|
344
400
|
}
|
|
345
401
|
async exec(query, values) {
|
|
402
|
+
await this.ensureReady();
|
|
346
403
|
const r = await this.pool.query(query, values);
|
|
347
404
|
return {
|
|
348
405
|
rowCount: r?.rowCount || 0,
|
|
@@ -350,23 +407,35 @@ class Postgres {
|
|
|
350
407
|
};
|
|
351
408
|
}
|
|
352
409
|
async close() {
|
|
353
|
-
|
|
410
|
+
if (!this.closePromise) {
|
|
411
|
+
this.closePromise = this.pool.end();
|
|
412
|
+
}
|
|
413
|
+
return this.closePromise;
|
|
354
414
|
}
|
|
355
415
|
}
|
|
356
416
|
exports.Postgres = Postgres;
|
|
357
417
|
class PostgresClient {
|
|
358
|
-
constructor(client) {
|
|
418
|
+
constructor(client, ready) {
|
|
359
419
|
this.client = client;
|
|
420
|
+
this.ready = ready;
|
|
421
|
+
}
|
|
422
|
+
async ensureReady() {
|
|
423
|
+
if (this.ready) {
|
|
424
|
+
await this.ready;
|
|
425
|
+
}
|
|
360
426
|
}
|
|
361
427
|
async query(query, values) {
|
|
428
|
+
await this.ensureReady();
|
|
362
429
|
const r = await this.client.query(query, values);
|
|
363
430
|
return r;
|
|
364
431
|
}
|
|
365
432
|
async queryAll(query, values) {
|
|
433
|
+
await this.ensureReady();
|
|
366
434
|
const r = await this.client.query(query, values);
|
|
367
435
|
return r;
|
|
368
436
|
}
|
|
369
437
|
async exec(query, values) {
|
|
438
|
+
await this.ensureReady();
|
|
370
439
|
const r = await this.client.query(query, values);
|
|
371
440
|
return {
|
|
372
441
|
rowCount: r?.rowCount || 0,
|
|
@@ -378,3 +447,29 @@ class PostgresClient {
|
|
|
378
447
|
}
|
|
379
448
|
}
|
|
380
449
|
exports.PostgresClient = PostgresClient;
|
|
450
|
+
async function validateDevSchema(pool, schemaName) {
|
|
451
|
+
const res = await pool.query("SELECT EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = $1) AS ok", [schemaName]);
|
|
452
|
+
if (!res.rows?.[0]?.ok) {
|
|
453
|
+
throw new Error(`dev branch schema \"${schemaName}\" does not exist. Run auto_schema or migrations to create it.`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
async function touchDevSchemaRegistry(pool, schemaName, branchName) {
|
|
457
|
+
const branch = branchName ?? null;
|
|
458
|
+
try {
|
|
459
|
+
// Avoid DDL at runtime; registry table should be created by auto_schema/prune.
|
|
460
|
+
await pool.query(`
|
|
461
|
+
INSERT INTO public.ent_dev_schema_registry (schema_name, branch_name, created_at, last_used_at)
|
|
462
|
+
VALUES ($1, $2, now(), now())
|
|
463
|
+
ON CONFLICT (schema_name)
|
|
464
|
+
DO UPDATE SET last_used_at = now(), branch_name = EXCLUDED.branch_name
|
|
465
|
+
`, [schemaName, branch]);
|
|
466
|
+
}
|
|
467
|
+
catch (err) {
|
|
468
|
+
if (err &&
|
|
469
|
+
typeof err.message === "string" &&
|
|
470
|
+
err.message.includes("ent_dev_schema_registry")) {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
(0, logger_1.log)("debug", err);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RuntimeDevSchemaConfig } from "./config";
|
|
2
|
+
export interface ResolvedDevSchema {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
schemaName?: string;
|
|
5
|
+
branchName?: string;
|
|
6
|
+
includePublic?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function resolveDevSchema(cfg?: RuntimeDevSchemaConfig): ResolvedDevSchema;
|
|
9
|
+
export declare function isDevSchemaEnabled(cfg?: RuntimeDevSchemaConfig): boolean;
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.resolveDevSchema = resolveDevSchema;
|
|
37
|
+
exports.isDevSchemaEnabled = isDevSchemaEnabled;
|
|
38
|
+
const crypto_1 = require("crypto");
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const STATE_DIR = ".ent";
|
|
42
|
+
const STATE_FILE = "dev_schema.json";
|
|
43
|
+
const DEFAULT_SCHEMA_DIR = path.join("src", "schema");
|
|
44
|
+
const DEFAULT_SCHEMA_PREFIX = "ent_dev";
|
|
45
|
+
const MAX_SCHEMA_LEN = 63;
|
|
46
|
+
function resolveDevSchema(cfg) {
|
|
47
|
+
if (!isDevSchemaEnabled(cfg)) {
|
|
48
|
+
return { enabled: false };
|
|
49
|
+
}
|
|
50
|
+
if (cfg?.schemaName) {
|
|
51
|
+
const schemaName = sanitizeIdentifier(cfg.schemaName);
|
|
52
|
+
return {
|
|
53
|
+
enabled: true,
|
|
54
|
+
schemaName,
|
|
55
|
+
includePublic: cfg.includePublic === true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (cfg) {
|
|
59
|
+
const branchName = requireCurrentBranch("dev branch schemas are enabled but the current git branch could not be determined. Set devSchema.schemaName explicitly.");
|
|
60
|
+
return {
|
|
61
|
+
enabled: true,
|
|
62
|
+
schemaName: buildSchemaName(branchName),
|
|
63
|
+
branchName,
|
|
64
|
+
includePublic: cfg.includePublic === true,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const state = loadDevSchemaState(resolveStatePath());
|
|
68
|
+
if (state?.schemaName) {
|
|
69
|
+
const branchName = state.branchName;
|
|
70
|
+
if (branchName) {
|
|
71
|
+
// State-file mode is tied to the branch that produced the generated
|
|
72
|
+
// schema metadata. Fail closed after branch switches until codegen
|
|
73
|
+
// refreshes the state file.
|
|
74
|
+
const currentBranch = requireCurrentBranch(`dev branch schema state was generated for branch "${branchName}" but the current git branch could not be determined. Run ent codegen to regenerate or set devSchema.schemaName explicitly.`);
|
|
75
|
+
if (currentBranch !== branchName) {
|
|
76
|
+
throw new Error(`dev branch schema state was generated for branch "${branchName}" but current branch is "${currentBranch}". Run ent codegen to regenerate or set devSchema.schemaName explicitly.`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
enabled: true,
|
|
81
|
+
schemaName: sanitizeIdentifier(state.schemaName),
|
|
82
|
+
branchName,
|
|
83
|
+
includePublic: state.includePublic === true,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const branchName = requireCurrentBranch("dev branch schemas are enabled but the current git branch could not be determined. Set devSchema.schemaName explicitly or run ent codegen to regenerate src/schema/.ent/dev_schema.json.");
|
|
87
|
+
return {
|
|
88
|
+
enabled: true,
|
|
89
|
+
schemaName: buildSchemaName(branchName),
|
|
90
|
+
branchName,
|
|
91
|
+
includePublic: false,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function isDevSchemaEnabled(cfg) {
|
|
95
|
+
const nodeEnv = (process.env.NODE_ENV || "").toLowerCase();
|
|
96
|
+
if (nodeEnv === "production") {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
const envEnabled = parseEnvBool("ENT_DEV_SCHEMA_ENABLED");
|
|
100
|
+
if (envEnabled !== undefined) {
|
|
101
|
+
return envEnabled;
|
|
102
|
+
}
|
|
103
|
+
if (cfg) {
|
|
104
|
+
if (cfg.enabled !== true) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const branch = resolveGitBranch();
|
|
108
|
+
if (isBranchIgnored(cfg.ignoreBranches, branch)) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
const state = loadDevSchemaState(resolveStatePath());
|
|
114
|
+
if (!state?.schemaName) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
const branch = resolveGitBranch();
|
|
118
|
+
if (isBranchIgnored(state.ignoreBranches, branch)) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
function loadDevSchemaState(statePath) {
|
|
124
|
+
if (!statePath || !fs.existsSync(statePath)) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
const raw = fs.readFileSync(statePath, "utf8");
|
|
128
|
+
let data;
|
|
129
|
+
try {
|
|
130
|
+
data = JSON.parse(raw);
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
throw new Error(`invalid dev schema state file at ${statePath}`);
|
|
134
|
+
}
|
|
135
|
+
if (!data || !data.schemaName) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
return data;
|
|
139
|
+
}
|
|
140
|
+
function requireCurrentBranch(message) {
|
|
141
|
+
const branch = resolveGitBranch();
|
|
142
|
+
if (!branch) {
|
|
143
|
+
throw new Error(message);
|
|
144
|
+
}
|
|
145
|
+
return branch;
|
|
146
|
+
}
|
|
147
|
+
function slugify(input) {
|
|
148
|
+
if (!input) {
|
|
149
|
+
return "";
|
|
150
|
+
}
|
|
151
|
+
const lower = input.toLowerCase();
|
|
152
|
+
let out = "";
|
|
153
|
+
let lastUnderscore = false;
|
|
154
|
+
for (const ch of lower) {
|
|
155
|
+
const isAlpha = ch >= "a" && ch <= "z";
|
|
156
|
+
const isDigit = ch >= "0" && ch <= "9";
|
|
157
|
+
if (isAlpha || isDigit) {
|
|
158
|
+
out += ch;
|
|
159
|
+
lastUnderscore = false;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (!lastUnderscore) {
|
|
163
|
+
out += "_";
|
|
164
|
+
lastUnderscore = true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return trimBoundaryUnderscores(out);
|
|
168
|
+
}
|
|
169
|
+
function trimBoundaryUnderscores(input) {
|
|
170
|
+
let start = 0;
|
|
171
|
+
let end = input.length;
|
|
172
|
+
while (start < end && input[start] === "_") {
|
|
173
|
+
start++;
|
|
174
|
+
}
|
|
175
|
+
while (end > start && input[end - 1] === "_") {
|
|
176
|
+
end--;
|
|
177
|
+
}
|
|
178
|
+
return input.slice(start, end);
|
|
179
|
+
}
|
|
180
|
+
function sanitizeIdentifier(input) {
|
|
181
|
+
const slug = slugify(input);
|
|
182
|
+
if (!slug) {
|
|
183
|
+
return "schema";
|
|
184
|
+
}
|
|
185
|
+
let normalized = slug;
|
|
186
|
+
if (normalized[0] >= "0" && normalized[0] <= "9") {
|
|
187
|
+
normalized = `schema_${normalized}`;
|
|
188
|
+
}
|
|
189
|
+
if (normalized.length > MAX_SCHEMA_LEN) {
|
|
190
|
+
return normalized.slice(0, MAX_SCHEMA_LEN);
|
|
191
|
+
}
|
|
192
|
+
return normalized;
|
|
193
|
+
}
|
|
194
|
+
function shortHash(input) {
|
|
195
|
+
return (0, crypto_1.createHash)("sha1").update(input).digest("hex").slice(0, 8);
|
|
196
|
+
}
|
|
197
|
+
function buildSchemaName(branch) {
|
|
198
|
+
const prefix = sanitizeIdentifier(DEFAULT_SCHEMA_PREFIX);
|
|
199
|
+
let branchSlug = slugify(branch);
|
|
200
|
+
if (!branchSlug) {
|
|
201
|
+
branchSlug = "branch";
|
|
202
|
+
}
|
|
203
|
+
const hash = shortHash(branch);
|
|
204
|
+
let name = [prefix, branchSlug, hash].join("_");
|
|
205
|
+
if (name.length <= MAX_SCHEMA_LEN) {
|
|
206
|
+
return name;
|
|
207
|
+
}
|
|
208
|
+
const over = name.length - MAX_SCHEMA_LEN;
|
|
209
|
+
if (over > 0 && branchSlug.length > 1) {
|
|
210
|
+
branchSlug = branchSlug.slice(0, branchSlug.length - Math.min(over, branchSlug.length - 1));
|
|
211
|
+
}
|
|
212
|
+
name = [prefix, branchSlug, hash].join("_");
|
|
213
|
+
if (name.length > MAX_SCHEMA_LEN) {
|
|
214
|
+
return name.slice(0, MAX_SCHEMA_LEN);
|
|
215
|
+
}
|
|
216
|
+
return name;
|
|
217
|
+
}
|
|
218
|
+
function resolveStatePath() {
|
|
219
|
+
const start = process.cwd();
|
|
220
|
+
const root = findGitRoot(start) || start;
|
|
221
|
+
const schemaDir = path.join(root, DEFAULT_SCHEMA_DIR);
|
|
222
|
+
return path.join(schemaDir, STATE_DIR, STATE_FILE);
|
|
223
|
+
}
|
|
224
|
+
function isBranchIgnored(ignoreBranches, branch) {
|
|
225
|
+
if (!branch || !ignoreBranches || ignoreBranches.length === 0) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
for (const name of ignoreBranches) {
|
|
229
|
+
if (!name || !name.trim()) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (name === branch) {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
function parseEnvBool(key) {
|
|
239
|
+
const raw = process.env[key];
|
|
240
|
+
if (!raw) {
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
const val = raw.trim().toLowerCase();
|
|
244
|
+
if (["1", "true", "t", "yes", "y"].includes(val)) {
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
if (["0", "false", "f", "no", "n"].includes(val)) {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
function resolveGitBranch() {
|
|
253
|
+
const start = process.cwd();
|
|
254
|
+
const root = findGitRoot(start);
|
|
255
|
+
if (!root) {
|
|
256
|
+
return "";
|
|
257
|
+
}
|
|
258
|
+
const gitDir = resolveGitDir(path.join(root, ".git"));
|
|
259
|
+
if (!gitDir) {
|
|
260
|
+
return "";
|
|
261
|
+
}
|
|
262
|
+
const headPath = path.join(gitDir, "HEAD");
|
|
263
|
+
if (!fs.existsSync(headPath)) {
|
|
264
|
+
return "";
|
|
265
|
+
}
|
|
266
|
+
const head = fs.readFileSync(headPath, "utf8").trim();
|
|
267
|
+
if (!head.startsWith("ref:")) {
|
|
268
|
+
return "";
|
|
269
|
+
}
|
|
270
|
+
return head
|
|
271
|
+
.replace("ref:", "")
|
|
272
|
+
.trim()
|
|
273
|
+
.replace(/^refs\/heads\//, "");
|
|
274
|
+
}
|
|
275
|
+
function resolveGitDir(gitPath) {
|
|
276
|
+
if (!fs.existsSync(gitPath)) {
|
|
277
|
+
return undefined;
|
|
278
|
+
}
|
|
279
|
+
const stat = fs.statSync(gitPath);
|
|
280
|
+
if (stat.isDirectory()) {
|
|
281
|
+
return gitPath;
|
|
282
|
+
}
|
|
283
|
+
const contents = fs.readFileSync(gitPath, "utf8").trim();
|
|
284
|
+
if (!contents.startsWith("gitdir:")) {
|
|
285
|
+
return undefined;
|
|
286
|
+
}
|
|
287
|
+
let dir = contents.replace("gitdir:", "").trim();
|
|
288
|
+
if (!path.isAbsolute(dir)) {
|
|
289
|
+
dir = path.join(path.dirname(gitPath), dir);
|
|
290
|
+
}
|
|
291
|
+
return dir;
|
|
292
|
+
}
|
|
293
|
+
function findGitRoot(start) {
|
|
294
|
+
let dir = start;
|
|
295
|
+
while (true) {
|
|
296
|
+
const gitPath = path.join(dir, ".git");
|
|
297
|
+
if (fs.existsSync(gitPath)) {
|
|
298
|
+
return dir;
|
|
299
|
+
}
|
|
300
|
+
const parent = path.dirname(dir);
|
|
301
|
+
if (parent === dir) {
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
dir = parent;
|
|
305
|
+
}
|
|
306
|
+
}
|
package/core/ent.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Context, CreateRowOptions, Data, DataOptions, EdgeQueryableDataOptions, EditRowOptions, Ent, ID, LoadCustomEntOptions, LoadEntOptions, LoadRowOptions, LoadRowsOptions, LoaderWithLoadMany, QueryDataOptions, SelectCustomDataOptions, Viewer } from "./base";
|
|
1
|
+
import { Context, CreateRowOptions, Data, DataOptions, EdgeQueryableDataOptions, EditRowOptions, Ent, ID, LoadCustomEntOptions, LoadEntOptions, LoadRowOptions, LoadRowsOptions, LoaderWithLoadMany, QueryDataOptions, SelectBaseDataOptions, SelectCustomDataOptions, Viewer } from "./base";
|
|
2
2
|
import { Queryer, SyncQueryer } from "./db";
|
|
3
|
-
import DataLoader from "dataloader";
|
|
4
3
|
import * as clause from "./clause";
|
|
4
|
+
import { InstrumentedDataLoader } from "./loaders/loader";
|
|
5
5
|
import { OrderBy } from "./query_impl";
|
|
6
6
|
declare class entCacheMap<TViewer extends Viewer, TEnt extends Ent<TViewer>> {
|
|
7
7
|
private viewer;
|
|
@@ -108,10 +108,7 @@ interface GroupQueryOptions<T extends Data, K = keyof T> {
|
|
|
108
108
|
tableName: string;
|
|
109
109
|
clause?: clause.Clause<T, K>;
|
|
110
110
|
groupColumn: K;
|
|
111
|
-
fields:
|
|
112
|
-
alias: string;
|
|
113
|
-
column: K;
|
|
114
|
-
})[];
|
|
111
|
+
fields: SelectBaseDataOptions["fields"];
|
|
115
112
|
values: any[];
|
|
116
113
|
orderby?: OrderBy;
|
|
117
114
|
limit: number;
|
|
@@ -151,6 +148,7 @@ export interface cursorOptions {
|
|
|
151
148
|
*/
|
|
152
149
|
rowKeys?: string[];
|
|
153
150
|
}
|
|
151
|
+
export declare function decodeCursorPayload(encoded: string): string;
|
|
154
152
|
export declare function getCursor(opts: cursorOptions): string;
|
|
155
153
|
export declare class AssocEdgeData {
|
|
156
154
|
edgeType: string;
|
|
@@ -160,7 +158,7 @@ export declare class AssocEdgeData {
|
|
|
160
158
|
edgeTable: string;
|
|
161
159
|
constructor(data: Data);
|
|
162
160
|
}
|
|
163
|
-
export declare const assocEdgeLoader:
|
|
161
|
+
export declare const assocEdgeLoader: InstrumentedDataLoader<ID, Data | null>;
|
|
164
162
|
export declare function loadEdgeData(edgeType: string): Promise<AssocEdgeData | null>;
|
|
165
163
|
export declare function loadEdgeDatas(...edgeTypes: string[]): Promise<Map<string, AssocEdgeData>>;
|
|
166
164
|
export interface AssocEdgeConstructor<T extends AssocEdge> {
|