From 0fc6b1b8a8926b17011745cc08575032a07b7246 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Tue, 27 Sep 2022 15:49:41 -0500 Subject: [PATCH] DB things --- db-migrations.ts | 13 ++++++++++++ db.ts | 25 ++++++++++++++++++++++ fresh.gen.ts | 10 +++++---- routes/_middleware.ts | 2 +- routes/note.tsx | 48 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 db-migrations.ts create mode 100644 db.ts create mode 100644 routes/note.tsx diff --git a/db-migrations.ts b/db-migrations.ts new file mode 100644 index 0000000..ac39c29 --- /dev/null +++ b/db-migrations.ts @@ -0,0 +1,13 @@ +import { query } from "./db.ts"; + +await query(` + create extension if not exists "uuid-ossp"; + + drop table if exists notes; + create table if not exists notes ( + id uuid primary key default uuid_generate_v4(), + content text not null, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() + ); +`); diff --git a/db.ts b/db.ts new file mode 100644 index 0000000..2262e82 --- /dev/null +++ b/db.ts @@ -0,0 +1,25 @@ +import * as postgres from "https://deno.land/x/postgres@v0.16.1/mod.ts"; +import { type QueryArguments } from "https://deno.land/x/postgres@v0.16.1/query/query.ts?s=QueryArguments"; + +export { type QueryObjectResult } from "https://deno.land/x/postgres@v0.16.1/query/query.ts?s=QueryArguments"; + +const databaseUrl = Deno.env.get("DATABASE_URL") || + "postgresql://danielflanagan:@127.0.0.1:5432/lyricscreen"; +const pool = new postgres.Pool(databaseUrl, 3, true); + +export async function query(sql: string, ...args: QueryArguments[]) { + let result = null; + try { + const connection = await pool.connect(); + try { + result = await connection.queryObject(sql, ...args); + } catch (err) { + console.error("Error querying database:", err); + } finally { + connection.release(); + } + } catch (err) { + console.error("Error connecting to database:", err); + } + return result; +} diff --git a/fresh.gen.ts b/fresh.gen.ts index 125a01b..98be1ea 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -13,8 +13,9 @@ import * as $6 from "./routes/api/random-uuid.ts"; import * as $7 from "./routes/countdown.tsx"; import * as $8 from "./routes/github/[username].tsx"; import * as $9 from "./routes/index.tsx"; -import * as $10 from "./routes/route-config-example.tsx"; -import * as $11 from "./routes/search.tsx"; +import * as $10 from "./routes/note.tsx"; +import * as $11 from "./routes/route-config-example.tsx"; +import * as $12 from "./routes/search.tsx"; import * as $$0 from "./islands/Countdown.tsx"; import * as $$1 from "./islands/Counter.tsx"; @@ -30,8 +31,9 @@ const manifest = { "./routes/countdown.tsx": $7, "./routes/github/[username].tsx": $8, "./routes/index.tsx": $9, - "./routes/route-config-example.tsx": $10, - "./routes/search.tsx": $11, + "./routes/note.tsx": $10, + "./routes/route-config-example.tsx": $11, + "./routes/search.tsx": $12, }, islands: { "./islands/Countdown.tsx": $$0, diff --git a/routes/_middleware.ts b/routes/_middleware.ts index a66390e..70f2013 100644 --- a/routes/_middleware.ts +++ b/routes/_middleware.ts @@ -10,6 +10,6 @@ export async function handler( ) { ctx.state.data = "myData"; const resp = await ctx.next(); - resp.headers.set("server", "fresh server"); + if (resp) resp.headers.set("server", "fresh server"); return resp; } diff --git a/routes/note.tsx b/routes/note.tsx new file mode 100644 index 0000000..f77ac67 --- /dev/null +++ b/routes/note.tsx @@ -0,0 +1,48 @@ +import { Handlers, PageProps } from "$fresh/server.ts"; +import { query, type QueryObjectResult } from "../db.ts"; + +interface Note { + id: string; + created_at: Date; + content: string; +} + +export const handler: Handlers = { + async GET(request, context) { + console.debug({ request, context }); + const result = await query("select * from notes"); + if (result == null) throw "unable to fetch from database"; + const notes = result.rows; + console.debug(notes); + return await context.render(notes); + }, + async POST(request, context) { + console.debug({ request, context }); + if (request.headers.get("content-type") != "application/json") { + throw "content-type must be application/json"; + } + const body = await request.json(); + console.log({ body }); + if (!("content" in body)) { + throw "no content field present in body"; + } + const result = await query( + "insert into notes (content) values ($1) returning id", + body.content, + ); + if (result == null) throw "failed to fetch notes"; + const { rows: [{ id }] } = result as QueryObjectResult; + console.debug(id); + }, +}; + +export default function Page({ data }: PageProps) { + return ( +
+

Yo!

+
+        {JSON.stringify(data, null, 2)}
+      
+
+ ); +}