start of db management and tables
All checks were successful
Code quality checks / biome (push) Successful in 9s

This commit is contained in:
creations 2025-05-01 17:16:36 -04:00
parent ab81475ad6
commit d066cc9fed
Signed by: creations
GPG key ID: 8F553AA4320FC711
6 changed files with 112 additions and 18 deletions

View file

@ -14,11 +14,13 @@ export const redisTtl: number = process.env.REDIS_TTL
export const cassandra: CassandraConfig = { export const cassandra: CassandraConfig = {
host: process.env.CASSANDRA_HOST || "localhost", host: process.env.CASSANDRA_HOST || "localhost",
port: Number.parseInt(process.env.CASSANDRA_PORT || "9042", 10), port: Number.parseInt(process.env.CASSANDRA_PORT || "9042", 10),
keyspace: process.env.CASSANDRA_KEYSPACE || "", keyspace: process.env.CASSANDRA_KEYSPACE || "void_db",
username: process.env.CASSANDRA_USERNAME || "", username: process.env.CASSANDRA_USERNAME || "",
password: process.env.CASSANDRA_PASSWORD || "", password: process.env.CASSANDRA_PASSWORD || "",
datacenter: process.env.CASSANDRA_DATACENTER || "", datacenter: process.env.CASSANDRA_DATACENTER || "",
contactPoints: (process.env.CASSANDRA_CONTACT_POINTS || "localhost").split(","), contactPoints: (process.env.CASSANDRA_CONTACT_POINTS || "localhost").split(
",",
),
authEnabled: process.env.CASSANDRA_AUTH_ENABLED === "false", authEnabled: process.env.CASSANDRA_AUTH_ENABLED === "false",
}; };

68
config/setup/index.ts Normal file
View file

@ -0,0 +1,68 @@
import { readdir } from "node:fs/promises";
import { extname, join, resolve } from "node:path";
import { pathToFileURL } from "node:url";
import {
cassandra as cassandraConfig,
verifyRequiredVariables,
} from "@config/environment";
import { logger } from "@creations.works/logger";
import { CassandraService } from "@lib/cassandra";
async function setup(): Promise<void> {
verifyRequiredVariables();
await CassandraService.connect({ withKeyspace: false });
const client = CassandraService.getClient();
const keyspace = cassandraConfig.keyspace;
if (!keyspace) {
logger.error("No Cassandra keyspace configured in environment.");
process.exit(1);
}
await client.execute(`
CREATE KEYSPACE IF NOT EXISTS ${keyspace}
WITH REPLICATION = {
'class': 'SimpleStrategy',
'replication_factor': 1
};
`);
await client.execute(`USE ${keyspace}`);
logger.info(`Keyspace "${keyspace}" ensured and selected.`);
const tablesDir = resolve("config", "setup", "tables");
const files = await readdir(tablesDir);
for (const file of files) {
if (extname(file) !== ".ts") continue;
const modulePath = pathToFileURL(join(tablesDir, file)).href;
const mod = await import(modulePath);
if (typeof mod.default === "function") {
await mod.default();
logger.info(`Ran default export from ${file}`);
} else if (typeof mod.createTable === "function") {
await mod.createTable();
logger.info(`Ran createTable from ${file}`);
} else {
logger.warn(`No callable export found in ${file}`);
}
}
logger.info("Setup complete.");
}
setup()
.catch((error: Error) => {
logger.error(error);
process.exit(1);
})
.finally(() => {
CassandraService.shutdown().catch((error: Error) => {
logger.error(["Error shutting down Cassandra client:", error as Error]);
});
process.exit(0);
});

View file

@ -0,0 +1,17 @@
import { CassandraService } from "@lib/cassandra";
export async function createTable() {
await CassandraService.getClient().execute(`
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
name TEXT,
display_name TEXT,
email TEXT,
password TEXT,
avatar_url TEXT,
is_verified BOOLEAN,
created_at TIMESTAMP,
updated_at TIMESTAMP
);
`);
}

View file

@ -7,7 +7,9 @@
"dev": "bun run --hot src/index.ts --dev", "dev": "bun run --hot src/index.ts --dev",
"lint": "bunx biome check", "lint": "bunx biome check",
"lint:fix": "bunx biome check --fix", "lint:fix": "bunx biome check --fix",
"cleanup": "rm -rf logs node_modules bun.lockdb" "cleanup": "rm -rf logs node_modules bun.lockdb",
"setup": "bun run config/setup/index.ts"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.2.11", "@types/bun": "^1.2.11",

View file

@ -1,7 +1,7 @@
import { CassandraService } from "@/lib/cassandra";
import { serverHandler } from "@/server"; import { serverHandler } from "@/server";
import { verifyRequiredVariables } from "@config/environment"; import { verifyRequiredVariables } from "@config/environment";
import { logger } from "@creations.works/logger"; import { logger } from "@creations.works/logger";
import { CassandraService } from "@lib/cassandra";
import { redis } from "bun"; import { redis } from "bun";
async function main(): Promise<void> { async function main(): Promise<void> {

View file

@ -9,26 +9,31 @@ class CassandraService {
public static getClient(): Client { public static getClient(): Client {
if (!CassandraService.instance) { if (!CassandraService.instance) {
CassandraService.instance = new Client({ logger.error("Cassandra client is not initialized somehow?");
contactPoints: config.contactPoints, process.exit(1);
localDataCenter: config.datacenter,
keyspace: config.keyspace,
authProvider: config.authEnabled
? new auth.PlainTextAuthProvider(config.username, config.password)
: undefined,
protocolOptions: {
port: config.port,
},
});
} }
return CassandraService.instance; return CassandraService.instance;
} }
public static async connect(): Promise<void> { public static async connect({ withKeyspace = true } = {}): Promise<void> {
if (CassandraService.instance) return;
const client = new Client({
contactPoints: config.contactPoints,
localDataCenter: config.datacenter,
authProvider: config.authEnabled
? new auth.PlainTextAuthProvider(config.username, config.password)
: undefined,
protocolOptions: {
port: config.port,
},
...(withKeyspace && config.keyspace ? { keyspace: config.keyspace } : {}),
});
try { try {
await CassandraService.getClient().connect(); await client.connect();
logger.info("Connected to Cassandra successfully."); logger.info("Connected to Cassandra successfully.");
CassandraService.instance = client;
} catch (error) { } catch (error) {
logger.error(["Failed to connect to Cassandra:", error as Error]); logger.error(["Failed to connect to Cassandra:", error as Error]);
process.exit(1); process.exit(1);