this repo has no description
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: move to pg

+102 -58
+7
README.md
··· 23 23 bun ngrok 24 24 ``` 25 25 26 + also if you haven't worked with your postgres table yet then push the schema with 27 + 28 + ```bash 29 + bun db:push 30 + ``` 31 + 26 32 you also need to create a `.env` file with the following keys 27 33 28 34 ```bash ··· 31 37 SLACK_CHANNEL="C08KX2YNN87" 32 38 NODE_ENV="dev" 33 39 SENTRY_DSN="https://xxxxxx@xxxxxx.ingest.us.sentry.io/xxxx" 40 + DATABASE_URL="postgres://user:password@host:5432/table_name" 34 41 ``` 35 42 36 43 ## 📜 License
+3 -2
bun.lock
··· 5 5 "name": "takes", 6 6 "dependencies": { 7 7 "@sentry/bun": "^9.10.1", 8 + "@types/pg": "^8.11.13", 8 9 "bottleneck": "^2.19.5", 9 10 "colors": "^1.4.0", 10 - "drizzle-kit": "^0.31.0", 11 11 "drizzle-orm": "^0.42.0", 12 + "pg": "^8.15.1", 12 13 "slack-edge": "^1.3.7", 13 14 "yaml": "^2.7.1", 14 15 }, 15 16 "devDependencies": { 16 17 "@types/bun": "latest", 17 - "@types/pg": "^8.11.13", 18 + "drizzle-kit": "^0.31.0", 18 19 }, 19 20 "peerDependencies": { 20 21 "typescript": "^5",
+15 -6
drizzle.config.ts
··· 1 1 import type { Config } from "drizzle-kit"; 2 2 3 + // Parse connection string from environment variable 4 + const databaseUrl = process.env.DATABASE_URL || ""; 5 + const url = new URL(databaseUrl); 6 + 3 7 export default { 4 - schema: "./src/libs/schema.ts", 5 - out: "./migrations", 6 - dialect: "sqlite", 7 - dbCredentials: { 8 - url: "./local.db", 9 - }, 8 + schema: "./src/libs/schema.ts", 9 + out: "./migrations", 10 + dialect: "postgresql", 11 + dbCredentials: { 12 + host: url.hostname, 13 + port: Number.parseInt(url.port), 14 + user: url.username, 15 + password: url.password, 16 + database: url.pathname.slice(1), 17 + ssl: url.searchParams.get("sslmode") === "require", 18 + }, 10 19 } satisfies Config;
+31 -30
package.json
··· 1 1 { 2 - "name": "hn-alerts", 3 - "description": "be pinged", 4 - "version": "0.0.0", 5 - "module": "src/index.ts", 6 - "type": "module", 7 - "private": true, 8 - "scripts": { 9 - "dev": "bun run --watch src/index.ts", 10 - "ngrok": "ngrok http 3000 --domain=casual-renewing-reptile.ngrok-free.app", 11 - "db:generate": "drizzle-kit generate", 12 - "db:migrate": "drizzle-kit migrate", 13 - "db:studio": "drizzle-kit studio --port 3001", 14 - "db:push": "drizzle-kit push" 15 - }, 16 - "devDependencies": { 17 - "@types/bun": "latest", 18 - "@types/pg": "^8.11.13" 19 - }, 20 - "peerDependencies": { 21 - "typescript": "^5" 22 - }, 23 - "dependencies": { 24 - "@sentry/bun": "^9.10.1", 25 - "bottleneck": "^2.19.5", 26 - "colors": "^1.4.0", 27 - "drizzle-kit": "^0.31.0", 28 - "drizzle-orm": "^0.42.0", 29 - "slack-edge": "^1.3.7", 30 - "yaml": "^2.7.1" 31 - } 2 + "name": "hn-alerts", 3 + "description": "be pinged", 4 + "version": "0.0.0", 5 + "module": "src/index.ts", 6 + "type": "module", 7 + "private": true, 8 + "scripts": { 9 + "dev": "bun run --watch src/index.ts", 10 + "ngrok": "ngrok http 3000 --domain=casual-renewing-reptile.ngrok-free.app", 11 + "db:generate": "drizzle-kit generate", 12 + "db:migrate": "drizzle-kit migrate", 13 + "db:studio": "drizzle-kit studio --port 3001", 14 + "db:push": "drizzle-kit push" 15 + }, 16 + "devDependencies": { 17 + "@types/bun": "latest", 18 + "drizzle-kit": "^0.31.0" 19 + }, 20 + "peerDependencies": { 21 + "typescript": "^5" 22 + }, 23 + "dependencies": { 24 + "@sentry/bun": "^9.10.1", 25 + "@types/pg": "^8.11.13", 26 + "bottleneck": "^2.19.5", 27 + "colors": "^1.4.0", 28 + "drizzle-orm": "^0.42.0", 29 + "pg": "^8.15.1", 30 + "slack-edge": "^1.3.7", 31 + "yaml": "^2.7.1" 32 + } 32 33 }
+5 -4
src/index.ts
··· 1 + import * as Sentry from "@sentry/bun"; 1 2 import { SlackApp } from "slack-edge"; 3 + import setup from "./features"; 4 + import { db } from "./libs/db"; 2 5 import { version, name } from "../package.json"; 3 6 const environment = process.env.NODE_ENV; 4 7 const commit = (() => { ··· 12 15 } 13 16 })(); 14 17 15 - import * as Sentry from "@sentry/bun"; 16 - import setup from "./features"; 17 - 18 18 // Check required environment variables 19 19 const requiredVars = [ 20 20 "SLACK_BOT_TOKEN", 21 21 "SLACK_SIGNING_SECRET", 22 22 "SLACK_CHANNEL", 23 23 "SENTRY_DSN", 24 + "DATABASE_URL", 24 25 ] as const; 25 26 const missingVars = requiredVars.filter((varName) => !process.env[varName]); 26 27 ··· 80 81 } milliseconds on version: ${version}@${commit}!\n\n----------------------------------\n`, 81 82 ); 82 83 83 - export { slackApp, slackClient, version, name, environment }; 84 + export { slackApp, slackClient, version, name, environment, db };
+9 -10
src/libs/db.ts
··· 1 - import { drizzle } from "drizzle-orm/bun-sqlite"; 2 - import { Database } from "bun:sqlite"; 1 + import { drizzle } from "drizzle-orm/node-postgres"; 2 + import { Pool } from "pg"; 3 3 import * as schema from "./schema"; 4 4 5 - // Use environment variable for the database path in production 6 - const dbPath = process.env.DATABASE_PATH || "./local.db"; 5 + const pool = new Pool({ 6 + connectionString: process.env.DATABASE_URL, 7 + }); 7 8 8 - // Create a SQLite database instance using Bun's built-in driver 9 - const sqlite = new Database(dbPath); 9 + export const db = drizzle(pool, { schema }); 10 10 11 - // Create a Drizzle instance with the database and schema 12 - export const db = drizzle(sqlite, { schema }); 11 + // Set up triggers when initializing the database 12 + schema.setupTriggers(pool).catch(console.error); 13 13 14 - // Export the sqlite instance and schema for use in other files 15 - export { sqlite, schema }; 14 + export { pool, schema };
+32 -6
src/libs/schema.ts
··· 1 - import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core"; 1 + import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; 2 + import type { Pool } from "pg"; 2 3 3 4 // Define the users table 4 - export const users = sqliteTable("users", { 5 - id: text("id").primaryKey(), // Slack user ID 6 - hackernewsUsername: text("hackernews_username"), 7 - createdAt: integer("created_at", { mode: "timestamp" }), 8 - lastUpdatedAt: integer("last_updated_at", { mode: "timestamp" }), 5 + export const users = pgTable("users", { 6 + id: text("id").primaryKey(), 7 + hackernewsUsername: text("hackernews_username"), 8 + createdAt: timestamp("created_at") 9 + .$defaultFn(() => new Date()) 10 + .notNull(), 11 + updatedAt: timestamp("updated_at") 12 + .$defaultFn(() => new Date()) 13 + .notNull(), 9 14 }); 15 + 16 + export async function setupTriggers(pool: Pool) { 17 + await pool.query(` 18 + -- Create or replace the update function 19 + CREATE OR REPLACE FUNCTION update_user_updated_at() 20 + RETURNS TRIGGER AS $$ 21 + BEGIN 22 + NEW.updated_at = NOW(); 23 + RETURN NEW; 24 + END; 25 + $$ LANGUAGE plpgsql; 26 + 27 + -- Drop trigger if exists and create a new one 28 + DROP TRIGGER IF EXISTS update_user_updated_at_trigger ON users; 29 + 30 + CREATE TRIGGER update_user_updated_at_trigger 31 + BEFORE UPDATE ON users 32 + FOR EACH ROW 33 + EXECUTE FUNCTION update_user_updated_at(); 34 + `); 35 + }