From 413cbc79b38d16701ddd0738483f7e7c41326d7e Mon Sep 17 00:00:00 2001 From: Mateus Abelli Date: Fri, 10 Nov 2023 17:31:58 -0300 Subject: [PATCH] Initial refactoring --- src/Provider.ts | 141 ++++++++++++++++++++++++++++-------- src/methods/Create.ts | 40 +--------- src/methods/Update.ts | 40 ---------- src/utils/Database.ts | 74 +++++++++++-------- test/jest.setup.ts | 84 ++++++++++----------- test/methods/create.spec.ts | 7 +- test/methods/update.spec.ts | 22 +++--- 7 files changed, 214 insertions(+), 194 deletions(-) diff --git a/src/Provider.ts b/src/Provider.ts index bfdc6e3..33ff89a 100644 --- a/src/Provider.ts +++ b/src/Provider.ts @@ -1,45 +1,128 @@ -import { CreateParams, DeleteOneParams, GetListParams, GetManyParams, GetOneParams, UpdateParams } from "./interfaces/MethodParams"; +import { CreateParams, UpdateParams } from "./interfaces/MethodParams"; +import Database from "./utils/Database"; -import GetOne from "./methods/GetOne"; -import Create from "./methods/Create"; -import DeleteOne from "./methods/DeleteOne"; -import GetMany from "./methods/GetMany"; -import Update from "./methods/Update"; -import GetList from "./methods/GetList"; +import { Database as SQLiteDatabase } from "sql.js" class Provider { - private dbPath: string; + private dbArgs: string + private type: 'local' | 'inMemory' - constructor(dbPath: string) { - this.dbPath = dbPath; - } + constructor(type: 'local' | 'inMemory', dbArgs: string) { + this.dbArgs = dbArgs; + this.type = type; + } - create(params: CreateParams) { - return Create.build(this.dbPath, params) + private async dbConnect(): Promise { + try { + return await Database.init(this.dbArgs); + } catch (error) { + console.error("Error in dbConnect()", error); } + } - update(params: UpdateParams) { - return Update.build(this.dbPath, params) - } + public async create(params: CreateParams) { + const database = await this.dbConnect(); + const { resource, variables } = params; - deleteOne(params: DeleteOneParams) { - return DeleteOne.build(this.dbPath, params); - } + try { + if (!database) + throw new Error("Database connection not available."); - getOne(params: GetOneParams) { - return GetOne.build(this.dbPath, params); - } + const columns = Object.keys(variables).join(", ") + const values = Object.values(variables).map((value) => `'${value}'`).join(", ") - getMany(params: GetManyParams) { - return GetMany.build(this.dbPath, params); + let insertSql = `INSERT INTO ${resource} (${columns}) VALUES (${values})`; + let selectSql = `SELECT * FROM ${resource} WHERE (${columns}) = (${values})`; + + database.run(insertSql); + const data = database.exec(selectSql) + const dataColumns = data[0].columns + const dataValues = data[0].values[0] + + if (data) { + return { + data: Object.fromEntries( + dataColumns.map((col, index) => [col, dataValues[index]]), + ) + } + } else { + throw new Error(`Could not create data in ${resource}`); + } + } catch (error) { + console.error("Error in create()", error); + return { + data: {} + } + } finally { + database?.close() } + } + + public async update(params: UpdateParams) { + const database = await this.dbConnect(); + const { resource, id, variables } = params; + + try { + if (!database) + throw new Error("Database connection not available."); - getList(params: GetListParams) { - return GetList.build(this.dbPath, params); + const columns = Object.keys(variables || {}); + const values = Object.values(variables || {}); + + let updateQuery = ""; + + columns.forEach((column, index) => { + updateQuery += `${column} = '${values[index]}', `; + }); + + // Slices the last comma + updateQuery = updateQuery.slice(0, -2); + + const updateSql = `UPDATE ${resource} SET ${updateQuery} WHERE id = ${id}`; + const selectSql = `SELECT * FROM ${resource} WHERE id = ${id}`; + + database.run(updateSql); + const data = database.exec(selectSql) + const dataColumns = data[0].columns + const dataValues = data[0].values[0] + + if (data) { + return { + data: Object.fromEntries( + dataColumns.map((col, index) => [col, dataValues[index]]), + ) + } + } else { + throw new Error(`Could not update data in ${resource}`); + } + } catch (error) { + console.error("Error in update()", error); + return { + data: {} + } + } finally { + database?.close() } + } + + // deleteOne(params: DeleteOneParams) { + // return DeleteOne.build(this.dbPath, params); + // } + // + // getOne(params: GetOneParams) { + // return GetOne.build(this.dbPath, params); + // } + // + // getMany(params: GetManyParams) { + // return GetMany.build(this.dbPath, params); + // } + // + // getList(params: GetListParams) { + // return GetList.build(this.dbPath, params); + // } } -export const dataProvider = (dbPath: string) => { - return new Provider(dbPath); -}; +export const dataProvider = (type: 'local' | 'inMemory', dbArgs: string) => { + return new Provider(type, dbArgs); +} diff --git a/src/methods/Create.ts b/src/methods/Create.ts index eb6cfdd..80ed41b 100644 --- a/src/methods/Create.ts +++ b/src/methods/Create.ts @@ -5,46 +5,10 @@ import sqlite3 from "sqlite3"; import Database from "../utils/Database"; class Create { - private static dbInstance: Database; - private db: sqlite3.Database | null = null; + private constructor() { } - private constructor(dbPath: string) { - Create.dbInstance = Database.getInstance(dbPath); - this.db = Create.dbInstance.getDatabase(); - } - - static async build(dbPath: string, params: CreateParams): Promise { - const init = new Create(dbPath); - const { resource, variables } = params; - - try { - if (!init.db) - throw new Error("Database connection not available."); - - const columns = Object.keys(variables).join(", ") - const values = Object.values(variables).map((value) => `'${value}'`).join(", ") - - let insertSql = `INSERT INTO ${resource} (${columns}) VALUES (${values})`; - let selectSql = `SELECT * FROM ${resource} WHERE (${columns}) = (${values})`; - - const dbRun = promisify(init.db.run.bind(init.db)); - await dbRun(insertSql); - - const dbGet = promisify(init.db.get.bind(init.db)); - const data = await dbGet(selectSql) as any; + static async build(params: CreateParams, dbPath?: string, ): Promise { - if (data) - return { data } - else - throw new Error(`Could not create data in ${resource}`); - } catch (error) { - console.error("Error in create()", error); - return { - data: {} - } - } finally { - this.dbInstance.closeDatabase(); - } } } diff --git a/src/methods/Update.ts b/src/methods/Update.ts index c558f82..1acb112 100644 --- a/src/methods/Update.ts +++ b/src/methods/Update.ts @@ -14,46 +14,6 @@ class Update { } static async build(dbPath: string, params: UpdateParams): Promise { - const init = new Update(dbPath); - const { resource, id, variables } = params; - - try { - if (!init.db) - throw new Error("Database connection not available."); - - const columns = Object.keys(variables || {}); - const values = Object.values(variables || {}); - - let updateQuery = ""; - - columns.forEach((column, index) => { - updateQuery += `${column} = '${values[index]}', `; - }); - - // Slices the last comma - updateQuery = updateQuery.slice(0, -2); - - const updateSql = `UPDATE ${resource} SET ${updateQuery} WHERE id = ${id}`; - const selectSql = `SELECT * FROM ${resource} WHERE id = ${id}`; - - const dbRun = promisify(init.db.run.bind(init.db)); - await dbRun(updateSql); - - const dbGet = promisify(init.db.get.bind(init.db)); - const data = await dbGet(selectSql) as any; - - if (data) - return { data }; - else - throw new Error(`Could not update data in ${resource}`); - } catch (error) { - console.error("Error in update()", error); - return { - data: {} - } - } finally { - this.dbInstance.closeDatabase() - } } } diff --git a/src/utils/Database.ts b/src/utils/Database.ts index c3612b0..9c3691d 100644 --- a/src/utils/Database.ts +++ b/src/utils/Database.ts @@ -1,38 +1,52 @@ -import sqlite3 from "sqlite3"; +import initSqlJs, {Database as SQLiteDatabase} from "sql.js" +import fetch from "cross-fetch" class Database { - private static instance: Database | null = null; - private db: sqlite3.Database | null = null; + private constructor() { } - private constructor(dbPath: string) { - this.db = new sqlite3.Database(dbPath); - } - - public static getInstance(dbPath: string) { - if (this.instance === null) { - this.instance = new Database(dbPath); - } - return this.instance; - } + public static async init(dbPath: string): Promise { + const SQL = await initSqlJs({ + locateFile: () => "node_modules/sql.js/dist/sql-wasm.wasm" + }); - public getDatabase() { - if (this.db === null) { - throw new Error("Database connection is not established"); - } - return this.db; - } - - public closeDatabase() { - if (this.db !== null) { - this.db.close((error) => { - if (error) { - throw new Error(error.message); - } - }); - this.db = null; - Database.instance = null; - } + const dbFile = await fetch(dbPath).then(res => res.arrayBuffer()); + return new SQL.Database(new Uint8Array(dbFile)) } } +// class Database { +// private static instance: Database | null = null; +// private db: sqlite3.Database | null = null; +// +// private constructor(dbPath: string) { +// this.db = new sqlite3.Database(dbPath); +// } +// +// public static getInstance(dbPath: string) { +// if (this.instance === null) { +// this.instance = new Database(dbPath); +// } +// return this.instance; +// } +// +// public getDatabase() { +// if (this.db === null) { +// throw new Error("Database connection is not established"); +// } +// return this.db; +// } +// +// public closeDatabase() { +// if (this.db !== null) { +// this.db.close((error) => { +// if (error) { +// throw new Error(error.message); +// } +// }); +// this.db = null; +// Database.instance = null; +// } +// } +// } + export default Database; diff --git a/test/jest.setup.ts b/test/jest.setup.ts index f56a8d8..c03563d 100644 --- a/test/jest.setup.ts +++ b/test/jest.setup.ts @@ -1,45 +1,45 @@ import initSqlJs from "sql.js"; import fs from "fs"; -beforeAll(async () => { - const dbPath = "test.db"; - - try { - // Delete the database if it exists (DB must be disconnected elsewhere) - if (fs.existsSync(dbPath)) { - fs.rmSync(dbPath); - } - - // Create the database - const SQL = await initSqlJs({ - locateFile: () => "node_modules/sql.js/dist/sql-wasm.wasm" - }); - const db = new SQL.Database(); - - // Read the sql file - const sql = fs.readFileSync("./test.sql").toString(); - const sqlArray = sql.split(";"); - - // Create the tables - for (let i = 0; i < sqlArray.length - 1; i++) { - if (sqlArray[i].trim() === "") continue; - - try { - db.run(sqlArray[i]); - } catch (error) { - console.error("Error running queries: ", error); - } - } - - // Write the database - const data = db.export(); - fs.writeFileSync(dbPath, new Uint8Array(data)); - - // Close the connection - db.close(); - - } catch (error) { - console.error("Error in beforeAll: ", error); - } -}); - +// beforeAll(async () => { +// const dbPath = "test.db"; +// +// try { +// // Delete the database if it exists (DB must be disconnected elsewhere) +// if (fs.existsSync(dbPath)) { +// fs.rmSync(dbPath); +// } +// +// // Create the database +// const SQL = await initSqlJs({ +// locateFile: () => "node_modules/sql.js/dist/sql-wasm.wasm" +// }); +// const db = new SQL.Database(); +// +// // Read the sql file +// const sql = fs.readFileSync("./test.sql").toString(); +// const sqlArray = sql.split(";"); +// +// // Create the tables +// for (let i = 0; i < sqlArray.length - 1; i++) { +// if (sqlArray[i].trim() === "") continue; +// +// try { +// db.run(sqlArray[i]); +// } catch (error) { +// console.error("Error running queries: ", error); +// } +// } +// +// // Write the database +// const data = db.export(); +// fs.writeFileSync(dbPath, new Uint8Array(data)); +// +// // Close the connection +// db.close(); +// +// } catch (error) { +// console.error("Error in beforeAll: ", error); +// } +// }); +// diff --git a/test/methods/create.spec.ts b/test/methods/create.spec.ts index fceca53..4de212a 100644 --- a/test/methods/create.spec.ts +++ b/test/methods/create.spec.ts @@ -1,11 +1,10 @@ import dataProvider from "../../src"; describe("create", () => { - const apiUrl = "./test.db" - it("correct response", async () => { const response = await dataProvider( - apiUrl + "local", + "http://localhost:5173/test.db", ).create({ resource: "posts", variables: { id: 1001, title: "foo", category_id: 1 }, @@ -17,4 +16,4 @@ describe("create", () => { expect(data["title"]).toBe("foo"); expect(data["category_id"]).toBe(1); }); -}); \ No newline at end of file +}); diff --git a/test/methods/update.spec.ts b/test/methods/update.spec.ts index e3b4311..bb526f2 100644 --- a/test/methods/update.spec.ts +++ b/test/methods/update.spec.ts @@ -1,18 +1,18 @@ import dataProvider from "../../src"; describe("update", () => { - const apiUrl = "./test.db" - it("correct response", async () => { - const response = await dataProvider(apiUrl) - .update({ - resource: "posts", - id: "1", - variables: { - id: 1, - title: "foo", - }, - }); + const response = await dataProvider( + "local", + "http://localhost:5173/test.db" + ).update({ + resource: "posts", + id: "1", + variables: { + id: 1, + title: "foo", + }, + }); const { data } = response;