···2323bun ngrok
2424```
25252626+also if you haven't worked with your postgres table yet then push the schema with
2727+2828+```bash
2929+bun db:push
3030+```
3131+2632you also need to create a `.env` file with the following keys
27332834```bash
···3137SLACK_CHANNEL="C08KX2YNN87"
3238NODE_ENV="dev"
3339SENTRY_DSN="https://xxxxxx@xxxxxx.ingest.us.sentry.io/xxxx"
4040+DATABASE_URL="postgres://user:password@host:5432/table_name"
3441```
35423643## 📜 License
···11+import * as Sentry from "@sentry/bun";
12import { SlackApp } from "slack-edge";
33+import setup from "./features";
44+import { db } from "./libs/db";
25import { version, name } from "../package.json";
36const environment = process.env.NODE_ENV;
47const commit = (() => {
···1215 }
1316})();
14171515-import * as Sentry from "@sentry/bun";
1616-import setup from "./features";
1717-1818// Check required environment variables
1919const requiredVars = [
2020 "SLACK_BOT_TOKEN",
2121 "SLACK_SIGNING_SECRET",
2222 "SLACK_CHANNEL",
2323 "SENTRY_DSN",
2424+ "DATABASE_URL",
2425] as const;
2526const missingVars = requiredVars.filter((varName) => !process.env[varName]);
2627···8081 } milliseconds on version: ${version}@${commit}!\n\n----------------------------------\n`,
8182);
82838383-export { slackApp, slackClient, version, name, environment };
8484+export { slackApp, slackClient, version, name, environment, db };
+9-10
src/libs/db.ts
···11-import { drizzle } from "drizzle-orm/bun-sqlite";
22-import { Database } from "bun:sqlite";
11+import { drizzle } from "drizzle-orm/node-postgres";
22+import { Pool } from "pg";
33import * as schema from "./schema";
4455-// Use environment variable for the database path in production
66-const dbPath = process.env.DATABASE_PATH || "./local.db";
55+const pool = new Pool({
66+ connectionString: process.env.DATABASE_URL,
77+});
7888-// Create a SQLite database instance using Bun's built-in driver
99-const sqlite = new Database(dbPath);
99+export const db = drizzle(pool, { schema });
10101111-// Create a Drizzle instance with the database and schema
1212-export const db = drizzle(sqlite, { schema });
1111+// Set up triggers when initializing the database
1212+schema.setupTriggers(pool).catch(console.error);
13131414-// Export the sqlite instance and schema for use in other files
1515-export { sqlite, schema };
1414+export { pool, schema };
+32-6
src/libs/schema.ts
···11-import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
11+import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
22+import type { Pool } from "pg";
2334// Define the users table
44-export const users = sqliteTable("users", {
55- id: text("id").primaryKey(), // Slack user ID
66- hackernewsUsername: text("hackernews_username"),
77- createdAt: integer("created_at", { mode: "timestamp" }),
88- lastUpdatedAt: integer("last_updated_at", { mode: "timestamp" }),
55+export const users = pgTable("users", {
66+ id: text("id").primaryKey(),
77+ hackernewsUsername: text("hackernews_username"),
88+ createdAt: timestamp("created_at")
99+ .$defaultFn(() => new Date())
1010+ .notNull(),
1111+ updatedAt: timestamp("updated_at")
1212+ .$defaultFn(() => new Date())
1313+ .notNull(),
914});
1515+1616+export async function setupTriggers(pool: Pool) {
1717+ await pool.query(`
1818+ -- Create or replace the update function
1919+ CREATE OR REPLACE FUNCTION update_user_updated_at()
2020+ RETURNS TRIGGER AS $$
2121+ BEGIN
2222+ NEW.updated_at = NOW();
2323+ RETURN NEW;
2424+ END;
2525+ $$ LANGUAGE plpgsql;
2626+2727+ -- Drop trigger if exists and create a new one
2828+ DROP TRIGGER IF EXISTS update_user_updated_at_trigger ON users;
2929+3030+ CREATE TRIGGER update_user_updated_at_trigger
3131+ BEFORE UPDATE ON users
3232+ FOR EACH ROW
3333+ EXECUTE FUNCTION update_user_updated_at();
3434+ `);
3535+}