diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..42011c1 --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,12 @@ +import type { Config } from "drizzle-kit"; +import "dotenv/config"; + +export default { + schema: "./playground/database/schema/", + out: "./playground/database/migrations/", + dialect: "sqlite", + verbose: true, + dbCredentials: { + url: "./playground/database/sqlite.db", + }, +} satisfies Config; diff --git a/package.json b/package.json index cdff5ca..48818da 100644 --- a/package.json +++ b/package.json @@ -38,10 +38,16 @@ "lint": "eslint .", "test": "vitest run", "test:watch": "vitest watch", - "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit" + "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit", + "db:studio": "drizzle-kit studio", + "db:dev-push": "drizzle-kit push", + "db:make-migration": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate" }, "dependencies": { "@nuxt/kit": "^3.11.2", + "better-sqlite3": "^11.0.0", + "drizzle-orm": "^0.31.2", "lodash-es": "^4.17.21", "zod": "^3.23.8" }, @@ -55,6 +61,7 @@ "@types/node": "^20.12.11", "autoprefixer": "^10.4.19", "changelogen": "^0.5.5", + "drizzle-kit": "^0.22.6", "eslint": "^9.2.0", "eslint-config-prettier": "^9.1.0", "nuxt": "^3.11.2", diff --git a/playground/database/index.ts b/playground/database/index.ts new file mode 100644 index 0000000..39c9bd3 --- /dev/null +++ b/playground/database/index.ts @@ -0,0 +1,13 @@ +import { drizzle, BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; +import Database from "better-sqlite3"; +import registrations from "./schema/registrations"; + +const sqlite = new Database("./playground/database/sqlite.db"); + +const config = { + schema: { registrations }, + fileMustExist: true, +}; +const db: BetterSQLite3Database = drizzle(sqlite, config); + +export default db; diff --git a/playground/database/migrations/0000_deep_naoko.sql b/playground/database/migrations/0000_deep_naoko.sql new file mode 100644 index 0000000..104588b --- /dev/null +++ b/playground/database/migrations/0000_deep_naoko.sql @@ -0,0 +1,8 @@ +CREATE TABLE `registrations` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `name` text(255), + `email` text(255), + `created_at` text DEFAULT (CURRENT_TIMESTAMP) +); +--> statement-breakpoint +CREATE UNIQUE INDEX `registrations_email_unique` ON `registrations` (`email`); \ No newline at end of file diff --git a/playground/database/migrations/meta/0000_snapshot.json b/playground/database/migrations/meta/0000_snapshot.json new file mode 100644 index 0000000..39ce030 --- /dev/null +++ b/playground/database/migrations/meta/0000_snapshot.json @@ -0,0 +1,63 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "3e843d89-52e3-4405-a94d-8b135dbf2d3f", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "registrations": { + "name": "registrations", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "registrations_email_unique": { + "name": "registrations_email_unique", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/playground/database/migrations/meta/_journal.json b/playground/database/migrations/meta/_journal.json new file mode 100644 index 0000000..6c12a53 --- /dev/null +++ b/playground/database/migrations/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1717878275568, + "tag": "0000_deep_naoko", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/playground/database/migrations/run.ts b/playground/database/migrations/run.ts new file mode 100755 index 0000000..a4a9fff --- /dev/null +++ b/playground/database/migrations/run.ts @@ -0,0 +1,30 @@ +import { migrate } from "drizzle-orm/mysql2/migrator"; +import mysql from "mysql2/promise"; +import { drizzle } from "drizzle-orm/mysql2"; + +// get the database configuration from dotenv +import "dotenv/config"; + +async function run() { + const connection = await mysql.createConnection({ + host: process.env.DB_HOST, + port: process.env.DB_PORT ?? 3306, + database: process.env.DB_DATABASE, + user: process.env.DB_USERNAME, + password: process.env.DB_PASSWORD, + }); + const db = drizzle(connection); + + // This will run migrations on the database, skipping the ones already applied + await migrate(db, { migrationsFolder: "./database/migrations" }); + // Don't forget to close the connection, otherwise the script will hang + await connection.end(); +} + +run() + .catch((e) => { + console.error("Migrations failed"); + console.error(e); + process.exit(1); + }) + .then(() => console.log("Migrations ran successfully")); diff --git a/playground/database/schema/registrations.ts b/playground/database/schema/registrations.ts new file mode 100644 index 0000000..8e13d7a --- /dev/null +++ b/playground/database/schema/registrations.ts @@ -0,0 +1,9 @@ +import { sql } from "drizzle-orm"; +import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core"; + +export default sqliteTable("registrations", { + id: integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }), + name: text("name", { length: 255 }), + email: text("email", { length: 255 }).unique(), + createdAt: text("created_at").default(sql`(CURRENT_TIMESTAMP)`), +}); diff --git a/playground/database/sqlite.db b/playground/database/sqlite.db new file mode 100644 index 0000000..cf488b8 Binary files /dev/null and b/playground/database/sqlite.db differ diff --git a/playground/pages/register-precog.vue b/playground/pages/register-precog.vue index 7f8146e..8f9a171 100644 --- a/playground/pages/register-precog.vue +++ b/playground/pages/register-precog.vue @@ -2,15 +2,17 @@ const entries = ref([]); const form = usePrecognitionForm("post", "/api/register-precog", { + name: "", email: "", age: null, }); +const { data: registrations, refresh } = await useFetch("/api/registrations"); + const submitForm = async () => { await form.submit({ - onSuccess: (response) => { - console.log("onSuccess callback", response); - entries.value.push(response._data); + onSuccess: () => { + refresh(); }, }); }; @@ -20,6 +22,15 @@ const submitForm = async () => {
+ {
{{ form }}
-
-      
Entries
-
- {{ entry.description }} +
Registrations
+
+
{{ registration.name }}
+
{{ registration.email }}
diff --git a/playground/pages/register.vue b/playground/pages/register.vue index 377c9d1..d8af06b 100644 --- a/playground/pages/register.vue +++ b/playground/pages/register.vue @@ -1,14 +1,16 @@