prasi-lib/session/store/session-store.ts

147 lines
3.7 KiB
TypeScript
Executable File

/// <reference types="bun-types" />
import Database from "bun:sqlite";
import { and, ConsoleLogWriter, eq, sql } from "drizzle-orm";
import { BunSQLiteDatabase, drizzle } from "drizzle-orm/bun-sqlite";
import { mkdirSync } from "fs";
import { join } from "path";
import { dir } from "../../server/utils/dir";
import { SessionData, SessionStore, SingleSession } from "../type";
import { session } from "./schema";
export const newSessionStore = <T>(site_id?: string) => {
const db_path = site_id
? dir.data(`/code/${site_id}/site/sqlite`)
: dir.data(`/sqlite`);
mkdirSync(db_path, { recursive: true });
const path = { session: join(db_path, "session.db") };
const db = {
session: drizzle(new Database(path.session), { schema: { session } }),
track: {} as Record<string, BunSQLiteDatabase<Record<string, never>>>,
};
db.session.run(sql`
CREATE TABLE IF NOT EXISTS session (
sid text PRIMARY KEY NOT NULL,
uid text NOT NULL,
created_at integer NOT NULL DEFAULT current_timestamp,
active integer,
data text NOT NULL,
wsid text default \`[]\`,
expired_at integer
);
CREATE INDEX IF NOT EXISTS expired_at_idx ON session (expired_at);
`);
// const track_ddl = sql`
// CREATE TABLE track (
// id text PRIMARY KEY NOT NULL,
// created_at integer DEFAULT current_timestamp,
// session_id text,
// url text NOT NULL,
// referer text,
// user_ip text,
// data text,
// tstamp integer DEFAULT current_timestamp
// );
// CREATE INDEX session_id ON track (session_id);`;
const createSingleStore = <E extends SessionData<T>>(data: any) => {
if (!data) return null;
const row: SingleSession<E> = {
...data,
destroy() {
try {
db.session.delete(session).where(eq(session.sid, row.sid)).run();
return true;
} catch (e) {
console.error(e);
return false;
}
},
track(arg) {},
};
return row;
};
return {
create(data) {
try {
return createSingleStore(
db.session
.insert(session)
.values({
uid: data.uid,
data,
active: true,
expired_at: data.expired_at
? new Date(data.expired_at * 1000)
: undefined,
})
.returning()
.get()
);
} catch (e) {
console.error("Session Create Error:\n", e);
}
},
update(where, data) {
try {
db.session
.update(session)
.set(data)
.where(
and(
...Object.entries(where || {}).map(([k, v]) => {
return eq(k as any, v);
})
)
)
.get();
} catch (e) {
console.error("Session Update Error:\n", e);
}
},
findFirst(arg) {
try {
return createSingleStore(
db.session
.select()
.from(session)
.where(
and(
...Object.entries(arg || {}).map(([k, v]) => {
return eq((session as any)[k], v);
})
)
)
.get()
);
} catch (e) {
console.error("Session FindFirst Error:\n", e);
}
},
findMany(arg) {
try {
return db.session
.select()
.from(session)
.where(
and(
...Object.entries(arg || {}).map(([k, v]) => {
return eq((session as any)[k], v);
})
)
)
.all()
.map((e) => createSingleStore(e));
} catch (e) {
console.error("Session FindMany Error:\n", e);
}
},
} as SessionStore<T>;
};