diff --git a/src/Query.ts b/src/Query.ts index 53419b0..8e2b34c 100644 --- a/src/Query.ts +++ b/src/Query.ts @@ -11,6 +11,7 @@ import { import { ISQLFlavor } from "./Flavor"; import { AWSTimestreamFlavor } from "./flavors/aws-timestream"; import { MySQLFlavor } from "./flavors/mysql"; +import { SQLiteFlavor } from "./flavors/sqlite"; import { Fn } from "./Function"; import { IMetadata, @@ -24,6 +25,7 @@ import { DeleteMutation, InsertMutation, UpdateMutation } from "./Mutation"; const flavors = { mysql: new MySQLFlavor(), awsTimestream: new AWSTimestreamFlavor(), + sqlite: new SQLiteFlavor(), }; type TableSource = string | SelectQuery; diff --git a/src/flavors/awsdefault.test.ts b/src/flavors/awsdefault.test.ts new file mode 100644 index 0000000..7416a38 --- /dev/null +++ b/src/flavors/awsdefault.test.ts @@ -0,0 +1,29 @@ +import { Cond } from "../Condition"; +import { Fn } from "../Function"; +import { Q } from "../Query"; +import { DefaultFlavor } from "./default"; + +const flavor = new DefaultFlavor(); + +describe("Default Flavor flavor", () => { + it("should render correct select", () => { + const query = Q.select() + .addField("foo", "blah") + .addField(Fn.max("foo"), "blahMax") + .from("table") + .where(Cond.equal("foo", 123)) + .where(Cond.equal("blah", "hello")) + .orderBy("foo", "DESC") + .limit(100) + .offset(2); + expect(query.toSQL(flavor)).toEqual( + 'SELECT `foo` AS `blah`, MAX(`foo`) AS `blahMax` FROM `table` WHERE `foo` = 123 AND `blah` = "hello" ORDER BY `foo` DESC LIMIT 100 OFFSET 2' + ); + }); + it("should render correct update", () => { + const query = Q.update("table").set({ foo: `'aa'xx"` }); + expect(query.toSQL(flavor)).toEqual( + 'UPDATE `table` SET `foo` = "\'aa\'xx"""' + ); + }); +}); diff --git a/src/flavors/default.ts b/src/flavors/default.ts index e0f2965..d68d654 100644 --- a/src/flavors/default.ts +++ b/src/flavors/default.ts @@ -50,7 +50,10 @@ export class DefaultFlavor implements ISQLFlavor { }`; } if (typeof value === "string") { - return `${this.stringQuotes}${value}${this.stringQuotes}`; + return `${this.stringQuotes}${value.replace( + new RegExp(`${this.stringQuotes}`, "g"), + `${this.stringQuotes}${this.stringQuotes}` + )}${this.stringQuotes}`; } return `${value}`; } diff --git a/src/flavors/sqlite.test.ts b/src/flavors/sqlite.test.ts new file mode 100644 index 0000000..ab93876 --- /dev/null +++ b/src/flavors/sqlite.test.ts @@ -0,0 +1,29 @@ +import { Cond } from "../Condition"; +import { Fn } from "../Function"; +import { Q } from "../Query"; +import { DefaultFlavor } from "./default"; + +const flavor = Q.flavors.sqlite; + +describe("SQLite Flavor flavor", () => { + it("should render correct select", () => { + const query = Q.select() + .addField("foo", "blah") + .addField(Fn.max("foo"), "blahMax") + .from("table") + .where(Cond.equal("foo", 123)) + .where(Cond.equal("blah", "hello")) + .orderBy("foo", "DESC") + .limit(100) + .offset(2); + expect(query.toSQL(flavor)).toEqual( + "SELECT `foo` AS `blah`, MAX(`foo`) AS `blahMax` FROM `table` WHERE `foo` = 123 AND `blah` = 'hello' ORDER BY `foo` DESC LIMIT 100 OFFSET 2" + ); + }); + it("should render correct update", () => { + const query = Q.update("table").set({ foo: `'aa'xx"` }); + expect(query.toSQL(flavor)).toEqual( + "UPDATE `table` SET `foo` = '''aa''xx\"'" + ); + }); +});