From d663c5cc6aacb12489200946fd0fc77b8358a0d6 Mon Sep 17 00:00:00 2001 From: Marshall Thompson Date: Sun, 21 May 2023 21:34:41 -0600 Subject: [PATCH] json proposal, currently only insert --- src/model.ts | 9 +++++++-- src/queryBuilder.ts | 18 +++++++++++++----- test/querybuilder.test.js | 40 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/model.ts b/src/model.ts index 6b2a1a5..e2e6d45 100644 --- a/src/model.ts +++ b/src/model.ts @@ -5,7 +5,7 @@ import type { GenerateQueryOptions } from "./queryBuilder.js"; /** * @typeParam T - The type of the model, which will be returned when using methods such as First() or All() */ -export class Model> { +export class Model { /** * @param options - The options for the model. All parameters except autoIncrement and uniqueKeys are required. * @param options.tableName - The name of the table to use. @@ -195,7 +195,10 @@ export class Model> { orReplace = false ): Promise>> { const qt = orReplace ? QueryType.INSERT_OR_REPLACE : QueryType.INSERT; - const statement = GenerateQuery(qt, this.tableName, { data }); + const statement = GenerateQuery(qt, this.tableName, { + data, + columns: this.columns, + }); return this.D1Orm.prepare(statement.query) .bind(...statement.bindings) .run(); @@ -315,7 +318,9 @@ export interface ModelColumn { type: DataTypes; notNull?: boolean; defaultValue?: unknown; + json?: boolean; } +export type ModelColumns = Record; /** * @enum {string} Aliases for DataTypes used in a {@link ModelColumn} definition. diff --git a/src/queryBuilder.ts b/src/queryBuilder.ts index 1ee07ad..d1fdb36 100644 --- a/src/queryBuilder.ts +++ b/src/queryBuilder.ts @@ -1,3 +1,5 @@ +import type { ModelColumns } from "./model"; + /** * @enum {string} - The type of the query */ @@ -32,6 +34,7 @@ export type GenerateQueryOptions = { orderBy?: OrderBy | OrderBy[]; data?: Partial; upsertOnlyUpdateData?: Partial; + columns?: ModelColumns; }; /** @@ -112,14 +115,19 @@ export function GenerateQuery( throw new Error("Must provide data to insert"); } const keys = []; + const values = []; for (const [key, value] of Object.entries(options.data)) { + const column = options.columns?.[key]; keys.push(key); - bindings.push(value); + if (column?.json) { + bindings.push(JSON.stringify(value)); + values.push(`json(?)`); + } else { + bindings.push(value); + values.push("?"); + } } - query += ` (${keys.join(", ")}) VALUES (${"?" - .repeat(keys.length) - .split("") - .join(", ")})`; + query += ` (${keys.join(", ")}) VALUES (${values.join(", ")})`; break; } case QueryType.UPDATE: { diff --git a/test/querybuilder.test.js b/test/querybuilder.test.js index cc312c7..84586fe 100644 --- a/test/querybuilder.test.js +++ b/test/querybuilder.test.js @@ -176,6 +176,26 @@ describe("Query Builder", () => { expect(statement.bindings[0]).to.equal(1); expect(statement.bindings[1]).to.equal("test"); }); + it("can write JSON with a column config", () => { + const address = { line1: '1000 N. Main St.', city: 'New York', state: 'NY' } + const statement = GenerateQuery(QueryType.INSERT, "test", { + data: { + id: 1, + name: "test", + address + }, + columns: { + address: { type: 'text', json: true } + } + }); + expect(statement.query).to.equal( + "INSERT INTO `test` (id, name, address) VALUES (?, ?, json(?))" + ); + expect(statement.bindings.length).to.equal(3); + expect(statement.bindings[0]).to.equal(1); + expect(statement.bindings[1]).to.equal("test"); + expect(statement.bindings[2]).to.equal(JSON.stringify(address)); + }); }); describe(QueryType.INSERT_OR_REPLACE, () => { it("should throw an error if no data is provided", () => { @@ -209,6 +229,26 @@ describe("Query Builder", () => { expect(statement.bindings[0]).to.equal(1); expect(statement.bindings[1]).to.equal("test"); }); + it("can write JSON with a column config", () => { + const address = { line1: '1000 N. Main St.', city: 'New York', state: 'NY' } + const statement = GenerateQuery(QueryType.INSERT_OR_REPLACE, "test", { + data: { + id: 1, + name: "test", + address + }, + columns: { + address: { type: 'text', json: true } + } + }); + expect(statement.query).to.equal( + "INSERT or REPLACE INTO `test` (id, name, address) VALUES (?, ?, json(?))" + ); + expect(statement.bindings.length).to.equal(3); + expect(statement.bindings[0]).to.equal(1); + expect(statement.bindings[1]).to.equal("test"); + expect(statement.bindings[2]).to.equal(JSON.stringify(address)); + }); }); describe(QueryType.UPDATE, () => { it("should throw an error if no data is provided", () => {