@h3ravel/arquebus 0.3.6 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.cjs +4269 -2733
- package/bin/index.js +4364 -2828
- package/dist/browser/index.cjs +2 -0
- package/dist/browser/index.d.cts +94 -7
- package/dist/browser/index.d.ts +94 -7
- package/dist/browser/index.js +2 -1
- package/dist/index.cjs +1501 -15
- package/dist/index.d.cts +130 -10
- package/dist/index.d.ts +130 -10
- package/dist/index.js +1501 -16
- package/dist/inspector/index.cjs +4885 -0
- package/dist/inspector/index.d.cts +83 -0
- package/dist/inspector/index.d.ts +83 -0
- package/dist/inspector/index.js +4859 -0
- package/dist/migrations/index.cjs +4389 -2904
- package/dist/migrations/index.d.cts +128 -9
- package/dist/migrations/index.d.ts +129 -10
- package/dist/migrations/index.js +4275 -2790
- package/package.json +12 -3
- package/types/query-builder.ts +37 -1
- package/src/migrations/stubs/migration-js.stub +0 -21
- package/src/migrations/stubs/migration-ts.stub +0 -18
- package/src/migrations/stubs/migration.create-js.stub +0 -24
- package/src/migrations/stubs/migration.create-ts.stub +0 -21
- package/src/migrations/stubs/migration.update-js.stub +0 -25
- package/src/migrations/stubs/migration.update-ts.stub +0 -22
- package/src/stubs/arquebus.config-js.stub +0 -25
- package/src/stubs/arquebus.config-ts.stub +0 -24
- package/src/stubs/model-js.stub +0 -5
- package/src/stubs/model-ts.stub +0 -5
package/dist/index.js
CHANGED
|
@@ -208,6 +208,7 @@ const tap = (instance, callback) => {
|
|
|
208
208
|
return result instanceof Promise ? result.then(() => instance) : instance;
|
|
209
209
|
};
|
|
210
210
|
const { compose } = mixin_exports;
|
|
211
|
+
const flatten = (arr) => arr.flat();
|
|
211
212
|
const flattenDeep = (arr) => Array.isArray(arr) ? arr.reduce((a, b) => a.concat(flattenDeep(b)), []) : [arr];
|
|
212
213
|
const kebabCase = (str) => trim(dash(str.replace(/[^a-zA-Z0-9_-]/g, "-")), "_-");
|
|
213
214
|
const snakeCase = (str) => trim(snake(str.replace(/[^a-zA-Z0-9_-]/g, "-")), "_-");
|
|
@@ -3526,13 +3527,1430 @@ var MigrationRepository = class {
|
|
|
3526
3527
|
return this.getConnection().table(this.table);
|
|
3527
3528
|
}
|
|
3528
3529
|
getConnection() {
|
|
3529
|
-
return this.resolver.
|
|
3530
|
+
return this.resolver.fire(this.connection);
|
|
3530
3531
|
}
|
|
3531
3532
|
setSource(name) {
|
|
3532
3533
|
this.connection = name;
|
|
3533
3534
|
}
|
|
3534
3535
|
};
|
|
3535
3536
|
|
|
3537
|
+
//#endregion
|
|
3538
|
+
//#region src/inspector/utils/strip-quotes.ts
|
|
3539
|
+
/**
|
|
3540
|
+
* Strip leading/trailing quotes from a string and handle null values.
|
|
3541
|
+
*/
|
|
3542
|
+
function stripQuotes(value) {
|
|
3543
|
+
if (value === null || value === void 0) return null;
|
|
3544
|
+
const trimmed = value.trim();
|
|
3545
|
+
if (trimmed.startsWith("'") && trimmed.endsWith("'") || trimmed.startsWith("\"") && trimmed.endsWith("\"")) return trimmed.slice(1, -1);
|
|
3546
|
+
return value;
|
|
3547
|
+
}
|
|
3548
|
+
|
|
3549
|
+
//#endregion
|
|
3550
|
+
//#region src/inspector/dialects/cockroachdb.ts
|
|
3551
|
+
/**
|
|
3552
|
+
* Converts CockroachDB default value to JS
|
|
3553
|
+
* Eg `'example'::character varying` => `example`
|
|
3554
|
+
*/
|
|
3555
|
+
function parseDefaultValue$5(value) {
|
|
3556
|
+
if (value === null) return null;
|
|
3557
|
+
if (value.startsWith("nextval(")) return value;
|
|
3558
|
+
value = value.split("::")[0];
|
|
3559
|
+
return stripQuotes(value);
|
|
3560
|
+
}
|
|
3561
|
+
var CockroachDB = class {
|
|
3562
|
+
knex;
|
|
3563
|
+
schema;
|
|
3564
|
+
explodedSchema;
|
|
3565
|
+
constructor(knex) {
|
|
3566
|
+
this.knex = knex;
|
|
3567
|
+
const config = knex.client.config;
|
|
3568
|
+
if (!config.searchPath) {
|
|
3569
|
+
this.schema = "public";
|
|
3570
|
+
this.explodedSchema = [this.schema];
|
|
3571
|
+
} else if (typeof config.searchPath === "string") {
|
|
3572
|
+
this.schema = config.searchPath;
|
|
3573
|
+
this.explodedSchema = [config.searchPath];
|
|
3574
|
+
} else {
|
|
3575
|
+
this.schema = config.searchPath[0];
|
|
3576
|
+
this.explodedSchema = config.searchPath;
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
/**
|
|
3580
|
+
* Set the schema to be used in other methods
|
|
3581
|
+
*/
|
|
3582
|
+
withSchema(schema) {
|
|
3583
|
+
this.schema = schema;
|
|
3584
|
+
this.explodedSchema = [this.schema];
|
|
3585
|
+
return this;
|
|
3586
|
+
}
|
|
3587
|
+
/**
|
|
3588
|
+
* List all existing tables in the current schema/database
|
|
3589
|
+
*/
|
|
3590
|
+
async tables() {
|
|
3591
|
+
return (await this.knex.select("tablename").from("pg_catalog.pg_tables").whereIn("schemaname", this.explodedSchema)).map(({ tablename }) => tablename);
|
|
3592
|
+
}
|
|
3593
|
+
async tableInfo(table) {
|
|
3594
|
+
const query = this.knex.select("table_name", "table_schema", this.knex.select(this.knex.raw("obj_description(oid)")).from("pg_class").where({ relkind: "r" }).andWhere({ relname: "table_name" }).as("table_comment")).from("information_schema.tables").whereIn("table_schema", this.explodedSchema).andWhereRaw("\"table_catalog\" = current_database()").andWhere({ table_type: "BASE TABLE" }).orderBy("table_name", "asc");
|
|
3595
|
+
if (table) {
|
|
3596
|
+
const rawTable = await query.andWhere({ table_name: table }).limit(1).first();
|
|
3597
|
+
return {
|
|
3598
|
+
name: rawTable.table_name,
|
|
3599
|
+
schema: rawTable.table_schema,
|
|
3600
|
+
comment: rawTable.table_comment
|
|
3601
|
+
};
|
|
3602
|
+
}
|
|
3603
|
+
return (await query).map((rawTable) => {
|
|
3604
|
+
return {
|
|
3605
|
+
name: rawTable.table_name,
|
|
3606
|
+
schema: rawTable.table_schema,
|
|
3607
|
+
comment: rawTable.table_comment
|
|
3608
|
+
};
|
|
3609
|
+
});
|
|
3610
|
+
}
|
|
3611
|
+
/**
|
|
3612
|
+
* Check if a table exists in the current schema/database
|
|
3613
|
+
*/
|
|
3614
|
+
async hasTable(table) {
|
|
3615
|
+
const subquery = this.knex.select().from("information_schema.tables").whereIn("table_schema", this.explodedSchema).andWhere({ table_name: table });
|
|
3616
|
+
const record = await this.knex.select(this.knex.raw("exists (?)", [subquery])).first();
|
|
3617
|
+
return (record === null || record === void 0 ? void 0 : record.exists) || false;
|
|
3618
|
+
}
|
|
3619
|
+
/**
|
|
3620
|
+
* Get all the available columns in the current schema/database. Can be filtered to a specific table
|
|
3621
|
+
*/
|
|
3622
|
+
async columns(table) {
|
|
3623
|
+
const query = this.knex.select("table_name", "column_name").from("information_schema.columns").whereIn("table_schema", this.explodedSchema);
|
|
3624
|
+
if (table) query.andWhere({ table_name: table });
|
|
3625
|
+
return (await query).map(({ table_name, column_name }) => ({
|
|
3626
|
+
table: table_name,
|
|
3627
|
+
column: column_name
|
|
3628
|
+
}));
|
|
3629
|
+
}
|
|
3630
|
+
async columnInfo(table, column) {
|
|
3631
|
+
const { knex } = this;
|
|
3632
|
+
const bindings = [];
|
|
3633
|
+
if (table) bindings.push(table);
|
|
3634
|
+
if (column) bindings.push(column);
|
|
3635
|
+
const schemaIn = this.explodedSchema.map((schemaName) => `${this.knex.raw("?", [schemaName])}::regnamespace`);
|
|
3636
|
+
const [columns, constraints] = await Promise.all([knex.raw(`
|
|
3637
|
+
SELECT *, CASE WHEN res.is_generated THEN (
|
|
3638
|
+
SELECT
|
|
3639
|
+
generation_expression
|
|
3640
|
+
FROM
|
|
3641
|
+
information_schema.columns
|
|
3642
|
+
WHERE
|
|
3643
|
+
table_schema = res.schema
|
|
3644
|
+
AND table_name = res.table
|
|
3645
|
+
AND column_name = res.name
|
|
3646
|
+
) ELSE NULL END AS generation_expression
|
|
3647
|
+
FROM (
|
|
3648
|
+
SELECT
|
|
3649
|
+
att.attname AS name,
|
|
3650
|
+
rel.relname AS table,
|
|
3651
|
+
rel.relnamespace::regnamespace::text AS schema,
|
|
3652
|
+
format_type(att.atttypid, null) AS data_type,
|
|
3653
|
+
NOT att.attnotnull AS is_nullable,
|
|
3654
|
+
CASE WHEN att.attgenerated = '' THEN pg_get_expr(ad.adbin, ad.adrelid) ELSE null END AS default_value,
|
|
3655
|
+
att.attgenerated = 's' AS is_generated,
|
|
3656
|
+
CASE
|
|
3657
|
+
WHEN att.atttypid IN (1042, 1043) THEN (att.atttypmod - 4)::int4
|
|
3658
|
+
WHEN att.atttypid IN (1560, 1562) THEN (att.atttypmod)::int4
|
|
3659
|
+
ELSE NULL
|
|
3660
|
+
END AS max_length,
|
|
3661
|
+
des.description AS comment,
|
|
3662
|
+
CASE att.atttypid
|
|
3663
|
+
WHEN 21 THEN 16
|
|
3664
|
+
WHEN 23 THEN 32
|
|
3665
|
+
WHEN 20 THEN 64
|
|
3666
|
+
WHEN 1700 THEN
|
|
3667
|
+
CASE WHEN atttypmod = -1 THEN NULL
|
|
3668
|
+
ELSE (((atttypmod - 4) >> 16) & 65535)::int4
|
|
3669
|
+
END
|
|
3670
|
+
WHEN 700 THEN 24
|
|
3671
|
+
WHEN 701 THEN 53
|
|
3672
|
+
ELSE NULL
|
|
3673
|
+
END AS numeric_precision,
|
|
3674
|
+
CASE
|
|
3675
|
+
WHEN atttypid IN (21, 23, 20) THEN 0
|
|
3676
|
+
WHEN atttypid = 1700 THEN
|
|
3677
|
+
CASE
|
|
3678
|
+
WHEN atttypmod = -1 THEN NULL
|
|
3679
|
+
ELSE ((atttypmod - 4) & 65535)::int4
|
|
3680
|
+
END
|
|
3681
|
+
ELSE null
|
|
3682
|
+
END AS numeric_scale
|
|
3683
|
+
FROM
|
|
3684
|
+
pg_attribute att
|
|
3685
|
+
LEFT JOIN pg_class rel ON att.attrelid = rel.oid
|
|
3686
|
+
LEFT JOIN pg_attrdef ad ON (att.attrelid, att.attnum) = (ad.adrelid, ad.adnum)
|
|
3687
|
+
LEFT JOIN pg_description des ON (att.attrelid, att.attnum) = (des.objoid, des.objsubid)
|
|
3688
|
+
WHERE
|
|
3689
|
+
rel.relnamespace IN (${schemaIn})
|
|
3690
|
+
${table ? "AND rel.relname = ?" : ""}
|
|
3691
|
+
${column ? "AND att.attname = ?" : ""}
|
|
3692
|
+
AND rel.relkind = 'r'
|
|
3693
|
+
AND att.attnum > 0
|
|
3694
|
+
AND NOT att.attisdropped
|
|
3695
|
+
ORDER BY rel.relname, att.attnum) res;
|
|
3696
|
+
`, bindings), knex.raw(`
|
|
3697
|
+
SELECT
|
|
3698
|
+
con.contype AS type,
|
|
3699
|
+
rel.relname AS table,
|
|
3700
|
+
att.attname AS column,
|
|
3701
|
+
frel.relnamespace::regnamespace::text AS foreign_key_schema,
|
|
3702
|
+
frel.relname AS foreign_key_table,
|
|
3703
|
+
fatt.attname AS foreign_key_column
|
|
3704
|
+
FROM
|
|
3705
|
+
pg_constraint con
|
|
3706
|
+
LEFT JOIN pg_class rel ON con.conrelid = rel.oid
|
|
3707
|
+
LEFT JOIN pg_class frel ON con.confrelid = frel.oid
|
|
3708
|
+
LEFT JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = con.conkey[1]
|
|
3709
|
+
LEFT JOIN pg_attribute fatt ON fatt.attrelid = con.confrelid AND fatt.attnum = con.confkey[1]
|
|
3710
|
+
WHERE con.connamespace IN (${schemaIn})
|
|
3711
|
+
AND array_length(con.conkey, 1) <= 1
|
|
3712
|
+
AND (con.confkey IS NULL OR array_length(con.confkey, 1) = 1)
|
|
3713
|
+
${table ? "AND rel.relname = ?" : ""}
|
|
3714
|
+
${column ? "AND att.attname = ?" : ""}
|
|
3715
|
+
`, bindings)]);
|
|
3716
|
+
const parsedColumms = columns.rows.map((col) => {
|
|
3717
|
+
var _col$default_value;
|
|
3718
|
+
const constraintsForColumn = constraints.rows.filter((constraint) => constraint.table === col.table && constraint.column === col.name);
|
|
3719
|
+
const foreignKeyConstraint = constraintsForColumn.find((constraint) => constraint.type === "f");
|
|
3720
|
+
return {
|
|
3721
|
+
...col,
|
|
3722
|
+
is_unique: constraintsForColumn.some((constraint) => ["u", "p"].includes(constraint.type)),
|
|
3723
|
+
is_primary_key: constraintsForColumn.some((constraint) => constraint.type === "p"),
|
|
3724
|
+
has_auto_increment: ["integer", "bigint"].includes(col.data_type) && (((_col$default_value = col.default_value) === null || _col$default_value === void 0 ? void 0 : _col$default_value.startsWith("nextval(")) ?? false),
|
|
3725
|
+
default_value: parseDefaultValue$5(col.default_value),
|
|
3726
|
+
foreign_key_schema: (foreignKeyConstraint === null || foreignKeyConstraint === void 0 ? void 0 : foreignKeyConstraint.foreign_key_schema) ?? null,
|
|
3727
|
+
foreign_key_table: (foreignKeyConstraint === null || foreignKeyConstraint === void 0 ? void 0 : foreignKeyConstraint.foreign_key_table) ?? null,
|
|
3728
|
+
foreign_key_column: (foreignKeyConstraint === null || foreignKeyConstraint === void 0 ? void 0 : foreignKeyConstraint.foreign_key_column) ?? null
|
|
3729
|
+
};
|
|
3730
|
+
});
|
|
3731
|
+
if (table && column) return parsedColumms[0];
|
|
3732
|
+
return parsedColumms;
|
|
3733
|
+
}
|
|
3734
|
+
/**
|
|
3735
|
+
* Check if the given table contains the given column
|
|
3736
|
+
*/
|
|
3737
|
+
async hasColumn(table, column) {
|
|
3738
|
+
const subquery = this.knex.select().from("information_schema.columns").whereIn("table_schema", this.explodedSchema).andWhere({
|
|
3739
|
+
table_name: table,
|
|
3740
|
+
column_name: column
|
|
3741
|
+
});
|
|
3742
|
+
const record = await this.knex.select(this.knex.raw("exists (?)", [subquery])).first();
|
|
3743
|
+
return (record === null || record === void 0 ? void 0 : record.exists) || false;
|
|
3744
|
+
}
|
|
3745
|
+
/**
|
|
3746
|
+
* Get the primary key column for the given table
|
|
3747
|
+
*/
|
|
3748
|
+
async primary(table) {
|
|
3749
|
+
const result = await this.knex.select("information_schema.key_column_usage.column_name").from("information_schema.key_column_usage").leftJoin("information_schema.table_constraints", function() {
|
|
3750
|
+
this.on("information_schema.table_constraints.constraint_name", "=", "information_schema.key_column_usage.constraint_name").andOn("information_schema.table_constraints.table_name", "=", "information_schema.key_column_usage.table_name");
|
|
3751
|
+
}).whereIn("information_schema.table_constraints.table_schema", this.explodedSchema).andWhere({
|
|
3752
|
+
"information_schema.table_constraints.constraint_type": "PRIMARY KEY",
|
|
3753
|
+
"information_schema.table_constraints.table_name": table
|
|
3754
|
+
});
|
|
3755
|
+
return result.length > 0 ? result.length === 1 ? result[0].column_name : result.map((r) => r.column_name) : null;
|
|
3756
|
+
}
|
|
3757
|
+
async foreignKeys(table) {
|
|
3758
|
+
const rowsWithoutQuotes = (await this.knex.raw(`
|
|
3759
|
+
SELECT
|
|
3760
|
+
c.conrelid::regclass::text AS "table",
|
|
3761
|
+
(
|
|
3762
|
+
SELECT
|
|
3763
|
+
STRING_AGG(a.attname, ','
|
|
3764
|
+
ORDER BY
|
|
3765
|
+
t.seq)
|
|
3766
|
+
FROM (
|
|
3767
|
+
SELECT
|
|
3768
|
+
ROW_NUMBER() OVER (ROWS UNBOUNDED PRECEDING) AS seq,
|
|
3769
|
+
attnum
|
|
3770
|
+
FROM
|
|
3771
|
+
UNNEST(c.conkey) AS t (attnum)) AS t
|
|
3772
|
+
INNER JOIN pg_attribute AS a ON a.attrelid = c.conrelid
|
|
3773
|
+
AND a.attnum = t.attnum) AS "column",
|
|
3774
|
+
tt.name AS foreign_key_table,
|
|
3775
|
+
(
|
|
3776
|
+
SELECT
|
|
3777
|
+
STRING_AGG(QUOTE_IDENT(a.attname), ','
|
|
3778
|
+
ORDER BY
|
|
3779
|
+
t.seq)
|
|
3780
|
+
FROM (
|
|
3781
|
+
SELECT
|
|
3782
|
+
ROW_NUMBER() OVER (ROWS UNBOUNDED PRECEDING) AS seq,
|
|
3783
|
+
attnum
|
|
3784
|
+
FROM
|
|
3785
|
+
UNNEST(c.confkey) AS t (attnum)) AS t
|
|
3786
|
+
INNER JOIN pg_attribute AS a ON a.attrelid = c.confrelid
|
|
3787
|
+
AND a.attnum = t.attnum) AS foreign_key_column,
|
|
3788
|
+
tt.schema AS foreign_key_schema,
|
|
3789
|
+
c.conname AS constraint_name,
|
|
3790
|
+
CASE confupdtype
|
|
3791
|
+
WHEN 'r' THEN
|
|
3792
|
+
'RESTRICT'
|
|
3793
|
+
WHEN 'c' THEN
|
|
3794
|
+
'CASCADE'
|
|
3795
|
+
WHEN 'n' THEN
|
|
3796
|
+
'SET NULL'
|
|
3797
|
+
WHEN 'd' THEN
|
|
3798
|
+
'SET DEFAULT'
|
|
3799
|
+
WHEN 'a' THEN
|
|
3800
|
+
'NO ACTION'
|
|
3801
|
+
ELSE
|
|
3802
|
+
NULL
|
|
3803
|
+
END AS on_update,
|
|
3804
|
+
CASE confdeltype
|
|
3805
|
+
WHEN 'r' THEN
|
|
3806
|
+
'RESTRICT'
|
|
3807
|
+
WHEN 'c' THEN
|
|
3808
|
+
'CASCADE'
|
|
3809
|
+
WHEN 'n' THEN
|
|
3810
|
+
'SET NULL'
|
|
3811
|
+
WHEN 'd' THEN
|
|
3812
|
+
'SET DEFAULT'
|
|
3813
|
+
WHEN 'a' THEN
|
|
3814
|
+
'NO ACTION'
|
|
3815
|
+
ELSE
|
|
3816
|
+
NULL
|
|
3817
|
+
END AS
|
|
3818
|
+
on_delete
|
|
3819
|
+
FROM
|
|
3820
|
+
pg_catalog.pg_constraint AS c
|
|
3821
|
+
INNER JOIN (
|
|
3822
|
+
SELECT
|
|
3823
|
+
pg_class.oid,
|
|
3824
|
+
QUOTE_IDENT(pg_namespace.nspname) AS SCHEMA,
|
|
3825
|
+
QUOTE_IDENT(pg_class.relname) AS name
|
|
3826
|
+
FROM
|
|
3827
|
+
pg_class
|
|
3828
|
+
INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid) AS tf ON tf.oid = c.conrelid
|
|
3829
|
+
INNER JOIN (
|
|
3830
|
+
SELECT
|
|
3831
|
+
pg_class.oid,
|
|
3832
|
+
QUOTE_IDENT(pg_namespace.nspname) AS SCHEMA,
|
|
3833
|
+
QUOTE_IDENT(pg_class.relname) AS name
|
|
3834
|
+
FROM
|
|
3835
|
+
pg_class
|
|
3836
|
+
INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid) AS tt ON tt.oid = c.confrelid
|
|
3837
|
+
WHERE
|
|
3838
|
+
c.contype = 'f';
|
|
3839
|
+
`)).rows.map(stripRowQuotes);
|
|
3840
|
+
if (table) return rowsWithoutQuotes.filter((row) => row.table === table);
|
|
3841
|
+
return rowsWithoutQuotes;
|
|
3842
|
+
function stripRowQuotes(row) {
|
|
3843
|
+
return Object.fromEntries(Object.entries(row).map(([key, value]) => {
|
|
3844
|
+
return [key, stripQuotes(value)];
|
|
3845
|
+
}));
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3848
|
+
};
|
|
3849
|
+
|
|
3850
|
+
//#endregion
|
|
3851
|
+
//#region src/inspector/dialects/mssql.ts
|
|
3852
|
+
function rawColumnToColumn$2(rawColumn) {
|
|
3853
|
+
return {
|
|
3854
|
+
...rawColumn,
|
|
3855
|
+
default_value: parseDefaultValue$4(rawColumn.default_value),
|
|
3856
|
+
generation_expression: rawColumn.generation_expression || null,
|
|
3857
|
+
is_generated: !!rawColumn.is_generated,
|
|
3858
|
+
is_unique: rawColumn.is_unique === true,
|
|
3859
|
+
is_primary_key: rawColumn.is_primary_key === true,
|
|
3860
|
+
is_nullable: rawColumn.is_nullable === "YES",
|
|
3861
|
+
has_auto_increment: rawColumn.has_auto_increment === "YES",
|
|
3862
|
+
numeric_precision: rawColumn.numeric_precision || null,
|
|
3863
|
+
numeric_scale: rawColumn.numeric_scale || null,
|
|
3864
|
+
max_length: parseMaxLength(rawColumn)
|
|
3865
|
+
};
|
|
3866
|
+
function parseMaxLength(rawColumn$1) {
|
|
3867
|
+
const max_length = Number(rawColumn$1.max_length);
|
|
3868
|
+
if (Number.isNaN(max_length) || rawColumn$1.max_length === null || rawColumn$1.max_length === void 0) return null;
|
|
3869
|
+
if ([
|
|
3870
|
+
"nvarchar",
|
|
3871
|
+
"nchar",
|
|
3872
|
+
"ntext"
|
|
3873
|
+
].includes(rawColumn$1.data_type)) return max_length === -1 ? max_length : max_length / 2;
|
|
3874
|
+
return max_length;
|
|
3875
|
+
}
|
|
3876
|
+
}
|
|
3877
|
+
function parseDefaultValue$4(value) {
|
|
3878
|
+
if (value === null) return null;
|
|
3879
|
+
while (value.startsWith("(") && value.endsWith(")")) value = value.slice(1, -1);
|
|
3880
|
+
if (value.trim().toLowerCase() === "null") return null;
|
|
3881
|
+
return stripQuotes(value);
|
|
3882
|
+
}
|
|
3883
|
+
var MSSQL = class {
|
|
3884
|
+
knex;
|
|
3885
|
+
_schema;
|
|
3886
|
+
constructor(knex) {
|
|
3887
|
+
this.knex = knex;
|
|
3888
|
+
}
|
|
3889
|
+
/**
|
|
3890
|
+
* Set the schema to be used in other methods
|
|
3891
|
+
*/
|
|
3892
|
+
withSchema(schema) {
|
|
3893
|
+
this.schema = schema;
|
|
3894
|
+
return this;
|
|
3895
|
+
}
|
|
3896
|
+
get schema() {
|
|
3897
|
+
return this._schema || "dbo";
|
|
3898
|
+
}
|
|
3899
|
+
set schema(value) {
|
|
3900
|
+
this._schema = value;
|
|
3901
|
+
}
|
|
3902
|
+
/**
|
|
3903
|
+
* List all existing tables in the current schema/database
|
|
3904
|
+
*/
|
|
3905
|
+
async tables() {
|
|
3906
|
+
return (await this.knex.select("TABLE_NAME").from("INFORMATION_SCHEMA.TABLES").where({
|
|
3907
|
+
TABLE_TYPE: "BASE TABLE",
|
|
3908
|
+
TABLE_CATALOG: this.knex.client.database(),
|
|
3909
|
+
TABLE_SCHEMA: this.schema
|
|
3910
|
+
})).map(({ TABLE_NAME }) => TABLE_NAME);
|
|
3911
|
+
}
|
|
3912
|
+
async tableInfo(table) {
|
|
3913
|
+
const query = this.knex.select("TABLE_NAME", "TABLE_SCHEMA", "TABLE_CATALOG", "TABLE_TYPE").from("INFORMATION_SCHEMA.TABLES").where({
|
|
3914
|
+
TABLE_CATALOG: this.knex.client.database(),
|
|
3915
|
+
TABLE_TYPE: "BASE TABLE",
|
|
3916
|
+
TABLE_SCHEMA: this.schema
|
|
3917
|
+
});
|
|
3918
|
+
if (table) {
|
|
3919
|
+
const rawTable = await query.andWhere({ table_name: table }).first();
|
|
3920
|
+
return {
|
|
3921
|
+
name: rawTable.TABLE_NAME,
|
|
3922
|
+
schema: rawTable.TABLE_SCHEMA,
|
|
3923
|
+
catalog: rawTable.TABLE_CATALOG
|
|
3924
|
+
};
|
|
3925
|
+
}
|
|
3926
|
+
return (await query).map((rawTable) => {
|
|
3927
|
+
return {
|
|
3928
|
+
name: rawTable.TABLE_NAME,
|
|
3929
|
+
schema: rawTable.TABLE_SCHEMA,
|
|
3930
|
+
catalog: rawTable.TABLE_CATALOG
|
|
3931
|
+
};
|
|
3932
|
+
});
|
|
3933
|
+
}
|
|
3934
|
+
/**
|
|
3935
|
+
* Check if a table exists in the current schema/database
|
|
3936
|
+
*/
|
|
3937
|
+
async hasTable(table) {
|
|
3938
|
+
const result = await this.knex.count({ count: "*" }).from("INFORMATION_SCHEMA.TABLES").where({
|
|
3939
|
+
TABLE_CATALOG: this.knex.client.database(),
|
|
3940
|
+
table_name: table,
|
|
3941
|
+
TABLE_SCHEMA: this.schema
|
|
3942
|
+
}).first();
|
|
3943
|
+
return result && result.count === 1 || false;
|
|
3944
|
+
}
|
|
3945
|
+
/**
|
|
3946
|
+
* Get all the available columns in the current schema/database. Can be filtered to a specific table
|
|
3947
|
+
*/
|
|
3948
|
+
async columns(table) {
|
|
3949
|
+
const query = this.knex.select("TABLE_NAME", "COLUMN_NAME").from("INFORMATION_SCHEMA.COLUMNS").where({
|
|
3950
|
+
TABLE_CATALOG: this.knex.client.database(),
|
|
3951
|
+
TABLE_SCHEMA: this.schema
|
|
3952
|
+
});
|
|
3953
|
+
if (table) query.andWhere({ TABLE_NAME: table });
|
|
3954
|
+
return (await query).map(({ TABLE_NAME, COLUMN_NAME }) => ({
|
|
3955
|
+
table: TABLE_NAME,
|
|
3956
|
+
column: COLUMN_NAME
|
|
3957
|
+
}));
|
|
3958
|
+
}
|
|
3959
|
+
async columnInfo(table, column) {
|
|
3960
|
+
const dbName = this.knex.client.database();
|
|
3961
|
+
const query = this.knex.select(this.knex.raw(`
|
|
3962
|
+
[o].[name] AS [table],
|
|
3963
|
+
[c].[name] AS [name],
|
|
3964
|
+
[t].[name] AS [data_type],
|
|
3965
|
+
[c].[max_length] AS [max_length],
|
|
3966
|
+
[c].[precision] AS [numeric_precision],
|
|
3967
|
+
[c].[scale] AS [numeric_scale],
|
|
3968
|
+
CASE WHEN [c].[is_nullable] = 0 THEN
|
|
3969
|
+
'NO'
|
|
3970
|
+
ELSE
|
|
3971
|
+
'YES'
|
|
3972
|
+
END AS [is_nullable],
|
|
3973
|
+
object_definition ([c].[default_object_id]) AS [default_value],
|
|
3974
|
+
[i].[is_primary_key],
|
|
3975
|
+
[i].[is_unique],
|
|
3976
|
+
CASE [c].[is_identity]
|
|
3977
|
+
WHEN 1 THEN
|
|
3978
|
+
'YES'
|
|
3979
|
+
ELSE
|
|
3980
|
+
'NO'
|
|
3981
|
+
END AS [has_auto_increment],
|
|
3982
|
+
OBJECT_NAME ([fk].[referenced_object_id]) AS [foreign_key_table],
|
|
3983
|
+
COL_NAME ([fk].[referenced_object_id],
|
|
3984
|
+
[fk].[referenced_column_id]) AS [foreign_key_column],
|
|
3985
|
+
[cc].[is_computed] as [is_generated],
|
|
3986
|
+
[cc].[definition] as [generation_expression]`)).from(this.knex.raw("??.[sys].[columns] [c]", [dbName])).joinRaw("JOIN [sys].[types] [t] ON [c].[user_type_id] = [t].[user_type_id]").joinRaw("JOIN [sys].[tables] [o] ON [o].[object_id] = [c].[object_id]").joinRaw("JOIN [sys].[schemas] [s] ON [s].[schema_id] = [o].[schema_id]").joinRaw("LEFT JOIN [sys].[computed_columns] AS [cc] ON [cc].[object_id] = [c].[object_id] AND [cc].[column_id] = [c].[column_id]").joinRaw("LEFT JOIN [sys].[foreign_key_columns] AS [fk] ON [fk].[parent_object_id] = [c].[object_id] AND [fk].[parent_column_id] = [c].[column_id]").joinRaw(`LEFT JOIN (
|
|
3987
|
+
SELECT
|
|
3988
|
+
[ic].[object_id],
|
|
3989
|
+
[ic].[column_id],
|
|
3990
|
+
[ix].[is_unique],
|
|
3991
|
+
[ix].[is_primary_key],
|
|
3992
|
+
MAX([ic].[index_column_id]) OVER(partition by [ic].[index_id], [ic].[object_id]) AS index_column_count,
|
|
3993
|
+
ROW_NUMBER() OVER (
|
|
3994
|
+
PARTITION BY [ic].[object_id], [ic].[column_id]
|
|
3995
|
+
ORDER BY [ix].[is_primary_key] DESC, [ix].[is_unique] DESC
|
|
3996
|
+
) AS index_priority
|
|
3997
|
+
FROM
|
|
3998
|
+
[sys].[index_columns] [ic]
|
|
3999
|
+
JOIN [sys].[indexes] AS [ix] ON [ix].[object_id] = [ic].[object_id]
|
|
4000
|
+
AND [ix].[index_id] = [ic].[index_id]
|
|
4001
|
+
) AS [i]
|
|
4002
|
+
ON [i].[object_id] = [c].[object_id]
|
|
4003
|
+
AND [i].[column_id] = [c].[column_id]
|
|
4004
|
+
AND ISNULL([i].[index_column_count], 1) = 1
|
|
4005
|
+
AND ISNULL([i].[index_priority], 1) = 1`).where({ "s.name": this.schema });
|
|
4006
|
+
if (table) query.andWhere({ "o.name": table });
|
|
4007
|
+
if (column) {
|
|
4008
|
+
const rawColumn = await query.andWhere({ "c.name": column }).first();
|
|
4009
|
+
return rawColumnToColumn$2(rawColumn);
|
|
4010
|
+
}
|
|
4011
|
+
return (await query).map(rawColumnToColumn$2);
|
|
4012
|
+
}
|
|
4013
|
+
/**
|
|
4014
|
+
* Check if a table exists in the current schema/database
|
|
4015
|
+
*/
|
|
4016
|
+
async hasColumn(table, column) {
|
|
4017
|
+
const result = await this.knex.count({ count: "*" }).from("INFORMATION_SCHEMA.COLUMNS").where({
|
|
4018
|
+
TABLE_CATALOG: this.knex.client.database(),
|
|
4019
|
+
TABLE_NAME: table,
|
|
4020
|
+
COLUMN_NAME: column,
|
|
4021
|
+
TABLE_SCHEMA: this.schema
|
|
4022
|
+
}).first();
|
|
4023
|
+
return result && result.count === 1 || false;
|
|
4024
|
+
}
|
|
4025
|
+
/**
|
|
4026
|
+
* Get the primary key column for the given table
|
|
4027
|
+
*/
|
|
4028
|
+
async primary(table) {
|
|
4029
|
+
const results = await this.knex.raw(`SELECT
|
|
4030
|
+
Col.Column_Name
|
|
4031
|
+
FROM
|
|
4032
|
+
INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab,
|
|
4033
|
+
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
|
|
4034
|
+
WHERE
|
|
4035
|
+
Col.Constraint_Name = Tab.Constraint_Name
|
|
4036
|
+
AND Col.Table_Name = Tab.Table_Name
|
|
4037
|
+
AND Constraint_Type = 'PRIMARY KEY'
|
|
4038
|
+
AND Col.Table_Name = ?
|
|
4039
|
+
AND Tab.CONSTRAINT_SCHEMA = ?`, [table, this.schema]);
|
|
4040
|
+
return results.length > 0 ? results.length === 1 ? results[0]["Column_Name"] : results.map((row) => row["Column_Name"]) : null;
|
|
4041
|
+
}
|
|
4042
|
+
async foreignKeys(table) {
|
|
4043
|
+
const result = await this.knex.raw(`
|
|
4044
|
+
SELECT
|
|
4045
|
+
OBJECT_NAME (fc.parent_object_id) AS "table",
|
|
4046
|
+
COL_NAME (fc.parent_object_id, fc.parent_column_id) AS "column",
|
|
4047
|
+
OBJECT_SCHEMA_NAME (f.referenced_object_id) AS foreign_key_schema,
|
|
4048
|
+
OBJECT_NAME (f.referenced_object_id) AS foreign_key_table,
|
|
4049
|
+
COL_NAME (fc.referenced_object_id, fc.referenced_column_id) AS foreign_key_column,
|
|
4050
|
+
f.name AS constraint_name,
|
|
4051
|
+
REPLACE(f.update_referential_action_desc, '_', ' ') AS on_update,
|
|
4052
|
+
REPLACE(f.delete_referential_action_desc, '_', ' ') AS on_delete
|
|
4053
|
+
FROM
|
|
4054
|
+
sys.foreign_keys AS f
|
|
4055
|
+
INNER JOIN sys.foreign_key_columns AS fc ON f.OBJECT_ID = fc.constraint_object_id
|
|
4056
|
+
WHERE
|
|
4057
|
+
OBJECT_SCHEMA_NAME (f.parent_object_id) = ?;
|
|
4058
|
+
`, [this.schema]);
|
|
4059
|
+
if (table) return result === null || result === void 0 ? void 0 : result.filter((row) => row.table === table);
|
|
4060
|
+
return result;
|
|
4061
|
+
}
|
|
4062
|
+
};
|
|
4063
|
+
|
|
4064
|
+
//#endregion
|
|
4065
|
+
//#region src/inspector/dialects/mysql.ts
|
|
4066
|
+
function rawColumnToColumn$1(rawColumn) {
|
|
4067
|
+
var _rawColumn$EXTRA;
|
|
4068
|
+
let dataType = rawColumn.COLUMN_TYPE.replace(/\(.*?\)/, "");
|
|
4069
|
+
if (rawColumn.COLUMN_TYPE.startsWith("tinyint(1)")) dataType = "boolean";
|
|
4070
|
+
return {
|
|
4071
|
+
name: rawColumn.COLUMN_NAME,
|
|
4072
|
+
table: rawColumn.TABLE_NAME,
|
|
4073
|
+
collation: rawColumn.COLLATION_NAME,
|
|
4074
|
+
data_type: dataType,
|
|
4075
|
+
default_value: parseDefaultValue$3(rawColumn.COLUMN_DEFAULT),
|
|
4076
|
+
generation_expression: rawColumn.GENERATION_EXPRESSION || null,
|
|
4077
|
+
max_length: rawColumn.CHARACTER_MAXIMUM_LENGTH,
|
|
4078
|
+
numeric_precision: rawColumn.NUMERIC_PRECISION,
|
|
4079
|
+
numeric_scale: rawColumn.NUMERIC_SCALE,
|
|
4080
|
+
is_generated: !!((_rawColumn$EXTRA = rawColumn.EXTRA) === null || _rawColumn$EXTRA === void 0 ? void 0 : _rawColumn$EXTRA.endsWith("GENERATED")),
|
|
4081
|
+
is_nullable: rawColumn.IS_NULLABLE === "YES",
|
|
4082
|
+
is_unique: rawColumn.COLUMN_KEY === "UNI",
|
|
4083
|
+
is_primary_key: rawColumn.CONSTRAINT_NAME === "PRIMARY" || rawColumn.COLUMN_KEY === "PRI",
|
|
4084
|
+
has_auto_increment: rawColumn.EXTRA === "auto_increment",
|
|
4085
|
+
foreign_key_column: rawColumn.REFERENCED_COLUMN_NAME,
|
|
4086
|
+
foreign_key_table: rawColumn.REFERENCED_TABLE_NAME,
|
|
4087
|
+
comment: rawColumn.COLUMN_COMMENT
|
|
4088
|
+
};
|
|
4089
|
+
}
|
|
4090
|
+
function parseDefaultValue$3(value) {
|
|
4091
|
+
if (value === null || value.trim().toLowerCase() === "null") return null;
|
|
4092
|
+
return stripQuotes(value);
|
|
4093
|
+
}
|
|
4094
|
+
var MySQL = class {
|
|
4095
|
+
knex;
|
|
4096
|
+
constructor(knex) {
|
|
4097
|
+
this.knex = knex;
|
|
4098
|
+
}
|
|
4099
|
+
/**
|
|
4100
|
+
* List all existing tables in the current schema/database
|
|
4101
|
+
*/
|
|
4102
|
+
async tables() {
|
|
4103
|
+
return (await this.knex.select("TABLE_NAME").from("INFORMATION_SCHEMA.TABLES").where({
|
|
4104
|
+
TABLE_TYPE: "BASE TABLE",
|
|
4105
|
+
TABLE_SCHEMA: this.knex.client.database()
|
|
4106
|
+
})).map(({ TABLE_NAME }) => TABLE_NAME);
|
|
4107
|
+
}
|
|
4108
|
+
async tableInfo(table) {
|
|
4109
|
+
const query = this.knex.select("TABLE_NAME", "ENGINE", "TABLE_SCHEMA", "TABLE_COLLATION", "TABLE_COMMENT").from("information_schema.tables").where({
|
|
4110
|
+
table_schema: this.knex.client.database(),
|
|
4111
|
+
table_type: "BASE TABLE"
|
|
4112
|
+
});
|
|
4113
|
+
if (table) {
|
|
4114
|
+
const rawTable = await query.andWhere({ table_name: table }).first();
|
|
4115
|
+
return {
|
|
4116
|
+
name: rawTable.TABLE_NAME,
|
|
4117
|
+
schema: rawTable.TABLE_SCHEMA,
|
|
4118
|
+
comment: rawTable.TABLE_COMMENT,
|
|
4119
|
+
collation: rawTable.TABLE_COLLATION,
|
|
4120
|
+
engine: rawTable.ENGINE
|
|
4121
|
+
};
|
|
4122
|
+
}
|
|
4123
|
+
return (await query).map((rawTable) => {
|
|
4124
|
+
return {
|
|
4125
|
+
name: rawTable.TABLE_NAME,
|
|
4126
|
+
schema: rawTable.TABLE_SCHEMA,
|
|
4127
|
+
comment: rawTable.TABLE_COMMENT,
|
|
4128
|
+
collation: rawTable.TABLE_COLLATION,
|
|
4129
|
+
engine: rawTable.ENGINE
|
|
4130
|
+
};
|
|
4131
|
+
});
|
|
4132
|
+
}
|
|
4133
|
+
/**
|
|
4134
|
+
* Check if a table exists in the current schema/database
|
|
4135
|
+
*/
|
|
4136
|
+
async hasTable(table) {
|
|
4137
|
+
const result = await this.knex.count({ count: "*" }).from("information_schema.tables").where({
|
|
4138
|
+
table_schema: this.knex.client.database(),
|
|
4139
|
+
table_name: table
|
|
4140
|
+
}).first();
|
|
4141
|
+
return result && result.count === 1 || false;
|
|
4142
|
+
}
|
|
4143
|
+
/**
|
|
4144
|
+
* Get all the available columns in the current schema/database. Can be filtered to a specific table
|
|
4145
|
+
*/
|
|
4146
|
+
async columns(table) {
|
|
4147
|
+
const query = this.knex.select("TABLE_NAME", "COLUMN_NAME").from("INFORMATION_SCHEMA.COLUMNS").where({ TABLE_SCHEMA: this.knex.client.database() });
|
|
4148
|
+
if (table) query.andWhere({ TABLE_NAME: table });
|
|
4149
|
+
return (await query).map(({ TABLE_NAME, COLUMN_NAME }) => ({
|
|
4150
|
+
table: TABLE_NAME,
|
|
4151
|
+
column: COLUMN_NAME
|
|
4152
|
+
}));
|
|
4153
|
+
}
|
|
4154
|
+
async columnInfo(table, column) {
|
|
4155
|
+
const query = this.knex.select("c.TABLE_NAME", "c.COLUMN_NAME", "c.COLUMN_DEFAULT", "c.COLUMN_TYPE", "c.CHARACTER_MAXIMUM_LENGTH", "c.IS_NULLABLE", "c.COLUMN_KEY", "c.EXTRA", "c.COLLATION_NAME", "c.COLUMN_COMMENT", "c.NUMERIC_PRECISION", "c.NUMERIC_SCALE", "c.GENERATION_EXPRESSION", "fk.REFERENCED_TABLE_NAME", "fk.REFERENCED_COLUMN_NAME", "fk.CONSTRAINT_NAME", "rc.UPDATE_RULE", "rc.DELETE_RULE", "rc.MATCH_OPTION").from("INFORMATION_SCHEMA.COLUMNS as c").leftJoin("INFORMATION_SCHEMA.KEY_COLUMN_USAGE as fk", function() {
|
|
4156
|
+
this.on("c.TABLE_NAME", "=", "fk.TABLE_NAME").andOn("fk.COLUMN_NAME", "=", "c.COLUMN_NAME").andOn("fk.CONSTRAINT_SCHEMA", "=", "c.TABLE_SCHEMA");
|
|
4157
|
+
}).leftJoin("INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as rc", function() {
|
|
4158
|
+
this.on("rc.TABLE_NAME", "=", "fk.TABLE_NAME").andOn("rc.CONSTRAINT_NAME", "=", "fk.CONSTRAINT_NAME").andOn("rc.CONSTRAINT_SCHEMA", "=", "fk.CONSTRAINT_SCHEMA");
|
|
4159
|
+
}).where({ "c.TABLE_SCHEMA": this.knex.client.database() });
|
|
4160
|
+
if (table) query.andWhere({ "c.TABLE_NAME": table });
|
|
4161
|
+
if (column) {
|
|
4162
|
+
const rawColumn = await query.andWhere({ "c.column_name": column }).first();
|
|
4163
|
+
return rawColumnToColumn$1(rawColumn);
|
|
4164
|
+
}
|
|
4165
|
+
return (await query).map(rawColumnToColumn$1).sort((column$1) => +!column$1.foreign_key_column).filter((column$1, index, records) => {
|
|
4166
|
+
return records.findIndex((_column) => {
|
|
4167
|
+
return column$1.name === _column.name && column$1.table === _column.table;
|
|
4168
|
+
}) === index;
|
|
4169
|
+
});
|
|
4170
|
+
}
|
|
4171
|
+
/**
|
|
4172
|
+
* Check if a table exists in the current schema/database
|
|
4173
|
+
*/
|
|
4174
|
+
async hasColumn(table, column) {
|
|
4175
|
+
const result = await this.knex.count("*", { as: "count" }).from("information_schema.columns").where({
|
|
4176
|
+
table_schema: this.knex.client.database(),
|
|
4177
|
+
table_name: table,
|
|
4178
|
+
column_name: column
|
|
4179
|
+
}).first();
|
|
4180
|
+
return !!(result && result.count);
|
|
4181
|
+
}
|
|
4182
|
+
/**
|
|
4183
|
+
* Get the primary key column for the given table
|
|
4184
|
+
*/
|
|
4185
|
+
async primary(table) {
|
|
4186
|
+
const results = await this.knex.raw("SHOW KEYS FROM ?? WHERE Key_name = 'PRIMARY'", table);
|
|
4187
|
+
if (results && results.length && results[0].length) {
|
|
4188
|
+
if (results[0].length === 1) return results[0][0]["Column_name"];
|
|
4189
|
+
return results[0].map((row) => row["Column_name"]);
|
|
4190
|
+
}
|
|
4191
|
+
return null;
|
|
4192
|
+
}
|
|
4193
|
+
async foreignKeys(table) {
|
|
4194
|
+
const query = this.knex.select("rc.TABLE_NAME AS table", "kcu.COLUMN_NAME AS column", "rc.REFERENCED_TABLE_NAME AS foreign_key_table", "kcu.REFERENCED_COLUMN_NAME AS foreign_key_column", "rc.CONSTRAINT_NAME AS constraint_name", "rc.UPDATE_RULE AS on_update", "rc.DELETE_RULE AS on_delete").from("information_schema.referential_constraints AS rc").leftJoin("information_schema.key_column_usage AS kcu ", function() {
|
|
4195
|
+
this.on("rc.CONSTRAINT_NAME", "=", "kcu.CONSTRAINT_NAME").andOn("kcu.CONSTRAINT_SCHEMA", "=", "rc.CONSTRAINT_SCHEMA");
|
|
4196
|
+
}).where({ "rc.CONSTRAINT_SCHEMA": this.knex.client.database() });
|
|
4197
|
+
if (table) query.andWhere({ "rc.TABLE_NAME": table });
|
|
4198
|
+
return await query;
|
|
4199
|
+
}
|
|
4200
|
+
async uniqueConstraints(table) {
|
|
4201
|
+
const { knex } = this;
|
|
4202
|
+
const query = knex.select("stat.table_name AS table_name", "stat.index_name AS constraint_name", knex.raw("group_concat(stat.column_name ORDER BY stat.seq_in_index separator ', ') AS columns")).from("information_schema.statistics stat").join("information_schema.table_constraints tco", function() {
|
|
4203
|
+
this.on("stat.table_schema", "=", "tco.table_schema").andOn("stat.table_name", "=", "tco.table_name").andOn("stat.index_name", "=", "tco.constraint_name");
|
|
4204
|
+
}).where("stat.non_unique", "=", 0).andWhere("tco.constraint_type", "=", "UNIQUE").andWhere("stat.table_schema", knex.client.database()).groupBy([
|
|
4205
|
+
"stat.table_name",
|
|
4206
|
+
"stat.index_name",
|
|
4207
|
+
"tco.constraint_type"
|
|
4208
|
+
]);
|
|
4209
|
+
if (table) query.andWhere("stat.table_name", "=", table);
|
|
4210
|
+
return (await query).map((v) => ({
|
|
4211
|
+
table: v.table_name,
|
|
4212
|
+
constraint_name: v.constraint_name,
|
|
4213
|
+
columns: v.columns
|
|
4214
|
+
}));
|
|
4215
|
+
}
|
|
4216
|
+
};
|
|
4217
|
+
|
|
4218
|
+
//#endregion
|
|
4219
|
+
//#region src/inspector/dialects/oracledb.ts
|
|
4220
|
+
/**
|
|
4221
|
+
* NOTE: Use previous optimizer for better data dictionary performance.
|
|
4222
|
+
*/
|
|
4223
|
+
const OPTIMIZER_FEATURES = "11.2.0.4";
|
|
4224
|
+
function rawColumnToColumn(rawColumn) {
|
|
4225
|
+
const is_generated = rawColumn.VIRTUAL_COLUMN === "YES";
|
|
4226
|
+
const default_value = parseDefaultValue$2(rawColumn.DATA_DEFAULT);
|
|
4227
|
+
return {
|
|
4228
|
+
name: rawColumn.COLUMN_NAME,
|
|
4229
|
+
table: rawColumn.TABLE_NAME,
|
|
4230
|
+
data_type: rawColumn.DATA_TYPE,
|
|
4231
|
+
default_value: !is_generated ? default_value : null,
|
|
4232
|
+
generation_expression: is_generated ? default_value : null,
|
|
4233
|
+
max_length: rawColumn.DATA_LENGTH,
|
|
4234
|
+
numeric_precision: rawColumn.DATA_PRECISION,
|
|
4235
|
+
numeric_scale: rawColumn.DATA_SCALE,
|
|
4236
|
+
is_generated: rawColumn.VIRTUAL_COLUMN === "YES",
|
|
4237
|
+
is_nullable: rawColumn.NULLABLE === "Y",
|
|
4238
|
+
is_unique: rawColumn.CONSTRAINT_TYPE === "U",
|
|
4239
|
+
is_primary_key: rawColumn.CONSTRAINT_TYPE === "P",
|
|
4240
|
+
has_auto_increment: rawColumn.IDENTITY_COLUMN === "YES",
|
|
4241
|
+
foreign_key_column: rawColumn.REFERENCED_COLUMN_NAME,
|
|
4242
|
+
foreign_key_table: rawColumn.REFERENCED_TABLE_NAME,
|
|
4243
|
+
comment: rawColumn.COLUMN_COMMENT
|
|
4244
|
+
};
|
|
4245
|
+
}
|
|
4246
|
+
function parseDefaultValue$2(value) {
|
|
4247
|
+
if (value === null || value.trim().toLowerCase() === "null") return null;
|
|
4248
|
+
if (value === "CURRENT_TIMESTAMP ") return "CURRENT_TIMESTAMP";
|
|
4249
|
+
return stripQuotes(value);
|
|
4250
|
+
}
|
|
4251
|
+
var oracleDB = class {
|
|
4252
|
+
knex;
|
|
4253
|
+
constructor(knex) {
|
|
4254
|
+
this.knex = knex;
|
|
4255
|
+
}
|
|
4256
|
+
/**
|
|
4257
|
+
* List all existing tables in the current schema/database
|
|
4258
|
+
*/
|
|
4259
|
+
async tables() {
|
|
4260
|
+
return (await this.knex.select(this.knex.raw(`
|
|
4261
|
+
/*+ OPTIMIZER_FEATURES_ENABLE('${OPTIMIZER_FEATURES}') */
|
|
4262
|
+
"TABLE_NAME" "name"
|
|
4263
|
+
`)).from("USER_TABLES")).map(({ name }) => name);
|
|
4264
|
+
}
|
|
4265
|
+
async tableInfo(table) {
|
|
4266
|
+
const query = this.knex.select(this.knex.raw(`
|
|
4267
|
+
/*+ OPTIMIZER_FEATURES_ENABLE('${OPTIMIZER_FEATURES}') */
|
|
4268
|
+
"TABLE_NAME" "name"
|
|
4269
|
+
`)).from("USER_TABLES");
|
|
4270
|
+
if (table) return await query.andWhere({ TABLE_NAME: table }).first();
|
|
4271
|
+
return await query;
|
|
4272
|
+
}
|
|
4273
|
+
/**
|
|
4274
|
+
* Check if a table exists in the current schema/database
|
|
4275
|
+
*/
|
|
4276
|
+
async hasTable(table) {
|
|
4277
|
+
const result = await this.knex.select(this.knex.raw(`
|
|
4278
|
+
/*+ OPTIMIZER_FEATURES_ENABLE('${OPTIMIZER_FEATURES}') */
|
|
4279
|
+
COUNT(*) "count"
|
|
4280
|
+
`)).from("USER_TABLES").where({ TABLE_NAME: table }).first();
|
|
4281
|
+
return !!(result === null || result === void 0 ? void 0 : result.count);
|
|
4282
|
+
}
|
|
4283
|
+
/**
|
|
4284
|
+
* Get all the available columns in the current schema/database. Can be filtered to a specific table
|
|
4285
|
+
*/
|
|
4286
|
+
async columns(table) {
|
|
4287
|
+
const query = this.knex.select(this.knex.raw(`
|
|
4288
|
+
/*+ OPTIMIZER_FEATURES_ENABLE('${OPTIMIZER_FEATURES}') NO_QUERY_TRANSFORMATION */
|
|
4289
|
+
"TABLE_NAME" "table",
|
|
4290
|
+
"COLUMN_NAME" "column"
|
|
4291
|
+
`)).from("USER_TAB_COLS").where({ HIDDEN_COLUMN: "NO" });
|
|
4292
|
+
if (table) query.andWhere({ TABLE_NAME: table });
|
|
4293
|
+
return await query;
|
|
4294
|
+
}
|
|
4295
|
+
async columnInfo(table, column) {
|
|
4296
|
+
/**
|
|
4297
|
+
* NOTE: Keep in mind, this query is optimized for speed.
|
|
4298
|
+
*/
|
|
4299
|
+
const query = this.knex.with("uc", this.knex.raw(`
|
|
4300
|
+
SELECT /*+ MATERIALIZE */
|
|
4301
|
+
"uc"."TABLE_NAME",
|
|
4302
|
+
"ucc"."COLUMN_NAME",
|
|
4303
|
+
"uc"."CONSTRAINT_NAME",
|
|
4304
|
+
"uc"."CONSTRAINT_TYPE",
|
|
4305
|
+
"uc"."R_CONSTRAINT_NAME",
|
|
4306
|
+
COUNT(*) OVER(
|
|
4307
|
+
PARTITION BY
|
|
4308
|
+
"uc"."CONSTRAINT_NAME"
|
|
4309
|
+
) "CONSTRAINT_COUNT",
|
|
4310
|
+
ROW_NUMBER() OVER(
|
|
4311
|
+
PARTITION BY
|
|
4312
|
+
"uc"."TABLE_NAME",
|
|
4313
|
+
"ucc"."COLUMN_NAME"
|
|
4314
|
+
ORDER BY
|
|
4315
|
+
"uc"."CONSTRAINT_TYPE"
|
|
4316
|
+
) "CONSTRAINT_PRIORITY"
|
|
4317
|
+
FROM "USER_CONSTRAINTS" "uc"
|
|
4318
|
+
INNER JOIN "USER_CONS_COLUMNS" "ucc"
|
|
4319
|
+
ON "uc"."CONSTRAINT_NAME" = "ucc"."CONSTRAINT_NAME"
|
|
4320
|
+
WHERE "uc"."CONSTRAINT_TYPE" IN ('P', 'U', 'R')
|
|
4321
|
+
`)).select(this.knex.raw(`
|
|
4322
|
+
/*+ OPTIMIZER_FEATURES_ENABLE('${OPTIMIZER_FEATURES}') */
|
|
4323
|
+
"c"."TABLE_NAME",
|
|
4324
|
+
"c"."COLUMN_NAME",
|
|
4325
|
+
"c"."DATA_DEFAULT",
|
|
4326
|
+
"c"."DATA_TYPE",
|
|
4327
|
+
"c"."DATA_LENGTH",
|
|
4328
|
+
"c"."DATA_PRECISION",
|
|
4329
|
+
"c"."DATA_SCALE",
|
|
4330
|
+
"c"."NULLABLE",
|
|
4331
|
+
"c"."IDENTITY_COLUMN",
|
|
4332
|
+
"c"."VIRTUAL_COLUMN",
|
|
4333
|
+
"cm"."COMMENTS" "COLUMN_COMMENT",
|
|
4334
|
+
"ct"."CONSTRAINT_TYPE",
|
|
4335
|
+
"fk"."TABLE_NAME" "REFERENCED_TABLE_NAME",
|
|
4336
|
+
"fk"."COLUMN_NAME" "REFERENCED_COLUMN_NAME"
|
|
4337
|
+
FROM "USER_TAB_COLS" "c"
|
|
4338
|
+
LEFT JOIN "USER_COL_COMMENTS" "cm"
|
|
4339
|
+
ON "c"."TABLE_NAME" = "cm"."TABLE_NAME"
|
|
4340
|
+
AND "c"."COLUMN_NAME" = "cm"."COLUMN_NAME"
|
|
4341
|
+
LEFT JOIN "uc" "ct"
|
|
4342
|
+
ON "c"."TABLE_NAME" = "ct"."TABLE_NAME"
|
|
4343
|
+
AND "c"."COLUMN_NAME" = "ct"."COLUMN_NAME"
|
|
4344
|
+
AND "ct"."CONSTRAINT_COUNT" = 1
|
|
4345
|
+
AND "ct"."CONSTRAINT_PRIORITY" = 1
|
|
4346
|
+
LEFT JOIN "uc" "fk"
|
|
4347
|
+
ON "ct"."R_CONSTRAINT_NAME" = "fk"."CONSTRAINT_NAME"
|
|
4348
|
+
`)).where({ "c.HIDDEN_COLUMN": "NO" });
|
|
4349
|
+
if (table) query.andWhere({ "c.TABLE_NAME": table });
|
|
4350
|
+
if (column) {
|
|
4351
|
+
const rawColumn = await query.andWhere({ "c.COLUMN_NAME": column }).first();
|
|
4352
|
+
return rawColumnToColumn(rawColumn);
|
|
4353
|
+
}
|
|
4354
|
+
return (await query).map(rawColumnToColumn);
|
|
4355
|
+
}
|
|
4356
|
+
/**
|
|
4357
|
+
* Check if a table exists in the current schema/database
|
|
4358
|
+
*/
|
|
4359
|
+
async hasColumn(table, column) {
|
|
4360
|
+
const result = await this.knex.select(this.knex.raw(`
|
|
4361
|
+
/*+ OPTIMIZER_FEATURES_ENABLE('${OPTIMIZER_FEATURES}') NO_QUERY_TRANSFORMATION */
|
|
4362
|
+
COUNT(*) "count"
|
|
4363
|
+
`)).from("USER_TAB_COLS").where({
|
|
4364
|
+
TABLE_NAME: table,
|
|
4365
|
+
COLUMN_NAME: column,
|
|
4366
|
+
HIDDEN_COLUMN: "NO"
|
|
4367
|
+
}).first();
|
|
4368
|
+
return !!(result === null || result === void 0 ? void 0 : result.count);
|
|
4369
|
+
}
|
|
4370
|
+
/**
|
|
4371
|
+
* Get the primary key column for the given table
|
|
4372
|
+
*/
|
|
4373
|
+
async primary(table) {
|
|
4374
|
+
/**
|
|
4375
|
+
* NOTE: Keep in mind, this query is optimized for speed.
|
|
4376
|
+
*/
|
|
4377
|
+
const result = await this.knex.with("uc", this.knex.select(this.knex.raw("/*+ MATERIALIZE */ \"CONSTRAINT_NAME\"")).from("USER_CONSTRAINTS").where({
|
|
4378
|
+
TABLE_NAME: table,
|
|
4379
|
+
CONSTRAINT_TYPE: "P"
|
|
4380
|
+
})).select(this.knex.raw(`
|
|
4381
|
+
/*+ OPTIMIZER_FEATURES_ENABLE('${OPTIMIZER_FEATURES}') */
|
|
4382
|
+
"ucc"."COLUMN_NAME"
|
|
4383
|
+
FROM "USER_CONS_COLUMNS" "ucc"
|
|
4384
|
+
INNER JOIN "uc" "pk"
|
|
4385
|
+
ON "ucc"."CONSTRAINT_NAME" = "pk"."CONSTRAINT_NAME"
|
|
4386
|
+
`));
|
|
4387
|
+
return result.length > 0 ? result.length === 1 ? result[0].COLUMN_NAME : result.map((r) => r.COLUMN_NAME) : null;
|
|
4388
|
+
}
|
|
4389
|
+
async foreignKeys(table) {
|
|
4390
|
+
/**
|
|
4391
|
+
* NOTE: Keep in mind, this query is optimized for speed.
|
|
4392
|
+
*/
|
|
4393
|
+
const query = this.knex.with("ucc", this.knex.raw(`
|
|
4394
|
+
SELECT /*+ MATERIALIZE */
|
|
4395
|
+
"TABLE_NAME",
|
|
4396
|
+
"COLUMN_NAME",
|
|
4397
|
+
"CONSTRAINT_NAME"
|
|
4398
|
+
FROM "USER_CONS_COLUMNS"
|
|
4399
|
+
`)).select(this.knex.raw(`
|
|
4400
|
+
/*+ OPTIMIZER_FEATURES_ENABLE('${OPTIMIZER_FEATURES}') */
|
|
4401
|
+
"uc"."TABLE_NAME" "table",
|
|
4402
|
+
"fcc"."COLUMN_NAME" "column",
|
|
4403
|
+
"rcc"."TABLE_NAME" AS "foreign_key_table",
|
|
4404
|
+
"rcc"."COLUMN_NAME" AS "foreign_key_column",
|
|
4405
|
+
"uc"."CONSTRAINT_NAME" "constraint_name",
|
|
4406
|
+
NULL as "on_update",
|
|
4407
|
+
"uc"."DELETE_RULE" "on_delete"
|
|
4408
|
+
FROM "USER_CONSTRAINTS" "uc"
|
|
4409
|
+
INNER JOIN "ucc" "fcc"
|
|
4410
|
+
ON "uc"."CONSTRAINT_NAME" = "fcc"."CONSTRAINT_NAME"
|
|
4411
|
+
INNER JOIN "ucc" "rcc"
|
|
4412
|
+
ON "uc"."R_CONSTRAINT_NAME" = "rcc"."CONSTRAINT_NAME"
|
|
4413
|
+
`)).where({ "uc.CONSTRAINT_TYPE": "R" });
|
|
4414
|
+
if (table) query.andWhere({ "uc.TABLE_NAME": table });
|
|
4415
|
+
return await query;
|
|
4416
|
+
}
|
|
4417
|
+
};
|
|
4418
|
+
|
|
4419
|
+
//#endregion
|
|
4420
|
+
//#region src/inspector/dialects/postgres.ts
|
|
4421
|
+
/**
|
|
4422
|
+
* Converts Postgres default value to JS
|
|
4423
|
+
* Eg `'example'::character varying` => `example`
|
|
4424
|
+
*/
|
|
4425
|
+
function parseDefaultValue$1(value) {
|
|
4426
|
+
if (value === null) return null;
|
|
4427
|
+
if (value.startsWith("nextval(")) return value;
|
|
4428
|
+
value = value.split("::")[0];
|
|
4429
|
+
if (value.trim().toLowerCase() === "null") return null;
|
|
4430
|
+
return stripQuotes(value);
|
|
4431
|
+
}
|
|
4432
|
+
var Postgres = class {
|
|
4433
|
+
knex;
|
|
4434
|
+
schema;
|
|
4435
|
+
explodedSchema;
|
|
4436
|
+
constructor(knex) {
|
|
4437
|
+
this.knex = knex;
|
|
4438
|
+
const config = knex.client.config;
|
|
4439
|
+
if (!config.searchPath) {
|
|
4440
|
+
this.schema = "public";
|
|
4441
|
+
this.explodedSchema = [this.schema];
|
|
4442
|
+
} else if (typeof config.searchPath === "string") {
|
|
4443
|
+
this.schema = config.searchPath;
|
|
4444
|
+
this.explodedSchema = [config.searchPath];
|
|
4445
|
+
} else {
|
|
4446
|
+
this.schema = config.searchPath[0];
|
|
4447
|
+
this.explodedSchema = config.searchPath;
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
/**
|
|
4451
|
+
* Set the schema to be used in other methods
|
|
4452
|
+
*/
|
|
4453
|
+
withSchema(schema) {
|
|
4454
|
+
this.schema = schema;
|
|
4455
|
+
this.explodedSchema = [this.schema];
|
|
4456
|
+
return this;
|
|
4457
|
+
}
|
|
4458
|
+
/**
|
|
4459
|
+
* List all existing tables in the current schema/database
|
|
4460
|
+
*/
|
|
4461
|
+
async tables() {
|
|
4462
|
+
const schemaIn = this.explodedSchema.map((schemaName) => `${this.knex.raw("?", [schemaName])}::regnamespace`);
|
|
4463
|
+
return (await this.knex.raw(`
|
|
4464
|
+
SELECT
|
|
4465
|
+
rel.relname AS name
|
|
4466
|
+
FROM
|
|
4467
|
+
pg_class rel
|
|
4468
|
+
WHERE
|
|
4469
|
+
rel.relnamespace IN (${schemaIn})
|
|
4470
|
+
AND rel.relkind = 'r'
|
|
4471
|
+
ORDER BY rel.relname
|
|
4472
|
+
`)).rows.map((row) => row.name);
|
|
4473
|
+
}
|
|
4474
|
+
async tableInfo(table) {
|
|
4475
|
+
const schemaIn = this.explodedSchema.map((schemaName) => `${this.knex.raw("?", [schemaName])}::regnamespace`);
|
|
4476
|
+
const bindings = [];
|
|
4477
|
+
if (table) bindings.push(table);
|
|
4478
|
+
const result = await this.knex.raw(`
|
|
4479
|
+
SELECT
|
|
4480
|
+
rel.relnamespace::regnamespace::text AS schema,
|
|
4481
|
+
rel.relname AS name,
|
|
4482
|
+
des.description AS comment
|
|
4483
|
+
FROM
|
|
4484
|
+
pg_class rel
|
|
4485
|
+
LEFT JOIN pg_description des ON rel.oid = des.objoid AND des.objsubid = 0
|
|
4486
|
+
WHERE
|
|
4487
|
+
rel.relnamespace IN (${schemaIn})
|
|
4488
|
+
${table ? "AND rel.relname = ?" : ""}
|
|
4489
|
+
AND rel.relkind = 'r'
|
|
4490
|
+
ORDER BY rel.relname
|
|
4491
|
+
`, bindings);
|
|
4492
|
+
if (table) return result.rows[0];
|
|
4493
|
+
return result.rows;
|
|
4494
|
+
}
|
|
4495
|
+
/**
|
|
4496
|
+
* Check if a table exists in the current schema/database
|
|
4497
|
+
*/
|
|
4498
|
+
async hasTable(table) {
|
|
4499
|
+
const schemaIn = this.explodedSchema.map((schemaName) => `${this.knex.raw("?", [schemaName])}::regnamespace`);
|
|
4500
|
+
return (await this.knex.raw(`
|
|
4501
|
+
SELECT
|
|
4502
|
+
rel.relname AS name
|
|
4503
|
+
FROM
|
|
4504
|
+
pg_class rel
|
|
4505
|
+
WHERE
|
|
4506
|
+
rel.relnamespace IN (${schemaIn})
|
|
4507
|
+
AND rel.relkind = 'r'
|
|
4508
|
+
AND rel.relname = ?
|
|
4509
|
+
ORDER BY rel.relname
|
|
4510
|
+
`, [table])).rows.length > 0;
|
|
4511
|
+
}
|
|
4512
|
+
/**
|
|
4513
|
+
* Get all the available columns in the current schema/database. Can be filtered to a specific table
|
|
4514
|
+
*/
|
|
4515
|
+
async columns(table) {
|
|
4516
|
+
const bindings = [];
|
|
4517
|
+
if (table) bindings.push(table);
|
|
4518
|
+
const schemaIn = this.explodedSchema.map((schemaName) => `${this.knex.raw("?", [schemaName])}::regnamespace`);
|
|
4519
|
+
return (await this.knex.raw(`
|
|
4520
|
+
SELECT
|
|
4521
|
+
att.attname AS column,
|
|
4522
|
+
rel.relname AS table
|
|
4523
|
+
FROM
|
|
4524
|
+
pg_attribute att
|
|
4525
|
+
LEFT JOIN pg_class rel ON att.attrelid = rel.oid
|
|
4526
|
+
WHERE
|
|
4527
|
+
rel.relnamespace IN (${schemaIn})
|
|
4528
|
+
${table ? "AND rel.relname = ?" : ""}
|
|
4529
|
+
AND rel.relkind = 'r'
|
|
4530
|
+
AND att.attnum > 0
|
|
4531
|
+
AND NOT att.attisdropped;
|
|
4532
|
+
`, bindings)).rows;
|
|
4533
|
+
}
|
|
4534
|
+
async columnInfo(table, column) {
|
|
4535
|
+
var _versionResponse$rows;
|
|
4536
|
+
const { knex } = this;
|
|
4537
|
+
const bindings = [];
|
|
4538
|
+
if (table) bindings.push(table);
|
|
4539
|
+
if (column) bindings.push(column);
|
|
4540
|
+
const schemaIn = this.explodedSchema.map((schemaName) => `${this.knex.raw("?", [schemaName])}::regnamespace`);
|
|
4541
|
+
const majorVersion = ((_versionResponse$rows = (await this.knex.raw("SHOW server_version")).rows) === null || _versionResponse$rows === void 0 || (_versionResponse$rows = _versionResponse$rows[0]) === null || _versionResponse$rows === void 0 || (_versionResponse$rows = _versionResponse$rows.server_version) === null || _versionResponse$rows === void 0 || (_versionResponse$rows = _versionResponse$rows.split(".")) === null || _versionResponse$rows === void 0 ? void 0 : _versionResponse$rows[0]) ?? 10;
|
|
4542
|
+
let generationSelect = `
|
|
4543
|
+
NULL AS generation_expression,
|
|
4544
|
+
pg_get_expr(ad.adbin, ad.adrelid) AS default_value,
|
|
4545
|
+
FALSE AS is_generated,
|
|
4546
|
+
`;
|
|
4547
|
+
if (Number(majorVersion) >= 12) generationSelect = `
|
|
4548
|
+
CASE WHEN att.attgenerated = 's' THEN pg_get_expr(ad.adbin, ad.adrelid) ELSE null END AS generation_expression,
|
|
4549
|
+
CASE WHEN att.attgenerated = '' THEN pg_get_expr(ad.adbin, ad.adrelid) ELSE null END AS default_value,
|
|
4550
|
+
att.attgenerated = 's' AS is_generated,
|
|
4551
|
+
`;
|
|
4552
|
+
const [columns, constraints] = await Promise.all([knex.raw(`
|
|
4553
|
+
SELECT
|
|
4554
|
+
att.attname AS name,
|
|
4555
|
+
rel.relname AS table,
|
|
4556
|
+
rel.relnamespace::regnamespace::text as schema,
|
|
4557
|
+
att.atttypid::regtype::text AS data_type,
|
|
4558
|
+
NOT att.attnotnull AS is_nullable,
|
|
4559
|
+
${generationSelect}
|
|
4560
|
+
CASE
|
|
4561
|
+
WHEN att.atttypid IN (1042, 1043) THEN (att.atttypmod - 4)::int4
|
|
4562
|
+
WHEN att.atttypid IN (1560, 1562) THEN (att.atttypmod)::int4
|
|
4563
|
+
ELSE NULL
|
|
4564
|
+
END AS max_length,
|
|
4565
|
+
des.description AS comment,
|
|
4566
|
+
CASE att.atttypid
|
|
4567
|
+
WHEN 21 THEN 16
|
|
4568
|
+
WHEN 23 THEN 32
|
|
4569
|
+
WHEN 20 THEN 64
|
|
4570
|
+
WHEN 1700 THEN
|
|
4571
|
+
CASE WHEN atttypmod = -1 THEN NULL
|
|
4572
|
+
ELSE (((atttypmod - 4) >> 16) & 65535)::int4
|
|
4573
|
+
END
|
|
4574
|
+
WHEN 700 THEN 24
|
|
4575
|
+
WHEN 701 THEN 53
|
|
4576
|
+
ELSE NULL
|
|
4577
|
+
END AS numeric_precision,
|
|
4578
|
+
CASE
|
|
4579
|
+
WHEN atttypid IN (21, 23, 20) THEN 0
|
|
4580
|
+
WHEN atttypid = 1700 THEN
|
|
4581
|
+
CASE
|
|
4582
|
+
WHEN atttypmod = -1 THEN NULL
|
|
4583
|
+
ELSE ((atttypmod - 4) & 65535)::int4
|
|
4584
|
+
END
|
|
4585
|
+
ELSE null
|
|
4586
|
+
END AS numeric_scale
|
|
4587
|
+
FROM
|
|
4588
|
+
pg_attribute att
|
|
4589
|
+
LEFT JOIN pg_class rel ON att.attrelid = rel.oid
|
|
4590
|
+
LEFT JOIN pg_attrdef ad ON (att.attrelid, att.attnum) = (ad.adrelid, ad.adnum)
|
|
4591
|
+
LEFT JOIN pg_description des ON (att.attrelid, att.attnum) = (des.objoid, des.objsubid)
|
|
4592
|
+
WHERE
|
|
4593
|
+
rel.relnamespace IN (${schemaIn})
|
|
4594
|
+
${table ? "AND rel.relname = ?" : ""}
|
|
4595
|
+
${column ? "AND att.attname = ?" : ""}
|
|
4596
|
+
AND rel.relkind = 'r'
|
|
4597
|
+
AND att.attnum > 0
|
|
4598
|
+
AND NOT att.attisdropped
|
|
4599
|
+
ORDER BY rel.relname, att.attnum;
|
|
4600
|
+
`, bindings), knex.raw(`
|
|
4601
|
+
SELECT
|
|
4602
|
+
con.contype AS type,
|
|
4603
|
+
rel.relname AS table,
|
|
4604
|
+
att.attname AS column,
|
|
4605
|
+
frel.relnamespace::regnamespace::text AS foreign_key_schema,
|
|
4606
|
+
frel.relname AS foreign_key_table,
|
|
4607
|
+
fatt.attname AS foreign_key_column,
|
|
4608
|
+
CASE
|
|
4609
|
+
WHEN con.contype = 'p' THEN pg_get_serial_sequence(att.attrelid::regclass::text, att.attname) != ''
|
|
4610
|
+
ELSE NULL
|
|
4611
|
+
END AS has_auto_increment
|
|
4612
|
+
FROM
|
|
4613
|
+
pg_constraint con
|
|
4614
|
+
LEFT JOIN pg_class rel ON con.conrelid = rel.oid
|
|
4615
|
+
LEFT JOIN pg_class frel ON con.confrelid = frel.oid
|
|
4616
|
+
LEFT JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = con.conkey[1]
|
|
4617
|
+
LEFT JOIN pg_attribute fatt ON fatt.attrelid = con.confrelid AND fatt.attnum = con.confkey[1]
|
|
4618
|
+
WHERE con.connamespace IN (${schemaIn})
|
|
4619
|
+
AND array_length(con.conkey, 1) <= 1
|
|
4620
|
+
AND (con.confkey IS NULL OR array_length(con.confkey, 1) = 1)
|
|
4621
|
+
${table ? "AND rel.relname = ?" : ""}
|
|
4622
|
+
${column ? "AND att.attname = ?" : ""}
|
|
4623
|
+
`, bindings)]);
|
|
4624
|
+
const parsedColumms = columns.rows.map((col) => {
|
|
4625
|
+
const constraintsForColumn = constraints.rows.filter((constraint) => constraint.table === col.table && constraint.column === col.name);
|
|
4626
|
+
const foreignKeyConstraint = constraintsForColumn.find((constraint) => constraint.type === "f");
|
|
4627
|
+
return {
|
|
4628
|
+
...col,
|
|
4629
|
+
is_unique: constraintsForColumn.some((constraint) => ["u", "p"].includes(constraint.type)),
|
|
4630
|
+
is_primary_key: constraintsForColumn.some((constraint) => constraint.type === "p"),
|
|
4631
|
+
has_auto_increment: constraintsForColumn.some((constraint) => constraint.has_auto_increment),
|
|
4632
|
+
default_value: parseDefaultValue$1(col.default_value),
|
|
4633
|
+
foreign_key_schema: (foreignKeyConstraint === null || foreignKeyConstraint === void 0 ? void 0 : foreignKeyConstraint.foreign_key_schema) ?? null,
|
|
4634
|
+
foreign_key_table: (foreignKeyConstraint === null || foreignKeyConstraint === void 0 ? void 0 : foreignKeyConstraint.foreign_key_table) ?? null,
|
|
4635
|
+
foreign_key_column: (foreignKeyConstraint === null || foreignKeyConstraint === void 0 ? void 0 : foreignKeyConstraint.foreign_key_column) ?? null
|
|
4636
|
+
};
|
|
4637
|
+
});
|
|
4638
|
+
if (table && column) return parsedColumms[0];
|
|
4639
|
+
return parsedColumms;
|
|
4640
|
+
}
|
|
4641
|
+
/**
|
|
4642
|
+
* Check if the given table contains the given column
|
|
4643
|
+
*/
|
|
4644
|
+
async hasColumn(table, column) {
|
|
4645
|
+
const schemaIn = this.explodedSchema.map((schemaName) => `${this.knex.raw("?", [schemaName])}::regnamespace`);
|
|
4646
|
+
return (await this.knex.raw(`
|
|
4647
|
+
SELECT
|
|
4648
|
+
att.attname AS column,
|
|
4649
|
+
rel.relname AS table
|
|
4650
|
+
FROM
|
|
4651
|
+
pg_attribute att
|
|
4652
|
+
LEFT JOIN pg_class rel ON att.attrelid = rel.oid
|
|
4653
|
+
WHERE
|
|
4654
|
+
rel.relnamespace IN (${schemaIn})
|
|
4655
|
+
AND rel.relname = ?
|
|
4656
|
+
AND att.attname = ?
|
|
4657
|
+
AND rel.relkind = 'r'
|
|
4658
|
+
AND att.attnum > 0
|
|
4659
|
+
AND NOT att.attisdropped;
|
|
4660
|
+
`, [table, column])).rows;
|
|
4661
|
+
}
|
|
4662
|
+
/**
|
|
4663
|
+
* Get the primary key column for the given table
|
|
4664
|
+
*/
|
|
4665
|
+
async primary(table) {
|
|
4666
|
+
const schemaIn = this.explodedSchema.map((schemaName) => `${this.knex.raw("?", [schemaName])}::regnamespace`);
|
|
4667
|
+
const result = await this.knex.raw(`
|
|
4668
|
+
SELECT
|
|
4669
|
+
att.attname AS column
|
|
4670
|
+
FROM
|
|
4671
|
+
pg_constraint con
|
|
4672
|
+
LEFT JOIN pg_class rel ON con.conrelid = rel.oid
|
|
4673
|
+
LEFT JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = ANY(con.conkey)
|
|
4674
|
+
WHERE con.connamespace IN (${schemaIn})
|
|
4675
|
+
AND con.contype = 'p'
|
|
4676
|
+
AND rel.relname = ?
|
|
4677
|
+
`, [table]);
|
|
4678
|
+
return result.rows.length !== 0 ? result.rows.length === 1 ? result.rows[0].column : result.rows.map((r) => r.column) : null;
|
|
4679
|
+
}
|
|
4680
|
+
async foreignKeys(table) {
|
|
4681
|
+
const schemaIn = this.explodedSchema.map((schemaName) => `${this.knex.raw("?", [schemaName])}::regnamespace`);
|
|
4682
|
+
const bindings = [];
|
|
4683
|
+
if (table) bindings.push(table);
|
|
4684
|
+
return (await this.knex.raw(`
|
|
4685
|
+
SELECT
|
|
4686
|
+
con.conname AS constraint_name,
|
|
4687
|
+
rel.relname AS table,
|
|
4688
|
+
att.attname AS column,
|
|
4689
|
+
frel.relnamespace::regnamespace::text AS foreign_key_schema,
|
|
4690
|
+
frel.relname AS foreign_key_table,
|
|
4691
|
+
fatt.attname AS foreign_key_column,
|
|
4692
|
+
CASE con.confupdtype
|
|
4693
|
+
WHEN 'r' THEN
|
|
4694
|
+
'RESTRICT'
|
|
4695
|
+
WHEN 'c' THEN
|
|
4696
|
+
'CASCADE'
|
|
4697
|
+
WHEN 'n' THEN
|
|
4698
|
+
'SET NULL'
|
|
4699
|
+
WHEN 'd' THEN
|
|
4700
|
+
'SET DEFAULT'
|
|
4701
|
+
WHEN 'a' THEN
|
|
4702
|
+
'NO ACTION'
|
|
4703
|
+
ELSE
|
|
4704
|
+
NULL
|
|
4705
|
+
END AS on_update,
|
|
4706
|
+
CASE con.confdeltype
|
|
4707
|
+
WHEN 'r' THEN
|
|
4708
|
+
'RESTRICT'
|
|
4709
|
+
WHEN 'c' THEN
|
|
4710
|
+
'CASCADE'
|
|
4711
|
+
WHEN 'n' THEN
|
|
4712
|
+
'SET NULL'
|
|
4713
|
+
WHEN 'd' THEN
|
|
4714
|
+
'SET DEFAULT'
|
|
4715
|
+
WHEN 'a' THEN
|
|
4716
|
+
'NO ACTION'
|
|
4717
|
+
ELSE
|
|
4718
|
+
NULL
|
|
4719
|
+
END AS on_delete
|
|
4720
|
+
FROM
|
|
4721
|
+
pg_constraint con
|
|
4722
|
+
LEFT JOIN pg_class rel ON con.conrelid = rel.oid
|
|
4723
|
+
LEFT JOIN pg_class frel ON con.confrelid = frel.oid
|
|
4724
|
+
LEFT JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = con.conkey[1]
|
|
4725
|
+
LEFT JOIN pg_attribute fatt ON fatt.attrelid = con.confrelid AND fatt.attnum = con.confkey[1]
|
|
4726
|
+
WHERE con.connamespace IN (${schemaIn})
|
|
4727
|
+
AND array_length(con.conkey, 1) <= 1
|
|
4728
|
+
AND (con.confkey IS NULL OR array_length(con.confkey, 1) = 1)
|
|
4729
|
+
AND con.contype = 'f'
|
|
4730
|
+
${table ? "AND rel.relname = ?" : ""}
|
|
4731
|
+
`, bindings)).rows;
|
|
4732
|
+
}
|
|
4733
|
+
async uniqueConstraints(table) {
|
|
4734
|
+
const { knex } = this;
|
|
4735
|
+
const schemaIn = this.explodedSchema.map((schemaName) => `${this.knex.raw("?", [schemaName])}::regnamespace`);
|
|
4736
|
+
const bindings = [];
|
|
4737
|
+
if (table) bindings.push(table);
|
|
4738
|
+
return (await knex.raw(`
|
|
4739
|
+
SELECT
|
|
4740
|
+
con.conrelid::regclass AS table_name,
|
|
4741
|
+
con.conname AS constraint_name,
|
|
4742
|
+
array_agg(a.attname ORDER BY k.n) AS columns
|
|
4743
|
+
FROM
|
|
4744
|
+
pg_constraint AS con
|
|
4745
|
+
CROSS JOIN LATERAL unnest(con.conkey) WITH ORDINALITY AS k(con,n)
|
|
4746
|
+
LEFT JOIN pg_class rel ON con.conrelid = rel.oid
|
|
4747
|
+
JOIN pg_attribute AS a ON a.attnum = k.con AND a.attrelid = con.conrelid
|
|
4748
|
+
WHERE con.contype = 'u'
|
|
4749
|
+
AND con.connamespace IN (${schemaIn})
|
|
4750
|
+
${table ? "AND rel.relname = ?" : ""}
|
|
4751
|
+
GROUP BY con.oid, con.conrelid, con.conname;
|
|
4752
|
+
`, bindings)).rows.map((v) => {
|
|
4753
|
+
const columns = Array.isArray(v.columns) ? v.columns : v.columns.substring(1, v.columns.length - 1).split(",");
|
|
4754
|
+
return {
|
|
4755
|
+
table: v.table_name,
|
|
4756
|
+
constraint_name: v.constraint_name,
|
|
4757
|
+
columns
|
|
4758
|
+
};
|
|
4759
|
+
});
|
|
4760
|
+
}
|
|
4761
|
+
};
|
|
4762
|
+
|
|
4763
|
+
//#endregion
|
|
4764
|
+
//#region src/inspector/utils/extract-max-length.ts
|
|
4765
|
+
/**
|
|
4766
|
+
* Extracts the length value out of a given datatype
|
|
4767
|
+
* For example: `varchar(32)` => 32
|
|
4768
|
+
*/
|
|
4769
|
+
function extractMaxLength(type) {
|
|
4770
|
+
const matches = /\(([^)]+)\)/.exec(type);
|
|
4771
|
+
if (matches && matches.length > 0 && matches[1]) return Number(matches[1]);
|
|
4772
|
+
return null;
|
|
4773
|
+
}
|
|
4774
|
+
|
|
4775
|
+
//#endregion
|
|
4776
|
+
//#region src/inspector/utils/extract-type.ts
|
|
4777
|
+
/**
|
|
4778
|
+
* Extracts the type out of a given datatype
|
|
4779
|
+
* For example: `varchar(32)` => varchar
|
|
4780
|
+
*/
|
|
4781
|
+
function extractType(type) {
|
|
4782
|
+
return type.replace(/[^a-zA-Z]/g, "").toLowerCase();
|
|
4783
|
+
}
|
|
4784
|
+
|
|
4785
|
+
//#endregion
|
|
4786
|
+
//#region src/inspector/dialects/sqlite.ts
|
|
4787
|
+
function parseDefaultValue(value) {
|
|
4788
|
+
if (value === null || value.trim().toLowerCase() === "null") return null;
|
|
4789
|
+
return stripQuotes(value);
|
|
4790
|
+
}
|
|
4791
|
+
var SQLite = class {
|
|
4792
|
+
knex;
|
|
4793
|
+
constructor(knex) {
|
|
4794
|
+
this.knex = knex;
|
|
4795
|
+
}
|
|
4796
|
+
/**
|
|
4797
|
+
* List all existing tables in the current schema/database
|
|
4798
|
+
*/
|
|
4799
|
+
async tables() {
|
|
4800
|
+
return (await this.knex.select("name").from("sqlite_master").whereRaw("type = 'table' AND name NOT LIKE 'sqlite_%'")).map(({ name }) => name);
|
|
4801
|
+
}
|
|
4802
|
+
async tableInfo(table) {
|
|
4803
|
+
const query = this.knex.select("name", "sql").from("sqlite_master").where({ type: "table" }).andWhereRaw("name NOT LIKE 'sqlite_%'");
|
|
4804
|
+
if (table) query.andWhere({ name: table });
|
|
4805
|
+
let records = await query;
|
|
4806
|
+
records = records.map((table$1) => ({
|
|
4807
|
+
name: table$1.name,
|
|
4808
|
+
sql: table$1.sql
|
|
4809
|
+
}));
|
|
4810
|
+
if (table) return records[0];
|
|
4811
|
+
return records;
|
|
4812
|
+
}
|
|
4813
|
+
/**
|
|
4814
|
+
* Check if a table exists in the current schema/database
|
|
4815
|
+
*/
|
|
4816
|
+
async hasTable(table) {
|
|
4817
|
+
return (await this.knex.select(1).from("sqlite_master").where({
|
|
4818
|
+
type: "table",
|
|
4819
|
+
name: table
|
|
4820
|
+
})).length > 0;
|
|
4821
|
+
}
|
|
4822
|
+
/**
|
|
4823
|
+
* Get all the available columns in the current schema/database. Can be filtered to a specific table
|
|
4824
|
+
*/
|
|
4825
|
+
async columns(table) {
|
|
4826
|
+
if (table) return (await this.knex.raw("PRAGMA table_xinfo(??)", table)).map((column) => ({
|
|
4827
|
+
table,
|
|
4828
|
+
column: column.name
|
|
4829
|
+
}));
|
|
4830
|
+
const tables = await this.tables();
|
|
4831
|
+
const columnsPerTable = await Promise.all(tables.map(async (table$1) => await this.columns(table$1)));
|
|
4832
|
+
return flatten(columnsPerTable);
|
|
4833
|
+
}
|
|
4834
|
+
async columnInfo(table, column) {
|
|
4835
|
+
const getColumnsForTable = async (table$1) => {
|
|
4836
|
+
const tablesWithAutoIncrementPrimaryKeys = (await this.knex.select("name").from("sqlite_master").whereRaw("sql LIKE '%AUTOINCREMENT%'")).map(({ name }) => name);
|
|
4837
|
+
const columns = await this.knex.raw("PRAGMA table_xinfo(??)", table$1);
|
|
4838
|
+
const foreignKeys = await this.knex.raw("PRAGMA foreign_key_list(??)", table$1);
|
|
4839
|
+
const indexList = await this.knex.raw("PRAGMA index_list(??)", table$1);
|
|
4840
|
+
const indexInfoList = await Promise.all(indexList.map((index) => this.knex.raw("PRAGMA index_info(??)", index.name)));
|
|
4841
|
+
return columns.map((raw) => {
|
|
4842
|
+
const foreignKey = foreignKeys.find((fk) => fk.from === raw.name);
|
|
4843
|
+
const indexIndex = indexInfoList.findIndex((list) => list.find((fk) => fk.name === raw.name));
|
|
4844
|
+
const index = indexList[indexIndex];
|
|
4845
|
+
const indexInfo = indexInfoList[indexIndex];
|
|
4846
|
+
return {
|
|
4847
|
+
name: raw.name,
|
|
4848
|
+
table: table$1,
|
|
4849
|
+
data_type: extractType(raw.type),
|
|
4850
|
+
default_value: parseDefaultValue(raw.dflt_value),
|
|
4851
|
+
max_length: extractMaxLength(raw.type),
|
|
4852
|
+
numeric_precision: null,
|
|
4853
|
+
numeric_scale: null,
|
|
4854
|
+
is_generated: raw.hidden !== 0,
|
|
4855
|
+
generation_expression: null,
|
|
4856
|
+
is_nullable: raw.notnull === 0,
|
|
4857
|
+
is_unique: !!(index === null || index === void 0 ? void 0 : index.unique) && (indexInfo === null || indexInfo === void 0 ? void 0 : indexInfo.length) === 1,
|
|
4858
|
+
is_primary_key: raw.pk === 1,
|
|
4859
|
+
has_auto_increment: raw.pk === 1 && tablesWithAutoIncrementPrimaryKeys.includes(table$1),
|
|
4860
|
+
foreign_key_column: (foreignKey === null || foreignKey === void 0 ? void 0 : foreignKey.to) || null,
|
|
4861
|
+
foreign_key_table: (foreignKey === null || foreignKey === void 0 ? void 0 : foreignKey.table) || null
|
|
4862
|
+
};
|
|
4863
|
+
});
|
|
4864
|
+
};
|
|
4865
|
+
if (!table) {
|
|
4866
|
+
const tables = await this.tables();
|
|
4867
|
+
const columnsPerTable = await Promise.all(tables.map(async (table$1) => await getColumnsForTable(table$1)));
|
|
4868
|
+
return flatten(columnsPerTable);
|
|
4869
|
+
}
|
|
4870
|
+
if (table && !column) return await getColumnsForTable(table);
|
|
4871
|
+
return (await getColumnsForTable(table)).find((columnInfo) => columnInfo.name === column);
|
|
4872
|
+
}
|
|
4873
|
+
/**
|
|
4874
|
+
* Check if a table exists in the current schema/database
|
|
4875
|
+
*/
|
|
4876
|
+
async hasColumn(table, column) {
|
|
4877
|
+
let isColumn = false;
|
|
4878
|
+
if ((await this.knex.raw(`SELECT COUNT(*) AS ct FROM pragma_table_xinfo('${table}') WHERE name='${column}'`))[0]["ct"] !== 0) isColumn = true;
|
|
4879
|
+
return isColumn;
|
|
4880
|
+
}
|
|
4881
|
+
/**
|
|
4882
|
+
* Get the primary key column for the given table
|
|
4883
|
+
*/
|
|
4884
|
+
async primary(table) {
|
|
4885
|
+
const pkColumns = (await this.knex.raw("PRAGMA table_xinfo(??)", table)).filter((col) => col.pk !== 0);
|
|
4886
|
+
return pkColumns.length > 0 ? pkColumns.length === 1 ? pkColumns[0].name : pkColumns.map((col) => col.name) : null;
|
|
4887
|
+
}
|
|
4888
|
+
async foreignKeys(table) {
|
|
4889
|
+
if (table) return (await this.knex.raw("PRAGMA foreign_key_list(??)", table)).map((key) => ({
|
|
4890
|
+
table,
|
|
4891
|
+
column: key.from,
|
|
4892
|
+
foreign_key_table: key.table,
|
|
4893
|
+
foreign_key_column: key.to,
|
|
4894
|
+
on_update: key.on_update,
|
|
4895
|
+
on_delete: key.on_delete,
|
|
4896
|
+
constraint_name: null
|
|
4897
|
+
}));
|
|
4898
|
+
const tables = await this.tables();
|
|
4899
|
+
const keysPerTable = await Promise.all(tables.map(async (table$1) => await this.foreignKeys(table$1)));
|
|
4900
|
+
return flatten(keysPerTable);
|
|
4901
|
+
}
|
|
4902
|
+
async uniqueConstraints(table) {
|
|
4903
|
+
if (table) {
|
|
4904
|
+
const indexList = await this.knex.raw("PRAGMA index_list(??)", table);
|
|
4905
|
+
const indexInfoList = await Promise.all(indexList.map((index) => this.knex.raw("PRAGMA index_info(??)", index.name)));
|
|
4906
|
+
return indexList.filter((i) => i.unique).map((index, i) => {
|
|
4907
|
+
const info = indexInfoList[i];
|
|
4908
|
+
return {
|
|
4909
|
+
table,
|
|
4910
|
+
constraint_name: index.name,
|
|
4911
|
+
columns: info.map((c) => c.name)
|
|
4912
|
+
};
|
|
4913
|
+
});
|
|
4914
|
+
}
|
|
4915
|
+
const tables = await this.tables();
|
|
4916
|
+
const constraintsPerTable = await Promise.all(tables.map(async (table$1) => await this.uniqueConstraints(table$1)));
|
|
4917
|
+
return flatten(constraintsPerTable);
|
|
4918
|
+
}
|
|
4919
|
+
};
|
|
4920
|
+
|
|
4921
|
+
//#endregion
|
|
4922
|
+
//#region src/inspector/index.ts
|
|
4923
|
+
var SchemaInspector = class {
|
|
4924
|
+
static inspect(knex) {
|
|
4925
|
+
let constructor;
|
|
4926
|
+
switch (knex.client.constructor.name) {
|
|
4927
|
+
case "Client_MySQL":
|
|
4928
|
+
case "Client_MySQL2":
|
|
4929
|
+
constructor = MySQL;
|
|
4930
|
+
break;
|
|
4931
|
+
case "Client_PG":
|
|
4932
|
+
constructor = Postgres;
|
|
4933
|
+
break;
|
|
4934
|
+
case "Client_CockroachDB":
|
|
4935
|
+
constructor = CockroachDB;
|
|
4936
|
+
break;
|
|
4937
|
+
case "Client_SQLite3":
|
|
4938
|
+
case "Client_BetterSQLite3":
|
|
4939
|
+
constructor = SQLite;
|
|
4940
|
+
break;
|
|
4941
|
+
case "Client_Oracledb":
|
|
4942
|
+
case "Client_Oracle":
|
|
4943
|
+
constructor = oracleDB;
|
|
4944
|
+
break;
|
|
4945
|
+
case "Client_MSSQL":
|
|
4946
|
+
constructor = MSSQL;
|
|
4947
|
+
break;
|
|
4948
|
+
default: throw Error("Unsupported driver used: " + knex.client.constructor.name);
|
|
4949
|
+
}
|
|
4950
|
+
return new constructor(knex);
|
|
4951
|
+
}
|
|
4952
|
+
};
|
|
4953
|
+
|
|
3536
4954
|
//#endregion
|
|
3537
4955
|
//#region src/migrations/migrator.ts
|
|
3538
4956
|
async function glob(folderPath) {
|
|
@@ -3574,14 +4992,14 @@ var Migrator = class {
|
|
|
3574
4992
|
return Object.values(files).filter((file) => !ran.includes(this.getMigrationName(file)));
|
|
3575
4993
|
}
|
|
3576
4994
|
async runPending(migrations, options = {}) {
|
|
3577
|
-
if (migrations.length === 0) {
|
|
3578
|
-
|
|
4995
|
+
if (migrations.length === 0 && !options.quiet) {
|
|
4996
|
+
Logger.info("INFO: Nothing to migrate.");
|
|
3579
4997
|
return;
|
|
3580
4998
|
}
|
|
3581
4999
|
let batch = await this.repository.getNextBatchNumber();
|
|
3582
5000
|
const pretend = options.pretend || false;
|
|
3583
5001
|
const step = options.step || false;
|
|
3584
|
-
|
|
5002
|
+
Logger.info("INFO: Running migrations...");
|
|
3585
5003
|
for (const file of migrations) {
|
|
3586
5004
|
await this.runUp(file, batch, pretend);
|
|
3587
5005
|
if (step) batch++;
|
|
@@ -3590,19 +5008,19 @@ var Migrator = class {
|
|
|
3590
5008
|
async runUp(file, batch, _pretend) {
|
|
3591
5009
|
const migration = await this.resolvePath(file);
|
|
3592
5010
|
const name = this.getMigrationName(file);
|
|
3593
|
-
await this.
|
|
5011
|
+
await this.taskRunner(name, () => this.runMigration(migration, "up"));
|
|
3594
5012
|
await this.repository.log(name, batch);
|
|
3595
5013
|
}
|
|
3596
5014
|
async runDown(file, migration, _pretend) {
|
|
3597
5015
|
const instance = await this.resolvePath(file);
|
|
3598
5016
|
const name = this.getMigrationName(file);
|
|
3599
|
-
await this.
|
|
5017
|
+
await this.taskRunner(name, () => this.runMigration(instance, "down"));
|
|
3600
5018
|
await this.repository.delete(migration);
|
|
3601
5019
|
}
|
|
3602
5020
|
async rollback(paths = [], options = {}) {
|
|
3603
5021
|
const migrations = await this.getMigrationsForRollback(options);
|
|
3604
5022
|
if (migrations.length === 0) {
|
|
3605
|
-
|
|
5023
|
+
Logger.info("INFO: Nothing to rollback");
|
|
3606
5024
|
return [];
|
|
3607
5025
|
}
|
|
3608
5026
|
return await this.rollbackMigrations(migrations, paths, options);
|
|
@@ -3615,7 +5033,7 @@ var Migrator = class {
|
|
|
3615
5033
|
async rollbackMigrations(migrations, paths, options) {
|
|
3616
5034
|
const rolledBack = [];
|
|
3617
5035
|
const files = await this.getMigrationFiles(paths);
|
|
3618
|
-
|
|
5036
|
+
Logger.info("INFO: Rolling back migrations...");
|
|
3619
5037
|
for (const migration of migrations) {
|
|
3620
5038
|
const file = files[migration.migration];
|
|
3621
5039
|
if (!file) {
|
|
@@ -3627,11 +5045,35 @@ var Migrator = class {
|
|
|
3627
5045
|
}
|
|
3628
5046
|
return rolledBack;
|
|
3629
5047
|
}
|
|
3630
|
-
reset(
|
|
3631
|
-
this.repository.getRan().then((r) => r.reverse());
|
|
3632
|
-
|
|
5048
|
+
async reset(paths = [], options, pretend = false) {
|
|
5049
|
+
const migrations = await this.repository.getRan().then((r) => r.map((e) => ({ migration: e })).reverse());
|
|
5050
|
+
if (migrations.length === 0) {
|
|
5051
|
+
if (!options.quiet) Logger.info("INFO: Nothing to reset.");
|
|
5052
|
+
return [];
|
|
5053
|
+
}
|
|
5054
|
+
return this.resetMigrations(migrations, paths, pretend);
|
|
3633
5055
|
}
|
|
3634
|
-
|
|
5056
|
+
/**
|
|
5057
|
+
* Drop all tables and re-run all migrations
|
|
5058
|
+
*
|
|
5059
|
+
* @param paths
|
|
5060
|
+
* @param options
|
|
5061
|
+
*/
|
|
5062
|
+
async fresh(paths, options) {
|
|
5063
|
+
/** Initialise connections */
|
|
5064
|
+
const connection = this.repository.getConnection().connector;
|
|
5065
|
+
const inspector = SchemaInspector.inspect(connection);
|
|
5066
|
+
await connection.raw("SET foreign_key_checks = 0");
|
|
5067
|
+
/** Drop all existing tables */
|
|
5068
|
+
for (const table of await inspector.tables()) this.taskRunner(`Dropping ${Logger.parse([[table, "grey"]], "", false)} table`, () => connection.schema.dropTableIfExists(table));
|
|
5069
|
+
await connection.raw("SET foreign_key_checks = 1");
|
|
5070
|
+
/** Create the migration repository */
|
|
5071
|
+
await this.repository.createRepository();
|
|
5072
|
+
console.log();
|
|
5073
|
+
/** Run fresh migrations */
|
|
5074
|
+
await this.run(paths, options);
|
|
5075
|
+
}
|
|
5076
|
+
async resetMigrations(migrations, paths, pretend = false) {
|
|
3635
5077
|
return this.rollbackMigrations(migrations, paths, { pretend });
|
|
3636
5078
|
}
|
|
3637
5079
|
async runMigration(migration, method) {
|
|
@@ -3682,7 +5124,7 @@ var Migrator = class {
|
|
|
3682
5124
|
return this.connection;
|
|
3683
5125
|
}
|
|
3684
5126
|
resolveConnection(connection) {
|
|
3685
|
-
return this.resolver.
|
|
5127
|
+
return this.resolver.fire(connection || this.connection);
|
|
3686
5128
|
}
|
|
3687
5129
|
getRepository() {
|
|
3688
5130
|
return this.repository;
|
|
@@ -3704,11 +5146,11 @@ var Migrator = class {
|
|
|
3704
5146
|
write(...args) {
|
|
3705
5147
|
if (this.output) console.log(...args);
|
|
3706
5148
|
}
|
|
3707
|
-
async
|
|
5149
|
+
async taskRunner(description, task) {
|
|
3708
5150
|
const startTime = process.hrtime();
|
|
3709
5151
|
let result = false;
|
|
3710
5152
|
try {
|
|
3711
|
-
result = await (task || (() => true))();
|
|
5153
|
+
result = await Promise.all([(task || (() => true))()].flat());
|
|
3712
5154
|
} finally {
|
|
3713
5155
|
const endTime = process.hrtime(startTime);
|
|
3714
5156
|
const duration = (endTime[0] * 1e9 + endTime[1]) / 1e6;
|
|
@@ -3815,6 +5257,49 @@ var Migrate = class {
|
|
|
3815
5257
|
if (destroyAll) await arquebus$1.destroyAll();
|
|
3816
5258
|
}
|
|
3817
5259
|
/**
|
|
5260
|
+
* Rollback all database migrations
|
|
5261
|
+
*
|
|
5262
|
+
* @param config
|
|
5263
|
+
* @param options
|
|
5264
|
+
* @param destroyAll
|
|
5265
|
+
*/
|
|
5266
|
+
async reset(config, options = {}, destroyAll = false) {
|
|
5267
|
+
const { arquebus: arquebus$1, migrator } = await this.setupConnection(config);
|
|
5268
|
+
const paths = await Utils.getMigrationPaths(this.basePath ?? process.cwd(), migrator, config.migrations.path, options.path);
|
|
5269
|
+
await migrator.setOutput(true).reset(paths, {
|
|
5270
|
+
step: options.step || 0,
|
|
5271
|
+
pretend: options.pretend,
|
|
5272
|
+
batch: options.batch || 0,
|
|
5273
|
+
quiet: options.quiet || false
|
|
5274
|
+
});
|
|
5275
|
+
if (destroyAll) await arquebus$1.destroyAll();
|
|
5276
|
+
}
|
|
5277
|
+
/**
|
|
5278
|
+
* Reset and re-run all migrations
|
|
5279
|
+
*
|
|
5280
|
+
* @param config
|
|
5281
|
+
* @param options
|
|
5282
|
+
* @param destroyAll
|
|
5283
|
+
*/
|
|
5284
|
+
async refresh(config, options = {}, destroyAll = false) {
|
|
5285
|
+
await this.reset(config, Object.assign({}, options, { quiet: true }), false);
|
|
5286
|
+
console.log("");
|
|
5287
|
+
await this.run(config, options, destroyAll);
|
|
5288
|
+
}
|
|
5289
|
+
/**
|
|
5290
|
+
* Drop all tables and re-run all migrations
|
|
5291
|
+
*
|
|
5292
|
+
* @param config
|
|
5293
|
+
* @param options
|
|
5294
|
+
* @param destroyAll
|
|
5295
|
+
*/
|
|
5296
|
+
async fresh(config, options = {}, destroyAll = false) {
|
|
5297
|
+
const { arquebus: arquebus$1, migrator } = await this.setupConnection(config);
|
|
5298
|
+
const paths = await Utils.getMigrationPaths(this.basePath ?? process.cwd(), migrator, config.migrations.path, options.path);
|
|
5299
|
+
await migrator.setOutput(true).fresh(paths, { pretend: options.pretend });
|
|
5300
|
+
if (destroyAll) await arquebus$1.destroyAll();
|
|
5301
|
+
}
|
|
5302
|
+
/**
|
|
3818
5303
|
* Prepares the database for migration
|
|
3819
5304
|
*
|
|
3820
5305
|
* @param migrator
|
|
@@ -4072,4 +5557,4 @@ const makeCollection = (model, data) => new collection_default(data.map((item) =
|
|
|
4072
5557
|
const makePaginator = (model, data) => new paginator_default(data.data.map((item) => model.make(item)), data.total, data.per_page, data.current_page);
|
|
4073
5558
|
|
|
4074
5559
|
//#endregion
|
|
4075
|
-
export { attribute_default as Attribute, builder_default as Builder, casts_attributes_default as CastsAttributes, collection_default as Collection, has_unique_ids_default as HasUniqueIds, InvalidArgumentError, Migrate, migration_default as Migration, model_default as Model, ModelNotFoundError, paginator_default as Paginator, pivot_default as Pivot, query_builder_default as QueryBuilder, RelationNotFoundError, scope_default as Scope, soft_deletes_default as SoftDeletes, arquebus_default as arquebus, compose, defineConfig, flattenDeep, getAttrMethod, getAttrName, getGetterMethod, getRelationMethod, getRelationName, getScopeMethod, getScopeName, getSetterMethod, kebabCase, make, makeCollection, makePaginator, now, snakeCase, tap };
|
|
5560
|
+
export { attribute_default as Attribute, builder_default as Builder, casts_attributes_default as CastsAttributes, collection_default as Collection, has_unique_ids_default as HasUniqueIds, InvalidArgumentError, Migrate, migration_default as Migration, model_default as Model, ModelNotFoundError, paginator_default as Paginator, pivot_default as Pivot, query_builder_default as QueryBuilder, RelationNotFoundError, scope_default as Scope, soft_deletes_default as SoftDeletes, arquebus_default as arquebus, compose, defineConfig, flatten, flattenDeep, getAttrMethod, getAttrName, getGetterMethod, getRelationMethod, getRelationName, getScopeMethod, getScopeName, getSetterMethod, kebabCase, make, makeCollection, makePaginator, now, snakeCase, tap };
|