Skip to content

Commit

Permalink
Merge pull request #3760 from drizzle-team/beta
Browse files Browse the repository at this point in the history
Beta
  • Loading branch information
AndriiSherman authored Dec 13, 2024
2 parents 866c257 + fe986e6 commit 10d2230
Show file tree
Hide file tree
Showing 17 changed files with 1,397 additions and 20 deletions.
35 changes: 35 additions & 0 deletions changelogs/drizzle-kit/0.30.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# New Features

### `drizzle-kit export`

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

```ts
// schema.ts
import { pgTable, serial, text } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
id: serial('id').primaryKey(),
email: text('email').notNull(),
name: text('name')
});
```
Running
```bash
npx drizzle-kit export
```

will output this string to console
```bash
CREATE TABLE "users" (
"id" serial PRIMARY KEY NOT NULL,
"email" text NOT NULL,
"name" text
);
```

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

```bash
npx drizzle-kit export --sql
```
58 changes: 58 additions & 0 deletions changelogs/drizzle-orm/0.38.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# New features

## `USE INDEX`, `FORCE INDEX` and `IGNORE INDEX` for MySQL

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.

### Use Index

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.

```ts
export const users = mysqlTable('users', {
id: int('id').primaryKey(),
name: varchar('name', { length: 100 }).notNull(),
}, () => [usersTableNameIndex]);

const usersTableNameIndex = index('users_name_index').on(users.name);

await db.select()
.from(users, { useIndex: usersTableNameIndex })
.where(eq(users.name, 'David'));
```

### Ignore Index

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.

```ts
export const users = mysqlTable('users', {
id: int('id').primaryKey(),
name: varchar('name', { length: 100 }).notNull(),
}, () => [usersTableNameIndex]);

const usersTableNameIndex = index('users_name_index').on(users.name);

await db.select()
.from(users, { ignoreIndex: usersTableNameIndex })
.where(eq(users.name, 'David'));
```

### Force Index

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.

```ts copy
export const users = mysqlTable('users', {
id: int('id').primaryKey(),
name: varchar('name', { length: 100 }).notNull(),
}, () => [usersTableNameIndex]);

const usersTableNameIndex = index('users_name_index').on(users.name);

await db.select()
.from(users, { forceIndex: usersTableNameIndex })
.where(eq(users.name, 'David'));
```

You can also combine those hints and use multiple indexes in a query if you need
2 changes: 1 addition & 1 deletion drizzle-kit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "drizzle-kit",
"version": "0.30.0",
"version": "0.30.1",
"homepage": "https://orm.drizzle.team",
"keywords": [
"drizzle",
Expand Down
168 changes: 167 additions & 1 deletion drizzle-kit/src/cli/commands/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
ResolveSelectNamed,
schema,
} from '../views';
import { GenerateConfig } from './utils';
import { ExportConfig, GenerateConfig } from './utils';

export type Named = {
name: string;
Expand Down Expand Up @@ -368,6 +368,44 @@ export const prepareAndMigratePg = async (config: GenerateConfig) => {
}
};

export const prepareAndExportPg = async (config: ExportConfig) => {
const schemaPath = config.schema;

try {
const { prev, cur } = await preparePgMigrationSnapshot(
[], // no snapshots before
schemaPath,
undefined,
);

const validatedPrev = pgSchema.parse(prev);
const validatedCur = pgSchema.parse(cur);

const squashedPrev = squashPgScheme(validatedPrev);
const squashedCur = squashPgScheme(validatedCur);

const { sqlStatements } = await applyPgSnapshotsDiff(
squashedPrev,
squashedCur,
schemasResolver,
enumsResolver,
sequencesResolver,
policyResolver,
indPolicyResolver,
roleResolver,
tablesResolver,
columnsResolver,
viewsResolver,
validatedPrev,
validatedCur,
);

console.log(sqlStatements.join('\n'));
} catch (e) {
console.error(e);
}
};

export const preparePgPush = async (
cur: PgSchema,
prev: PgSchema,
Expand Down Expand Up @@ -697,6 +735,70 @@ export const prepareAndMigrateSingleStore = async (config: GenerateConfig) => {
}
};

export const prepareAndExportSinglestore = async (config: ExportConfig) => {
const schemaPath = config.schema;

try {
const { prev, cur } = await prepareSingleStoreMigrationSnapshot(
[],
schemaPath,
undefined,
);

const validatedPrev = singlestoreSchema.parse(prev);
const validatedCur = singlestoreSchema.parse(cur);

const squashedPrev = squashSingleStoreScheme(validatedPrev);
const squashedCur = squashSingleStoreScheme(validatedCur);

const { sqlStatements, _meta } = await applySingleStoreSnapshotsDiff(
squashedPrev,
squashedCur,
tablesResolver,
columnsResolver,
/* singleStoreViewsResolver, */
validatedPrev,
validatedCur,
);

console.log(sqlStatements.join('\n'));
} catch (e) {
console.error(e);
}
};

export const prepareAndExportMysql = async (config: ExportConfig) => {
const schemaPath = config.schema;

try {
const { prev, cur, custom } = await prepareMySqlMigrationSnapshot(
[],
schemaPath,
undefined,
);

const validatedPrev = mysqlSchema.parse(prev);
const validatedCur = mysqlSchema.parse(cur);

const squashedPrev = squashMysqlScheme(validatedPrev);
const squashedCur = squashMysqlScheme(validatedCur);

const { sqlStatements, statements, _meta } = await applyMysqlSnapshotsDiff(
squashedPrev,
squashedCur,
tablesResolver,
columnsResolver,
mySqlViewsResolver,
validatedPrev,
validatedCur,
);

console.log(sqlStatements.join('\n'));
} catch (e) {
console.error(e);
}
};

export const prepareAndMigrateSqlite = async (config: GenerateConfig) => {
const outFolder = config.out;
const schemaPath = config.schema;
Expand Down Expand Up @@ -760,6 +862,38 @@ export const prepareAndMigrateSqlite = async (config: GenerateConfig) => {
}
};

export const prepareAndExportSqlite = async (config: ExportConfig) => {
const schemaPath = config.schema;

try {
const { prev, cur } = await prepareSqliteMigrationSnapshot(
[],
schemaPath,
undefined,
);

const validatedPrev = sqliteSchema.parse(prev);
const validatedCur = sqliteSchema.parse(cur);

const squashedPrev = squashSqliteScheme(validatedPrev);
const squashedCur = squashSqliteScheme(validatedCur);

const { sqlStatements, _meta } = await applySqliteSnapshotsDiff(
squashedPrev,
squashedCur,
tablesResolver,
columnsResolver,
sqliteViewsResolver,
validatedPrev,
validatedCur,
);

console.log(sqlStatements.join('\n'));
} catch (e) {
console.error(e);
}
};

export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => {
const outFolder = config.out;
const schemaPath = config.schema;
Expand Down Expand Up @@ -822,6 +956,38 @@ export const prepareAndMigrateLibSQL = async (config: GenerateConfig) => {
}
};

export const prepareAndExportLibSQL = async (config: ExportConfig) => {
const schemaPath = config.schema;

try {
const { prev, cur, custom } = await prepareSqliteMigrationSnapshot(
[],
schemaPath,
undefined,
);

const validatedPrev = sqliteSchema.parse(prev);
const validatedCur = sqliteSchema.parse(cur);

const squashedPrev = squashSqliteScheme(validatedPrev);
const squashedCur = squashSqliteScheme(validatedCur);

const { sqlStatements, _meta } = await applyLibSQLSnapshotsDiff(
squashedPrev,
squashedCur,
tablesResolver,
columnsResolver,
sqliteViewsResolver,
validatedPrev,
validatedCur,
);

console.log(sqlStatements.join('\n'));
} catch (e) {
console.error(e);
}
};

export const prepareSQLitePush = async (
schemaPath: string | string[],
snapshot: SQLiteSchema,
Expand Down
44 changes: 42 additions & 2 deletions drizzle-kit/src/cli/commands/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ export type GenerateConfig = {
driver?: Driver;
};

export type ExportConfig = {
dialect: Dialect;
schema: string | string[];
sql: boolean;
};

export const prepareGenerateConfig = async (
options: {
config?: string;
Expand Down Expand Up @@ -185,6 +191,38 @@ export const prepareGenerateConfig = async (
};
};

export const prepareExportConfig = async (
options: {
config?: string;
schema?: string;
dialect?: Dialect;
sql: boolean;
},
from: 'config' | 'cli',
): Promise<ExportConfig> => {
const config = from === 'config' ? await drizzleConfigFromFile(options.config, true) : options;

const { schema, dialect, sql } = config;

if (!schema || !dialect) {
console.log(error('Please provide required params:'));
console.log(wrapParam('schema', schema));
console.log(wrapParam('dialect', dialect));
process.exit(1);
}

const fileNames = prepareFilenames(schema);
if (fileNames.length === 0) {
render(`[${chalk.blue('i')}] No schema file in ${schema} was found`);
process.exit(0);
}
return {
dialect: dialect,
schema: schema,
sql: sql,
};
};

export const flattenDatabaseCredentials = (config: any) => {
if ('dbCredentials' in config) {
const { dbCredentials, ...rest } = config;
Expand Down Expand Up @@ -768,6 +806,7 @@ export const prepareMigrateConfig = async (configPath: string | undefined) => {

export const drizzleConfigFromFile = async (
configPath?: string,
isExport?: boolean,
): Promise<CliConfig> => {
const prefix = process.env.TEST_CONFIG_PATH_PREFIX || '';

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

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

console.log(chalk.grey(`Reading config file '${path}'`));
if (!isExport) console.log(chalk.grey(`Reading config file '${path}'`));

const { unregister } = await safeRegister();
const required = require(`${path}`);
const content = required.default ?? required;
Expand Down
Loading

0 comments on commit 10d2230

Please sign in to comment.