Skip to content

Commit

Permalink
[All] fixed insert that now bypasses the generated columns and added …
Browse files Browse the repository at this point in the history
…intergration tests
  • Loading branch information
Angelelz committed Nov 6, 2023
1 parent d06eff5 commit 00b1c05
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 11 deletions.
5 changes: 5 additions & 0 deletions drizzle-orm/src/column.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ export abstract class Column<
mapToDriverValue(value: unknown): unknown {
return value;
}

// ** @internal */
isGenerated(): boolean {
return this.generated !== undefined;
}
}

export type UpdateColConfig<
Expand Down
4 changes: 2 additions & 2 deletions drizzle-orm/src/mysql-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Param, type QueryWithTypings, SQL, sql, type SQLChunk, View } from '~/s
import { Subquery, SubqueryConfig } from '~/subquery.ts';
import { getTableName, Table } from '~/table.ts';
import { orderSelectedFields, type UpdateSet } from '~/utils.ts';
import { DrizzleError, type Name, ViewBaseConfig, and, eq } from '../index.ts';
import { and, DrizzleError, eq, type Name, ViewBaseConfig } from '../index.ts';
import { MySqlColumn } from './columns/common.ts';
import type { MySqlDeleteConfig } from './query-builders/delete.ts';
import type { MySqlInsertConfig } from './query-builders/insert.ts';
Expand Down Expand Up @@ -398,7 +398,7 @@ export class MySqlDialect {
// const isSingleValue = values.length === 1;
const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = [];
const columns: Record<string, MySqlColumn> = table[Table.Symbol.Columns];
const colEntries: [string, MySqlColumn][] = Object.entries(columns);
const colEntries: [string, MySqlColumn][] = Object.entries(columns).filter(([_, col]) => !col.isGenerated());

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

Expand Down
6 changes: 3 additions & 3 deletions drizzle-orm/src/pg-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
type TableRelationalConfig,
type TablesRelationalConfig,
} from '~/relations.ts';
import { and, eq, View } from '~/sql/index.ts';
import {
type DriverValueEncoder,
type Name,
Expand All @@ -39,9 +40,8 @@ import { getTableName, Table } from '~/table.ts';
import { orderSelectedFields, type UpdateSet } from '~/utils.ts';
import { ViewBaseConfig } from '~/view-common.ts';
import type { PgSession } from './session.ts';
import type { PgMaterializedView } from './view.ts';
import { View, and, eq } from '~/sql/index.ts';
import { PgViewBase } from './view-base.ts';
import type { PgMaterializedView } from './view.ts';

export class PgDialect {
static readonly [entityKind]: string = 'PgDialect';
Expand Down Expand Up @@ -426,7 +426,7 @@ export class PgDialect {
const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = [];
const columns: Record<string, PgColumn> = table[Table.Symbol.Columns];

const colEntries: [string, PgColumn][] = Object.entries(columns);
const colEntries: [string, PgColumn][] = Object.entries(columns).filter(([_, col]) => !col.isGenerated());

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

Expand Down
6 changes: 3 additions & 3 deletions drizzle-orm/src/sqlite-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import {
type TableRelationalConfig,
type TablesRelationalConfig,
} from '~/relations.ts';
import type { Name } from '~/sql/index.ts';
import { and, eq } from '~/sql/index.ts';
import { Param, type QueryWithTypings, SQL, sql, type SQLChunk } from '~/sql/sql.ts';
import type { Name} from '~/sql/index.ts';
import { and, eq } from '~/sql/index.ts'
import { SQLiteColumn } from '~/sqlite-core/columns/index.ts';
import type { SQLiteDeleteConfig, SQLiteInsertConfig, SQLiteUpdateConfig } from '~/sqlite-core/query-builders/index.ts';
import { SQLiteTable } from '~/sqlite-core/table.ts';
Expand Down Expand Up @@ -365,7 +365,7 @@ export abstract class SQLiteDialect {
const valuesSqlList: ((SQLChunk | SQL)[] | SQL)[] = [];
const columns: Record<string, SQLiteColumn> = table[Table.Symbol.Columns];

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

for (const [valueIndex, value] of values.entries()) {
Expand Down
100 changes: 99 additions & 1 deletion integration-tests/tests/libsql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1348,7 +1348,7 @@ test.serial('insert null timestamp', async (t) => {
t: integer('t', { mode: 'timestamp' }),
});

await db.run(sql`create table ${test} (t timestamp)`);
await db.run(sql`create table if not exists ${test} (t timestamp)`);

await db.insert(test).values({ t: null }).run();
const res = await db.select().from(test).all();
Expand Down Expand Up @@ -2423,3 +2423,101 @@ test.serial('set operations (mixed all) as function with subquery', async (t) =>
).orderBy(asc(sql`id`));
});
});

test.serial('select from a table with generated columns', async (t) => {
const { db } = t.context;

const usersTable = sqliteTable('users', {
id: int('id').primaryKey({ autoIncrement: true }),
firstName: text('first_name'),
lastName: text('last_name'),
fullName: text('full_name').generatedAlwaysAs(sql`first_name || ' ' || last_name`, { mode: 'virtual' }),
fullName2: text('full_name2').generatedAlwaysAs(sql`first_name || ' ' || last_name`, { mode: 'stored' }),
upper: text('upper').generatedAlwaysAs(sql`upper(full_name)`, { mode: 'virtual' }),
});
// const lkj = await db.get(sql`select * from ${usersTable}`);
// console.log(lkj);

await db.run(sql`drop table if exists ${usersTable}`);
await db.run(sql`
create table ${usersTable} (
id integer primary key autoincrement,
first_name text,
last_name text,
full_name text generated always as (first_name || ' ' || last_name) virtual,
full_name2 text generated always as (first_name || ' ' || last_name) stored,
upper text generated always as (upper(full_name)) virtual
)
`);

await db.insert(usersTable).values([
{ firstName: 'John', lastName: 'Doe' },
{ firstName: 'Jane', lastName: 'Doe' },
]);

const result = await db.select().from(usersTable);

Expect<
Equal<{
id: number;
firstName: string | null;
lastName: string | null;
fullName: string;
fullName2: string;
upper: string;
}[], typeof result>
>;

t.deepEqual(result, [
{ id: 1, firstName: 'John', lastName: 'Doe', fullName: 'John Doe', fullName2: 'John Doe', upper: 'JOHN DOE' },
{ id: 2, firstName: 'Jane', lastName: 'Doe', fullName: 'Jane Doe', fullName2: 'Jane Doe', upper: 'JANE DOE' },
]);
});

test.serial('select from a table with generated columns with null', async (t) => {
const { db } = t.context;

const usersTable = sqliteTable('users', {
id: int('id').primaryKey({ autoIncrement: true }),
firstName: text('first_name'),
lastName: text('last_name'),
fullName: text('full_name').generatedAlwaysAs(sql`first_name || ' ' || last_name`, { mode: 'virtual' }).$type<
string | null
>(),
fullName2: text('full_name2').generatedAlwaysAs(sql`first_name || ' ' || last_name`, { mode: 'stored' }).$type<
string | null
>(),
upper: text('upper').generatedAlwaysAs(sql`upper(full_name)`, { mode: 'virtual' }).$type<string | null>(),
});

await db.run(sql`drop table if exists ${usersTable}`);
await db.run(sql`
create table ${usersTable} (
id integer primary key autoincrement,
first_name text,
last_name text,
full_name text generated always as (first_name || ' ' || last_name) virtual,
full_name2 text generated always as (first_name || ' ' || last_name) stored,
upper text generated always as (upper(full_name)) virtual
)
`);

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

const result = await db.select().from(usersTable);

Expect<
Equal<{
id: number;
firstName: string | null;
lastName: string | null;
fullName: string | null;
fullName2: string | null;
upper: string | null;
}[], typeof result>
>;

t.deepEqual(result, [
{ id: 1, firstName: null, lastName: null, fullName: null, fullName2: null, upper: null },
]);
});
96 changes: 96 additions & 0 deletions integration-tests/tests/mysql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2654,3 +2654,99 @@ test.serial('set operations (mixed all) as function with subquery', async (t) =>
);
});
});

test.serial('select from a table with generated columns', async (t) => {
const { db } = t.context;

const usersTable = mysqlTable('users', {
id: serial('id'),
firstName: text('first_name'),
lastName: text('last_name'),
fullName: text('full_name').generatedAlwaysAs(sql`concat(first_name, ' ', last_name)`, { mode: 'virtual' }),
fullName2: text('full_name2').generatedAlwaysAs(sql`concat(first_name, ' ', last_name)`, { mode: 'stored' }),
upper: text('upper').generatedAlwaysAs(sql`upper(full_name)`, { mode: 'virtual' }),
});

await db.execute(sql`drop table if exists ${usersTable}`);
await db.execute(sql`
create table ${usersTable} (
id serial,
first_name text,
last_name text,
full_name text generated always as (concat(first_name, ' ', last_name)) virtual,
full_name2 text generated always as (concat(first_name, ' ', last_name)) stored,
upper text generated always as (upper(full_name)) virtual
)
`);

await db.insert(usersTable).values([
{ firstName: 'John', lastName: 'Doe' },
{ firstName: 'Jane', lastName: 'Doe' },
]);

const result = await db.select().from(usersTable);

Expect<
Equal<{
id: number;
firstName: string | null;
lastName: string | null;
fullName: string;
fullName2: string;
upper: string;
}[], typeof result>
>;

t.deepEqual(result, [
{ id: 1, firstName: 'John', lastName: 'Doe', fullName: 'John Doe', fullName2: 'John Doe', upper: 'JOHN DOE' },
{ id: 2, firstName: 'Jane', lastName: 'Doe', fullName: 'Jane Doe', fullName2: 'Jane Doe', upper: 'JANE DOE' },
]);
});

test.serial('select from a table with generated columns with null', async (t) => {
const { db } = t.context;

const usersTable = mysqlTable('users', {
id: serial('id'),
firstName: text('first_name'),
lastName: text('last_name'),
fullName: text('full_name').generatedAlwaysAs(sql`concat(first_name, ' ', last_name)`, { mode: 'virtual' }).$type<
string | null
>(),
fullName2: text('full_name2').generatedAlwaysAs(sql`concat(first_name, ' ', last_name)`, { mode: 'stored' }).$type<
string | null
>(),
upper: text('upper').generatedAlwaysAs(sql`upper(full_name)`, { mode: 'virtual' }).$type<string | null>(),
});

await db.execute(sql`drop table if exists ${usersTable}`);
await db.execute(sql`
create table ${usersTable} (
id serial,
first_name text,
last_name text,
full_name text generated always as (concat(first_name, ' ', last_name)) virtual,
full_name2 text generated always as (concat(first_name, ' ', last_name)) stored,
upper text generated always as (upper(full_name)) virtual
)
`);

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

const result = await db.select().from(usersTable);

Expect<
Equal<{
id: number;
firstName: string | null;
lastName: string | null;
fullName: string | null;
fullName2: string | null;
upper: string | null;
}[], typeof result>
>;

t.deepEqual(result, [
{ id: 1, firstName: null, lastName: null, fullName: null, fullName2: null, upper: null },
]);
});
2 changes: 1 addition & 1 deletion integration-tests/tests/pg-proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ test.after.always(async (t) => {

test.beforeEach(async (t) => {
const ctx = t.context;
await ctx.db.execute(sql`drop schema public cascade`);
await ctx.db.execute(sql`drop schema if exists public cascade`);
await ctx.db.execute(sql`create schema public`);
await ctx.db.execute(
sql`
Expand Down
Loading

0 comments on commit 00b1c05

Please sign in to comment.