Skip to content

Commit 10d2230

Browse files
Merge pull request #3760 from drizzle-team/beta
Beta
2 parents 866c257 + fe986e6 commit 10d2230

File tree

17 files changed

+1397
-20
lines changed

17 files changed

+1397
-20
lines changed

changelogs/drizzle-kit/0.30.1.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# New Features
2+
3+
### `drizzle-kit export`
4+
5+
To make drizzle-kit integration with other migration tools, like Atlas much easier, we've prepared a new command called `export`. It will translate your drizzle schema in SQL representation(DDL) statements and outputs to the console
6+
7+
```ts
8+
// schema.ts
9+
import { pgTable, serial, text } from 'drizzle-orm/pg-core'
10+
11+
export const users = pgTable('users', {
12+
id: serial('id').primaryKey(),
13+
email: text('email').notNull(),
14+
name: text('name')
15+
});
16+
```
17+
Running
18+
```bash
19+
npx drizzle-kit export
20+
```
21+
22+
will output this string to console
23+
```bash
24+
CREATE TABLE "users" (
25+
"id" serial PRIMARY KEY NOT NULL,
26+
"email" text NOT NULL,
27+
"name" text
28+
);
29+
```
30+
31+
By default, the only option for now is `--sql`, so the output format will be SQL DDL statements. In the future, we will support additional output formats to accommodate more migration tools
32+
33+
```bash
34+
npx drizzle-kit export --sql
35+
```

changelogs/drizzle-orm/0.38.2.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# New features
2+
3+
## `USE INDEX`, `FORCE INDEX` and `IGNORE INDEX` for MySQL
4+
5+
In MySQL, the statements USE INDEX, FORCE INDEX, and IGNORE INDEX are hints used in SQL queries to influence how the query optimizer selects indexes. These hints provide fine-grained control over index usage, helping optimize performance when the default behavior of the optimizer is not ideal.
6+
7+
### Use Index
8+
9+
The `USE INDEX` hint suggests to the optimizer which indexes to consider when processing the query. The optimizer is not forced to use these indexes but will prioritize them if they are suitable.
10+
11+
```ts
12+
export const users = mysqlTable('users', {
13+
id: int('id').primaryKey(),
14+
name: varchar('name', { length: 100 }).notNull(),
15+
}, () => [usersTableNameIndex]);
16+
17+
const usersTableNameIndex = index('users_name_index').on(users.name);
18+
19+
await db.select()
20+
.from(users, { useIndex: usersTableNameIndex })
21+
.where(eq(users.name, 'David'));
22+
```
23+
24+
### Ignore Index
25+
26+
The `IGNORE INDEX` hint tells the optimizer to avoid using specific indexes for the query. MySQL will consider all other indexes (if any) or perform a full table scan if necessary.
27+
28+
```ts
29+
export const users = mysqlTable('users', {
30+
id: int('id').primaryKey(),
31+
name: varchar('name', { length: 100 }).notNull(),
32+
}, () => [usersTableNameIndex]);
33+
34+
const usersTableNameIndex = index('users_name_index').on(users.name);
35+
36+
await db.select()
37+
.from(users, { ignoreIndex: usersTableNameIndex })
38+
.where(eq(users.name, 'David'));
39+
```
40+
41+
### Force Index
42+
43+
The `FORCE INDEX` hint forces the optimizer to use the specified index(es) for the query. If the specified index cannot be used, MySQL will not fall back to other indexes; it might resort to a full table scan instead.
44+
45+
```ts copy
46+
export const users = mysqlTable('users', {
47+
id: int('id').primaryKey(),
48+
name: varchar('name', { length: 100 }).notNull(),
49+
}, () => [usersTableNameIndex]);
50+
51+
const usersTableNameIndex = index('users_name_index').on(users.name);
52+
53+
await db.select()
54+
.from(users, { forceIndex: usersTableNameIndex })
55+
.where(eq(users.name, 'David'));
56+
```
57+
58+
You can also combine those hints and use multiple indexes in a query if you need

drizzle-kit/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "drizzle-kit",
3-
"version": "0.30.0",
3+
"version": "0.30.1",
44
"homepage": "https://orm.drizzle.team",
55
"keywords": [
66
"drizzle",

drizzle-kit/src/cli/commands/migrate.ts

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import {
5454
ResolveSelectNamed,
5555
schema,
5656
} from '../views';
57-
import { GenerateConfig } from './utils';
57+
import { ExportConfig, GenerateConfig } from './utils';
5858

5959
export type Named = {
6060
name: string;
@@ -368,6 +368,44 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => {
368368
}
369369
};
370370

371+
export const prepareAndExportPg = async (config: ExportConfig) => {
372+
const schemaPath = config.schema;
373+
374+
try {
375+
const { prev, cur } = await preparePgMigrationSnapshot(
376+
[], // no snapshots before
377+
schemaPath,
378+
undefined,
379+
);
380+
381+
const validatedPrev = pgSchema.parse(prev);
382+
const validatedCur = pgSchema.parse(cur);
383+
384+
const squashedPrev = squashPgScheme(validatedPrev);
385+
const squashedCur = squashPgScheme(validatedCur);
386+
387+
const { sqlStatements } = await applyPgSnapshotsDiff(
388+
squashedPrev,
389+
squashedCur,
390+
schemasResolver,
391+
enumsResolver,
392+
sequencesResolver,
393+
policyResolver,
394+
indPolicyResolver,
395+
roleResolver,
396+
tablesResolver,
397+
columnsResolver,
398+
viewsResolver,
399+
validatedPrev,
400+
validatedCur,
401+
);
402+
403+
console.log(sqlStatements.join('\n'));
404+
} catch (e) {
405+
console.error(e);
406+
}
407+
};
408+
371409
export const preparePgPush = async (
372410
cur: PgSchema,
373411
prev: PgSchema,
@@ -697,6 +735,70 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => {
697735
}
698736
};
699737

738+
export const prepareAndExportSinglestore = async (config: ExportConfig) => {
739+
const schemaPath = config.schema;
740+
741+
try {
742+
const { prev, cur } = await prepareSingleStoreMigrationSnapshot(
743+
[],
744+
schemaPath,
745+
undefined,
746+
);
747+
748+
const validatedPrev = singlestoreSchema.parse(prev);
749+
const validatedCur = singlestoreSchema.parse(cur);
750+
751+
const squashedPrev = squashSingleStoreScheme(validatedPrev);
752+
const squashedCur = squashSingleStoreScheme(validatedCur);
753+
754+
const { sqlStatements, _meta } = await applySingleStoreSnapshotsDiff(
755+
squashedPrev,
756+
squashedCur,
757+
tablesResolver,
758+
columnsResolver,
759+
/* singleStoreViewsResolver, */
760+
validatedPrev,
761+
validatedCur,
762+
);
763+
764+
console.log(sqlStatements.join('\n'));
765+
} catch (e) {
766+
console.error(e);
767+
}
768+
};
769+
770+
export const prepareAndExportMysql = async (config: ExportConfig) => {
771+
const schemaPath = config.schema;
772+
773+
try {
774+
const { prev, cur, custom } = await prepareMySqlMigrationSnapshot(
775+
[],
776+
schemaPath,
777+
undefined,
778+
);
779+
780+
const validatedPrev = mysqlSchema.parse(prev);
781+
const validatedCur = mysqlSchema.parse(cur);
782+
783+
const squashedPrev = squashMysqlScheme(validatedPrev);
784+
const squashedCur = squashMysqlScheme(validatedCur);
785+
786+
const { sqlStatements, statements, _meta } = await applyMysqlSnapshotsDiff(
787+
squashedPrev,
788+
squashedCur,
789+
tablesResolver,
790+
columnsResolver,
791+
mySqlViewsResolver,
792+
validatedPrev,
793+
validatedCur,
794+
);
795+
796+
console.log(sqlStatements.join('\n'));
797+
} catch (e) {
798+
console.error(e);
799+
}
800+
};
801+
700802
export const prepareAndMigrateSqlite = async (config: GenerateConfig) => {
701803
const outFolder = config.out;
702804
const schemaPath = config.schema;
@@ -760,6 +862,38 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => {
760862
}
761863
};
762864

865+
export const prepareAndExportSqlite = async (config: ExportConfig) => {
866+
const schemaPath = config.schema;
867+
868+
try {
869+
const { prev, cur } = await prepareSqliteMigrationSnapshot(
870+
[],
871+
schemaPath,
872+
undefined,
873+
);
874+
875+
const validatedPrev = sqliteSchema.parse(prev);
876+
const validatedCur = sqliteSchema.parse(cur);
877+
878+
const squashedPrev = squashSqliteScheme(validatedPrev);
879+
const squashedCur = squashSqliteScheme(validatedCur);
880+
881+
const { sqlStatements, _meta } = await applySqliteSnapshotsDiff(
882+
squashedPrev,
883+
squashedCur,
884+
tablesResolver,
885+
columnsResolver,
886+
sqliteViewsResolver,
887+
validatedPrev,
888+
validatedCur,
889+
);
890+
891+
console.log(sqlStatements.join('\n'));
892+
} catch (e) {
893+
console.error(e);
894+
}
895+
};
896+
763897
export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => {
764898
const outFolder = config.out;
765899
const schemaPath = config.schema;
@@ -822,6 +956,38 @@ export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => {
822956
}
823957
};
824958

959+
export const prepareAndExportLibSQL = async (config: ExportConfig) => {
960+
const schemaPath = config.schema;
961+
962+
try {
963+
const { prev, cur, custom } = await prepareSqliteMigrationSnapshot(
964+
[],
965+
schemaPath,
966+
undefined,
967+
);
968+
969+
const validatedPrev = sqliteSchema.parse(prev);
970+
const validatedCur = sqliteSchema.parse(cur);
971+
972+
const squashedPrev = squashSqliteScheme(validatedPrev);
973+
const squashedCur = squashSqliteScheme(validatedCur);
974+
975+
const { sqlStatements, _meta } = await applyLibSQLSnapshotsDiff(
976+
squashedPrev,
977+
squashedCur,
978+
tablesResolver,
979+
columnsResolver,
980+
sqliteViewsResolver,
981+
validatedPrev,
982+
validatedCur,
983+
);
984+
985+
console.log(sqlStatements.join('\n'));
986+
} catch (e) {
987+
console.error(e);
988+
}
989+
};
990+
825991
export const prepareSQLitePush = async (
826992
schemaPath: string | string[],
827993
snapshot: SQLiteSchema,

drizzle-kit/src/cli/commands/utils.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ export type GenerateConfig = {
135135
driver?: Driver;
136136
};
137137

138+
export type ExportConfig = {
139+
dialect: Dialect;
140+
schema: string | string[];
141+
sql: boolean;
142+
};
143+
138144
export const prepareGenerateConfig = async (
139145
options: {
140146
config?: string;
@@ -185,6 +191,38 @@ export const prepareGenerateConfig = async (
185191
};
186192
};
187193

194+
export const prepareExportConfig = async (
195+
options: {
196+
config?: string;
197+
schema?: string;
198+
dialect?: Dialect;
199+
sql: boolean;
200+
},
201+
from: 'config' | 'cli',
202+
): Promise<ExportConfig> => {
203+
const config = from === 'config' ? await drizzleConfigFromFile(options.config, true) : options;
204+
205+
const { schema, dialect, sql } = config;
206+
207+
if (!schema || !dialect) {
208+
console.log(error('Please provide required params:'));
209+
console.log(wrapParam('schema', schema));
210+
console.log(wrapParam('dialect', dialect));
211+
process.exit(1);
212+
}
213+
214+
const fileNames = prepareFilenames(schema);
215+
if (fileNames.length === 0) {
216+
render(`[${chalk.blue('i')}] No schema file in ${schema} was found`);
217+
process.exit(0);
218+
}
219+
return {
220+
dialect: dialect,
221+
schema: schema,
222+
sql: sql,
223+
};
224+
};
225+
188226
export const flattenDatabaseCredentials = (config: any) => {
189227
if ('dbCredentials' in config) {
190228
const { dbCredentials, ...rest } = config;
@@ -768,6 +806,7 @@ export const prepareMigrateConfig = async (configPath: string | undefined) => {
768806

769807
export const drizzleConfigFromFile = async (
770808
configPath?: string,
809+
isExport?: boolean,
771810
): Promise<CliConfig> => {
772811
const prefix = process.env.TEST_CONFIG_PATH_PREFIX || '';
773812

@@ -783,7 +822,7 @@ export const drizzleConfigFromFile = async (
783822
? 'drizzle.config.js'
784823
: 'drizzle.config.json';
785824

786-
if (!configPath) {
825+
if (!configPath && !isExport) {
787826
console.log(
788827
chalk.gray(
789828
`No config path provided, using default '${defaultConfigPath}'`,
@@ -798,7 +837,8 @@ export const drizzleConfigFromFile = async (
798837
process.exit(1);
799838
}
800839

801-
console.log(chalk.grey(`Reading config file '${path}'`));
840+
if (!isExport) console.log(chalk.grey(`Reading config file '${path}'`));
841+
802842
const { unregister } = await safeRegister();
803843
const required = require(`${path}`);
804844
const content = required.default ?? required;

0 commit comments

Comments
 (0)