Skip to content

Commit

Permalink
Merge branch 'beta' into improve-types-performance
Browse files Browse the repository at this point in the history
  • Loading branch information
dankochetov committed Aug 6, 2023
2 parents 4e264be + cd1b6be commit 569ea0f
Show file tree
Hide file tree
Showing 10 changed files with 455 additions and 26 deletions.
8 changes: 4 additions & 4 deletions drizzle-orm/src/pg-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,12 +346,11 @@ export class PgDialect {
}

buildInsertQuery({ table, values, onConflict, returning }: PgInsertConfig): SQL {
const isSingleValue = values.length === 1;
const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = [];
const columns: Record<string, PgColumn> = table[Table.Symbol.Columns];
const colEntries: [string, PgColumn][] = isSingleValue
? Object.keys(values[0]!).map((fieldName) => [fieldName, columns[fieldName]!])
: Object.entries(columns);

const colEntries: [string, PgColumn][] = Object.entries(columns);

const insertOrder = colEntries.map(([, column]) => sql.identifier(column.name));

for (const [valueIndex, value] of values.entries()) {
Expand All @@ -364,6 +363,7 @@ export class PgDialect {
valueList.push(colValue);
}
}

valuesSqlList.push(valueList);
if (valueIndex < values.length - 1) {
valuesSqlList.push(sql`, `);
Expand Down
11 changes: 7 additions & 4 deletions drizzle-orm/src/sqlite-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,11 @@ export abstract class SQLiteDialect {
}

buildInsertQuery({ table, values, onConflict, returning }: SQLiteInsertConfig): SQL {
const isSingleValue = values.length === 1;
// const isSingleValue = values.length === 1;
const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = [];
const columns: Record<string, SQLiteColumn> = table[Table.Symbol.Columns];
const colEntries: [string, SQLiteColumn][] = isSingleValue
? Object.keys(values[0]!).map((fieldName) => [fieldName, columns[fieldName]!])
: Object.entries(columns);

const colEntries: [string, SQLiteColumn][] = Object.entries(columns);
const insertOrder = colEntries.map(([, column]) => sql.identifier(column.name));

for (const [valueIndex, value] of values.entries()) {
Expand Down Expand Up @@ -312,6 +311,10 @@ export abstract class SQLiteDialect {

const onConflictSql = onConflict ? sql` on conflict ${onConflict}` : undefined;

// if (isSingleValue && valuesSqlList.length === 0){
// return sql`insert into ${table} default values ${onConflictSql}${returningSql}`;
// }

return sql`insert into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}${returningSql}`;
}

Expand Down
6 changes: 6 additions & 0 deletions drizzle-orm/src/sqlite-core/query-builders/insert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ export class SQLiteInsertBuilder<
return result;
});

// if (mappedValues.length > 1 && mappedValues.some((t) => Object.keys(t).length === 0)) {
// throw new Error(
// `One of the values you want to insert is empty. In SQLite you can insert only one empty object per statement. For this case Drizzle with use "INSERT INTO ... DEFAULT VALUES" syntax`,
// );
// }

return new SQLiteInsert(this.table, mappedValues, this.session, this.dialect);
}
}
Expand Down
84 changes: 84 additions & 0 deletions integration-tests/tests/better-sqlite.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,90 @@ test.serial('with ... select', (t) => {
]);
});

test.serial('query check: insert single empty row', (t) => {
const { db } = t.context;

const users = sqliteTable('users', {
id: integer('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

const query = db
.insert(users)
.values({})
.toSQL();

t.deepEqual(query, {
sql: 'insert into "users" ("id", "name", "state") values (null, ?, null)',
params: ['Dan'],
});
});

test.serial('query check: insert multiple empty rows', (t) => {
const { db } = t.context;

const users = sqliteTable('users', {
id: integer('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

const query = db
.insert(users)
.values([{}, {}])
.toSQL();

t.deepEqual(query, {
sql: 'insert into "users" ("id", "name", "state") values (null, ?, null), (null, ?, null)',
params: ['Dan', 'Dan'],
});
});

test.serial('Insert all defaults in 1 row', async (t) => {
const { db } = t.context;

const users = sqliteTable('empty_insert_single', {
id: integer('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

db.run(sql`drop table if exists ${users}`);

db.run(
sql`create table ${users} (id integer primary key, name text default 'Dan', state text)`,
);

db.insert(users).values({}).run();

const res = db.select().from(users).all();

t.deepEqual(res, [{ id: 1, name: 'Dan', state: null }]);
});

test.serial('Insert all defaults in multiple rows', async (t) => {
const { db } = t.context;

const users = sqliteTable('empty_insert_multiple', {
id: integer('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

db.run(sql`drop table if exists ${users}`);

db.run(
sql`create table ${users} (id integer primary key, name text default 'Dan', state text)`,
);

db.insert(users).values([{}, {}]).run()

const res = db.select().from(users).all();

t.deepEqual(res, [{ id: 1, name: 'Dan', state: null }, { id: 2, name: 'Dan', state: null }]);
});

test.serial('select from subquery sql', (t) => {
const { db } = t.context;

Expand Down
84 changes: 84 additions & 0 deletions integration-tests/tests/libsql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,90 @@ test.serial('delete returning sql', async (t) => {
t.deepEqual(users, [{ name: 'JOHN' }]);
});

test.serial('query check: insert single empty row', (t) => {
const { db } = t.context;

const users = sqliteTable('users', {
id: integer('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

const query = db
.insert(users)
.values({})
.toSQL();

t.deepEqual(query, {
sql: 'insert into "users" ("id", "name", "state") values (null, ?, null)',
params: ['Dan'],
});
});

test.serial('query check: insert multiple empty rows', (t) => {
const { db } = t.context;

const users = sqliteTable('users', {
id: integer('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

const query = db
.insert(users)
.values([{}, {}])
.toSQL();

t.deepEqual(query, {
sql: 'insert into "users" ("id", "name", "state") values (null, ?, null), (null, ?, null)',
params: ['Dan', 'Dan'],
});
});

test.serial('Insert all defaults in 1 row', async (t) => {
const { db } = t.context;

const users = sqliteTable('empty_insert_single', {
id: integer('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

await db.run(sql`drop table if exists ${users}`);

await db.run(
sql`create table ${users} (id integer primary key, name text default 'Dan', state text)`,
);

await db.insert(users).values({}).run();

const res = await db.select().from(users).all();

t.deepEqual(res, [{ id: 1, name: 'Dan', state: null }]);
});

test.serial('Insert all defaults in multiple rows', async (t) => {
const { db } = t.context;

const users = sqliteTable('empty_insert_multiple', {
id: integer('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

await db.run(sql`drop table if exists ${users}`);

await db.run(
sql`create table ${users} (id integer primary key, name text default 'Dan', state text)`,
);

await db.insert(users).values([{}, {}]).run()

const res = await db.select().from(users).all();

t.deepEqual(res, [{ id: 1, name: 'Dan', state: null }, { id: 2, name: 'Dan', state: null }]);
});

test.serial('update returning sql', async (t) => {
const { db } = t.context;

Expand Down
84 changes: 84 additions & 0 deletions integration-tests/tests/mysql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,90 @@ test.serial('build query', async (t) => {
});
});

test.serial('Query check: Insert all defaults in 1 row', async (t) => {
const { db } = t.context;

const users = mysqlTable('users', {
id: serial('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

const query = db
.insert(users)
.values({})
.toSQL();

t.deepEqual(query, {
sql: 'insert into `users` () values ()',
params: [],
});
});

test.serial('Query check: Insert all defaults in multiple rows', async (t) => {
const { db } = t.context;

const users = mysqlTable('users', {
id: serial('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state').default('UA'),
});

const query = db
.insert(users)
.values([{}, {}])
.toSQL();

t.deepEqual(query, {
sql: 'insert into `users` (`id`, `name`, `state`) values (default, default, default), (default, default, default)',
params: [],
});
});

test.serial('Insert all defaults in 1 row', async (t) => {
const { db } = t.context;

const users = mysqlTable('empty_insert_single', {
id: serial('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

await db.execute(sql`drop table if exists ${users}`);

await db.execute(
sql`create table ${users} (id serial primary key, name text default ('Dan'), state text)`,
);

await db.insert(users).values({});

const res = await db.select().from(users);

t.deepEqual(res, [{ id: 1, name: 'Dan', state: null }]);
});

test.serial('Insert all defaults in multiple rows', async (t) => {
const { db } = t.context;

const users = mysqlTable('empty_insert_multiple', {
id: serial('id').primaryKey(),
name: text('name').default('Dan'),
state: text('state'),
});

await db.execute(sql`drop table if exists ${users}`);

await db.execute(
sql`create table ${users} (id serial primary key, name text default ('Dan'), state text)`,
);

await db.insert(users).values([{}, {}])

const res = await db.select().from(users);

t.deepEqual(res, [{ id: 1, name: 'Dan', state: null }, { id: 2, name: 'Dan', state: null }]);
});

test.serial('build query insert with onDuplicate', async (t) => {
const { db } = t.context;

Expand Down
8 changes: 4 additions & 4 deletions integration-tests/tests/pg-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ test.serial('build query insert with onConflict do update', async (t) => {

t.deepEqual(query, {
sql:
'insert into "mySchema"."users" ("name", "jsonb") values ($1, $2) on conflict ("id") do update set "name" = $3',
'insert into "mySchema"."users" ("id", "name", "verified", "jsonb", "created_at") values (default, $1, default, $2, default) on conflict ("id") do update set "name" = $3',
params: ['John', '["foo","bar"]', 'John1'],
});
});
Expand All @@ -708,7 +708,7 @@ test.serial('build query insert with onConflict do update / multiple columns', a

t.deepEqual(query, {
sql:
'insert into "mySchema"."users" ("name", "jsonb") values ($1, $2) on conflict ("id","name") do update set "name" = $3',
'insert into "mySchema"."users" ("id", "name", "verified", "jsonb", "created_at") values (default, $1, default, $2, default) on conflict ("id","name") do update set "name" = $3',
params: ['John', '["foo","bar"]', 'John1'],
});
});
Expand All @@ -722,7 +722,7 @@ test.serial('build query insert with onConflict do nothing', async (t) => {
.toSQL();

t.deepEqual(query, {
sql: 'insert into "mySchema"."users" ("name", "jsonb") values ($1, $2) on conflict do nothing',
sql: 'insert into "mySchema"."users" ("id", "name", "verified", "jsonb", "created_at") values (default, $1, default, $2, default) on conflict do nothing',
params: ['John', '["foo","bar"]'],
});
});
Expand All @@ -736,7 +736,7 @@ test.serial('build query insert with onConflict do nothing + target', async (t)
.toSQL();

t.deepEqual(query, {
sql: 'insert into "mySchema"."users" ("name", "jsonb") values ($1, $2) on conflict ("id") do nothing',
sql: 'insert into "mySchema"."users" ("id", "name", "verified", "jsonb", "created_at") values (default, $1, default, $2, default) on conflict ("id") do nothing',
params: ['John', '["foo","bar"]'],
});
});
Expand Down
Loading

0 comments on commit 569ea0f

Please sign in to comment.