diff --git a/src/Mutation-serialization.test.ts b/src/Mutation-serialization.test.ts
index 74b804d..144830f 100644
--- a/src/Mutation-serialization.test.ts
+++ b/src/Mutation-serialization.test.ts
@@ -11,13 +11,23 @@ describe("Mutation serialization and deserialization", () => {
expect(deserializedQuery.toSQL()).toEqual(originalQuery.toSQL());
});
- it("should handle round-trip JSON serialization and deserialization for an insert", () => {
+ it("should handle round-trip JSON serialization and deserialization for an insert with values", () => {
const originalQuery = Q.insert("table").values([{ foo: 123, bar: "baz" }]);
const jsonStr = JSON.stringify(originalQuery.toJSON());
const deserializedQuery = MutationBase.deserialize(jsonStr);
expect(deserializedQuery.toSQL()).toEqual(originalQuery.toSQL());
});
+ it("should handle round-trip JSON serialization and deserialization for an insert with select", () => {
+ const originalQuery = Q.insert("users_backup").select(
+ Q.select().addField("id").addField("username").from("users"),
+ ["id", "username"]
+ );
+ const jsonStr = JSON.stringify(originalQuery.toJSON());
+ const deserializedQuery = MutationBase.deserialize(jsonStr);
+ expect(deserializedQuery.toSQL()).toEqual(originalQuery.toSQL());
+ });
+
it("should handle round-trip JSON serialization and deserialization for an update", () => {
const originalQuery = Q.update("table")
.set({
diff --git a/src/Mutation.test.ts b/src/Mutation.test.ts
index 4855fb8..2e63602 100644
--- a/src/Mutation.test.ts
+++ b/src/Mutation.test.ts
@@ -9,7 +9,13 @@ describe("Mutation builder SQL", () => {
);
});
- it("should return SQL for insert", () => {
+ it("should fail with empty insert", () => {
+ expect(() => console.log(Q.insert("users").toSQL())).toThrow(
+ new Error("values or select must be set for insert query")
+ );
+ });
+
+ it("should return SQL for insert values", () => {
expect(
Q.insert("users")
.values([{ name: "John Doe", age: 42, isActive: true }])
@@ -19,6 +25,25 @@ describe("Mutation builder SQL", () => {
);
});
+ it("should generate SQL for insert select", () => {
+ expect(
+ Q.insert("users_backup").select(Q.select().from("users")).toSQL()
+ ).toEqual("INSERT INTO `users_backup` SELECT * FROM `users`");
+ });
+
+ it("should generate SQL for insert select with columns", () => {
+ expect(
+ Q.insert("users_backup")
+ .select(Q.select().addField("id").addField("username").from("users"), [
+ "id",
+ "username",
+ ])
+ .toSQL()
+ ).toEqual(
+ "INSERT INTO `users_backup` (`id`, `username`) SELECT `id`, `username` FROM `users`"
+ );
+ });
+
it("should return SQL for update", () => {
expect(
Q.update("users")
diff --git a/src/Mutation.ts b/src/Mutation.ts
index 85b860b..21257e9 100644
--- a/src/Mutation.ts
+++ b/src/Mutation.ts
@@ -1,7 +1,7 @@
import { Condition } from "./Condition";
import { Expression, ExpressionValue } from "./Expression";
import { ISQLFlavor } from "./Flavor";
-import { Q, Table } from "./Query";
+import { Q, SelectQuery, Table } from "./Query";
import { MySQLFlavor } from "./flavors/mysql";
import {
IMetadata,
@@ -103,7 +103,8 @@ export class InsertMutation
extends MutationBase
implements ISerializable, ISequelizable, IMetadata
{
- protected _values: RowRecord[] = [];
+ protected _values?: RowRecord[];
+ protected _selectWithColumns: [SelectQuery, string[] | undefined];
public getOperationType(): MetadataOperationType {
return MetadataOperationType.INSERT;
@@ -111,31 +112,48 @@ export class InsertMutation
public clone(): this {
const clone = super.clone();
- clone._values = [...this._values];
+ clone._values = this._values && [...this._values];
return clone;
}
values(values: RowRecordInput[]): this {
const clone = this.clone();
- clone._values = [...clone._values, ...values];
+ if (clone._selectWithColumns) throw new Error("select already set");
+ clone._values = [...(clone._values ?? []), ...values];
return clone;
}
- toSQL(flavor: ISQLFlavor = new MySQLFlavor()): string {
- if (this._values.length === 0) throw new Error("No values to insert");
+ select(query: SelectQuery, columns?: string[]): this {
+ const clone = this.clone();
+ if (clone._values) throw new Error("values already set");
+ clone._selectWithColumns = [query, columns];
+ return clone;
+ }
- return `INSERT INTO ${this._table.toSQL(flavor)} (${Object.keys(
- this._values[0]
- )
- .map((k) => flavor.escapeColumn(k))
- .join(", ")}) VALUES ${this._values
- .map(
- (value) =>
- `(${Object.values(value)
- .map((v) => flavor.escapeValue(v))
- .join(", ")})`
+ toSQL(flavor: ISQLFlavor = new MySQLFlavor()): string {
+ if (this._values) {
+ return `INSERT INTO ${this._table.toSQL(flavor)} (${Object.keys(
+ this._values[0]
)
- .join(", ")}`;
+ .map((k) => flavor.escapeColumn(k))
+ .join(", ")}) VALUES ${this._values
+ .map(
+ (value) =>
+ `(${Object.values(value)
+ .map((v) => flavor.escapeValue(v))
+ .join(", ")})`
+ )
+ .join(", ")}`;
+ }
+ if (this._selectWithColumns) {
+ const [query, columns] = this._selectWithColumns;
+ return `INSERT INTO ${this._table.toSQL(flavor)}${
+ columns
+ ? ` (${columns.map((k) => flavor.escapeColumn(k)).join(", ")})`
+ : ""
+ } ${query.toSQL(flavor)}`;
+ }
+ throw new Error("values or select must be set for insert query");
}
serialize(): string {
@@ -147,12 +165,22 @@ export class InsertMutation
type: OperationType.INSERT,
table: this._table.toJSON(),
values: this._values,
+ select: this._selectWithColumns && [
+ this._selectWithColumns[0].toJSON(),
+ this._selectWithColumns[1],
+ ],
};
}
- static fromJSON({ table, values }: any): InsertMutation {
+ static fromJSON({ table, values, select }: any): InsertMutation {
const insertMutation = new InsertMutation(table.source, table.alias);
insertMutation._values = values;
+ if (select) {
+ insertMutation._selectWithColumns = [
+ SelectQuery.fromJSON(select[0]),
+ select[1],
+ ];
+ }
return insertMutation;
}
}
diff --git a/src/stories/1_Query.stories.mdx b/src/stories/1_Query.stories.mdx
index d9cd3c3..d25a827 100644
--- a/src/stories/1_Query.stories.mdx
+++ b/src/stories/1_Query.stories.mdx
@@ -291,6 +291,22 @@ Q.insert('table').values([{foo:'blah'}]);
`}
/>
+### Insert select
+
+
+
+You can also specify column names:
+
+
+
### Update