diff options
-rw-r--r-- | migrations/0003_empty_matthew_murdock.sql | 7 | ||||
-rw-r--r-- | migrations/meta/0003_snapshot.json | 225 | ||||
-rw-r--r-- | migrations/meta/_journal.json | 7 | ||||
-rw-r--r-- | src/db/schema.ts | 25 | ||||
-rw-r--r-- | src/index.tsx | 24 |
5 files changed, 273 insertions, 15 deletions
diff --git a/migrations/0003_empty_matthew_murdock.sql b/migrations/0003_empty_matthew_murdock.sql new file mode 100644 index 0000000..b626d41 --- /dev/null +++ b/migrations/0003_empty_matthew_murdock.sql @@ -0,0 +1,7 @@ +CREATE TABLE `users_groups` ( + `user_id` integer, + `group_id` integer, + PRIMARY KEY(`user_id`, `group_id`), + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action, + FOREIGN KEY (`group_id`) REFERENCES `groups`(`id`) ON UPDATE no action ON DELETE no action +); diff --git a/migrations/meta/0003_snapshot.json b/migrations/meta/0003_snapshot.json new file mode 100644 index 0000000..ab99d31 --- /dev/null +++ b/migrations/meta/0003_snapshot.json @@ -0,0 +1,225 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "f580093e-f5b1-402a-8da5-ae2d5bd2611e", + "prevId": "29e91293-4ebe-4039-a781-8609bf9505d5", + "tables": { + "users_groups": { + "name": "users_groups", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "users_groups_user_id_users_id_fk": { + "name": "users_groups_user_id_users_id_fk", + "tableFrom": "users_groups", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_groups_group_id_groups_id_fk": { + "name": "users_groups_group_id_groups_id_fk", + "tableFrom": "users_groups", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "users_groups_user_id_group_id_pk": { + "columns": [ + "user_id", + "group_id" + ], + "name": "users_groups_user_id_group_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groups": { + "name": "groups", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sessions": { + "name": "sessions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "uuid": { + "name": "uuid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_use": { + "name": "last_use", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + } + }, + "indexes": { + "sessions_uuid_unique": { + "name": "sessions_uuid_unique", + "columns": [ + "uuid" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "passkey": { + "name": "passkey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "passkey_id": { + "name": "passkey_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "users_name_unique": { + "name": "users_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "webauthn_challenges": { + "name": "webauthn_challenges", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "challenge": { + "name": "challenge", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +}
\ No newline at end of file diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index a434ab9..d3e9407 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1755543983317, "tag": "0002_red_morlun", "breakpoints": true + }, + { + "idx": 3, + "version": "6", + "when": 1755548102668, + "tag": "0003_empty_matthew_murdock", + "breakpoints": true } ] }
\ No newline at end of file diff --git a/src/db/schema.ts b/src/db/schema.ts index 339dfc0..affe19f 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -1,11 +1,15 @@ import { relations, sql } from "drizzle-orm"; -import { text, sqliteTable, integer } from "drizzle-orm/sqlite-core"; +import { text, sqliteTable, integer, primaryKey } from "drizzle-orm/sqlite-core"; export const groupTable = sqliteTable("groups", { id: integer().primaryKey(), name: text().notNull(), }); +export const groupRelations = relations(groupTable, ({ many }) => ({ + members: many(groupMembershipTable), +})); + export const userTable = sqliteTable("users", { id: integer().primaryKey(), name: text().unique().notNull(), @@ -13,6 +17,20 @@ export const userTable = sqliteTable("users", { passkeyId: text("passkey_id").notNull(), }); +export const userRelations = relations(userTable, ({ many }) => ({ + groups: many(groupMembershipTable), +})); + +export const groupMembershipTable = sqliteTable("users_groups", { + userId: integer("user_id").notNull().references(() => userTable.id), + groupId: integer("group_id").notNull().references(() => groupTable.id), +}, table => [primaryKey({ columns: [table.userId, table.groupId] })]); + +export const groupMembershipRelations = relations(groupMembershipTable, ({ one }) => ({ + group: one(groupTable, { fields: [groupMembershipTable.groupId], references: [groupTable.id] }), + user: one(userTable, { fields: [groupMembershipTable.userId], references: [userTable.id] }), +})); + export const sessionTable = sqliteTable("sessions", { id: integer().primaryKey(), uuid: text().unique().notNull(), @@ -21,10 +39,7 @@ export const sessionTable = sqliteTable("sessions", { }); export const sessionRelations = relations(sessionTable, ({ one }) => ({ - user: one(userTable, { - fields: [sessionTable.userId], - references: [userTable.id], - }), + user: one(userTable, { fields: [sessionTable.userId], references: [userTable.id] }), })); export const webauthnChallenges = sqliteTable("webauthn_challenges", { diff --git a/src/index.tsx b/src/index.tsx index 5975284..ea79902 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,22 +2,26 @@ import { serve } from "@hono/node-server"; import { Hono } from "hono"; import { createClient } from "@libsql/client"; import { drizzle } from "drizzle-orm/libsql"; -import { groupTable } from "./db/schema.js"; +import * as schema from "./db/schema.js"; import authRouter, { getSession, LoginForm } from "./auth.js"; +import { eq } from "drizzle-orm"; export const RP_ID = "localhost"; // "uneven.0m.nu"; export const ORIGIN = `http://${RP_ID}`; let app = new Hono(); -export let db = drizzle(createClient({ url: "file:data.db" })); +export let db = drizzle(createClient({ url: "file:data.db" }), { schema }); -async function Groups() { - let result = await db.select().from(groupTable).all(); +app.get("/groups", async c => { + let session = await getSession(c); + if (!session) return c.html("Must be logged in"); + let user = await db.query.userTable.findFirst({ where: user => eq(user.id, session.user.id), with: { groups: { with: { group: true } } } }); + if (!user) return c.html("Huh?"); - return <ul>{ - result.map(group => <li>{group.name}</li>) - }</ul>; -} + return c.html(<ul>{ + user.groups.map(group => <li>{group.group.name}</li>) + }</ul>); +}); app.get("/", c => c.html( <html lang="en"> @@ -31,8 +35,8 @@ app.get("/", c => c.html( </head> <body> <LoginForm /> - <Groups /> <button hx-get="/button" hx-swap="outerHTML">click me!</button> + <div hx-on-load="/groups" hx-swap="outerHTML" /> </body> </html> )); @@ -45,7 +49,7 @@ app.get("/button", async c => { hx-get="/button" hx-swap="outerHTML" style={{ backgroundColor: colors[Math.floor(Math.random() * colors.length)] }} - >disco button! {session.user.name}</button> + >disco button! {session?.user.name}</button> ); }); |