Skip to content

Commit

Permalink
fix(db): escape mysql queries
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Dec 26, 2024
1 parent 56fae44 commit 6e834d3
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 32 deletions.
66 changes: 51 additions & 15 deletions src/drivers/db0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,22 @@ export default defineDriver((opts: DB0DriverOptions) => {
return setupPromise;
};

const isMysql = opts.database.dialect === "mysql";

return {
name: DRIVER_NAME,
options: opts,
getInstance: () => opts.database,
async hasItem(key) {
await ensureTable();
const { rows } = await opts.database.sql<ResultSchema>/* sql */ `
const { rows } = isMysql
? await opts.database.sql<ResultSchema>/* sql */ `
SELECT EXISTS (
SELECT 1 FROM {${opts.tableName}}
WHERE \`key\` = ${key}
) AS \`value\`
`
: await opts.database.sql<ResultSchema>/* sql */ `
SELECT EXISTS (
SELECT 1 FROM {${opts.tableName}}
WHERE key = ${key}
Expand All @@ -60,23 +69,31 @@ export default defineDriver((opts: DB0DriverOptions) => {
},
getItem: async (key) => {
await ensureTable();
const { rows } = await opts.database.sql<ResultSchema>/* sql */ `
const { rows } = isMysql
? await opts.database.sql<ResultSchema>/* sql */ `
SELECT value FROM {${opts.tableName}} WHERE \`key\` = ${key}
`
: await opts.database.sql<ResultSchema>/* sql */ `
SELECT value FROM {${opts.tableName}} WHERE key = ${key}
`;
return rows?.[0]?.value ?? null;
},
getItemRaw: async (key) => {
await ensureTable();
const { rows } = await opts.database.sql<ResultSchema>/* sql */ `
const { rows } = isMysql
? await opts.database.sql<ResultSchema>/* sql */ `
SELECT \`blob\` as value FROM {${opts.tableName}} WHERE \`key\` = ${key}
`
: await opts.database.sql<ResultSchema>/* sql */ `
SELECT blob as value FROM {${opts.tableName}} WHERE key = ${key}
`;
return rows?.[0]?.value ?? null;
},
setItem: async (key, value) => {
await ensureTable();
if (opts.database.dialect === "mysql") {
if (isMysql) {
await opts.database.sql/* sql */ `
INSERT INTO {${opts.tableName}} (key, value, created_at, updated_at)
INSERT INTO {${opts.tableName}} (\`key\`, \`value\`, created_at, updated_at)
VALUES (${key}, ${value}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
ON DUPLICATE KEY UPDATE value = ${value}, updated_at = CURRENT_TIMESTAMP
`;
Expand All @@ -91,11 +108,12 @@ export default defineDriver((opts: DB0DriverOptions) => {
},
async setItemRaw(key, value) {
await ensureTable();
if (opts.database.dialect === "mysql") {
if (isMysql) {
const blob = Buffer.from(value) as any;
await opts.database.sql/* sql */ `
INSERT INTO {${opts.tableName}} (key, blob, created_at, updated_at)
VALUES (${key}, ${value}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
ON DUPLICATE KEY UPDATE blob = ${value}, updated_at = CURRENT_TIMESTAMP
INSERT INTO {${opts.tableName}} (\`key\`, \`blob\`, created_at, updated_at)
VALUES (${key}, ${blob}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
ON DUPLICATE KEY UPDATE \`blob\` = ${blob}, updated_at = CURRENT_TIMESTAMP
`;
} else {
await opts.database.sql/* sql */ `
Expand All @@ -108,13 +126,25 @@ export default defineDriver((opts: DB0DriverOptions) => {
},
removeItem: async (key) => {
await ensureTable();
await opts.database.sql/* sql */ `
if (isMysql) {
await opts.database.sql/* sql */ `
DELETE FROM {${opts.tableName}} WHERE \`key\`=${key}
`;
} else {
await opts.database.sql/* sql */ `
DELETE FROM {${opts.tableName}} WHERE key=${key}
`;
}
},
getMeta: async (key) => {
await ensureTable();
const { rows } = await opts.database.sql<ResultSchema>/* sql */ `
const { rows } = isMysql
? await opts.database.sql<ResultSchema>/* sql */ `
SELECT created_at, updated_at
FROM {${opts.tableName}}
WHERE \`key\` = ${key}
`
: await opts.database.sql<ResultSchema>/* sql */ `
SELECT created_at, updated_at
FROM {${opts.tableName}}
WHERE key = ${key}
Expand All @@ -127,7 +157,13 @@ export default defineDriver((opts: DB0DriverOptions) => {
},
getKeys: async (base = "") => {
await ensureTable();
const { rows } = await opts.database.sql<ResultSchema>/* sql */ `
const { rows } = isMysql
? await opts.database.sql<ResultSchema>/* sql */ `
SELECT \`key\`
FROM {${opts.tableName}}
WHERE \`key\` LIKE ${base + "%"}
`
: await opts.database.sql<ResultSchema>/* sql */ `
SELECT key
FROM {${opts.tableName}}
WHERE key LIKE ${base + "%"}
Expand Down Expand Up @@ -175,9 +211,9 @@ async function setupTable(opts: DB0DriverOptions) {
case "mysql": {
await opts.database.sql/* sql */ `
CREATE TABLE IF NOT EXISTS {${opts.tableName}} (
key VARCHAR(255) NOT NULL PRIMARY KEY,
value LONGTEXT,
blob BLOB,
\`key\` VARCHAR(255) NOT NULL PRIMARY KEY,
\`value\` LONGTEXT,
\`blob\` BLOB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
Expand Down
53 changes: 36 additions & 17 deletions test/drivers/db0.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,47 @@ const drivers = [
return createDatabase(pglite());
},
},
// docker run -it --rm --name mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=unstorage -p 3306:3306 mysql
// VITEST_MYSQL_URI=mysql://root:root@localhost/unstorage pnpm vitest test/drivers/db0.test.ts -t mysql
{
name: "mysql",
enabled: !!process.env.VITEST_MYSQL_URI,
async getDB() {
const mysql = await import("db0/connectors/mysql2").then(
(m) => m.default
);
return createDatabase(
mysql({
uri: process.env.VITEST_MYSQL_URI,
})
);
},
},
];

for (const driver of drivers) {
describe(`drivers: db0 - ${driver.name}`, async () => {
const db = await driver.getDB();
describe.skipIf(driver.enabled === false)(
`drivers: db0 - ${driver.name}`,
async () => {
const db = await driver.getDB();

afterAll(async () => {
await db.sql`DROP TABLE IF EXISTS unstorage`;
});
afterAll(async () => {
await db.sql`DROP TABLE IF EXISTS unstorage`;
});

testDriver({
driver: () => db0Driver({ database: db }),
additionalTests: (ctx) => {
it("meta", async () => {
await ctx.storage.setItem("meta:test", "test_data");
testDriver({
driver: () => db0Driver({ database: db }),
additionalTests: (ctx) => {
it("meta", async () => {
await ctx.storage.setItem("meta:test", "test_data");

expect(await ctx.storage.getMeta("meta:test")).toMatchObject({
birthtime: expect.any(Date),
mtime: expect.any(Date),
expect(await ctx.storage.getMeta("meta:test")).toMatchObject({
birthtime: expect.any(Date),
mtime: expect.any(Date),
});
});
});
},
});
});
},
});
}
);
}

0 comments on commit 6e834d3

Please sign in to comment.