start of db management and tables
All checks were successful
Code quality checks / biome (push) Successful in 9s
All checks were successful
Code quality checks / biome (push) Successful in 9s
This commit is contained in:
parent
ab81475ad6
commit
d066cc9fed
6 changed files with 112 additions and 18 deletions
|
@ -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
68
config/setup/index.ts
Normal 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);
|
||||||
|
});
|
17
config/setup/tables/users.ts
Normal file
17
config/setup/tables/users.ts
Normal 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
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
}
|
|
@ -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",
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Reference in a new issue