1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { sqlite } from "https://esm.town/v/std/sqlite";
import { raw, sql } from "https://esm.town/v/pomdtr/sql";
import { zip } from "npm:lodash-es";
import { generateId, Scrypt } from "npm:lucia";
import type {
Adapter,
DatabaseSession,
DatabaseUser,
RegisteredDatabaseSessionAttributes,
RegisteredDatabaseUserAttributes,
} from "npm:lucia";
export interface TableNames {
userTable: string;
sessionTable: string;
}
export interface Controller {
execute(sql: string, args: any[]): Promise<void>;
get<T>(sql: string, args: any[]): Promise<T | null>;
getAll<T>(sql: string, args: any[]): Promise<T[]>;
}
interface SessionSchema extends RegisteredDatabaseSessionAttributes {
id: string;
user_id: string;
expires_at: number;
}
interface UserSchema extends RegisteredDatabaseUserAttributes {
id: string;
}
export class SQLiteAdapter implements Adapter {
private controller: Controller;
private escapedUserTableName: string;
private escapedSessionTableName: string;
constructor(controller: Controller, tableNames: TableNames) {
this.controller = controller;
this.escapedSessionTableName = escapeName(tableNames.sessionTable);
this.escapedUserTableName = escapeName(tableNames.userTable);
}
public async deleteSession(sessionId: string): Promise<void> {
await this.controller.execute(`DELETE FROM ${this.escapedSessionTableName} WHERE id = ?`, [
sessionId,
]);
}
public async deleteUserSessions(userId: string): Promise<void> {
await this.controller.execute(
`DELETE FROM ${this.escapedSessionTableName} WHERE user_id = ?`,
[userId],
);
}
public async getSessionAndUser(
sessionId: string,
): Promise<[session: DatabaseSession | null, user: DatabaseUser | null]> {
const [databaseSession, databaseUser] = await Promise.all([
this.getSession(sessionId),
this.getUserFromSessionId(sessionId),
]);
return [databaseSession, databaseUser];
}
public async getUserSessions(userId: string): Promise<DatabaseSession[]> {
const result = await this.controller.getAll<SessionSchema>(
`SELECT * FROM ${this.escapedSessionTableName} WHERE user_id = ?`,
[userId],
);
return result.map((val) => transformIntoDatabaseSession(val));
}
public async setSession(databaseSession: DatabaseSession): Promise<void> {
const value: SessionSchema = {
id: databaseSession.id,
user_id: databaseSession.userId,
expires_at: Math.floor(databaseSession.expiresAt.getTime() / 1000),
...databaseSession.attributes,
};
const entries = Object.entries(value).filter(([_, v]) => v !== undefined);
const columns = entries.map(([k]) => escapeName(k));
const placeholders = Array(columns.length).fill("?");
const values = entries.map(([_, v]) => v);
await this.controller.execute(
`INSERT INTO ${this.escapedSessionTableName} (${
columns.join(", ")
}) VALUES (${placeholders.join(", ")})`,
values,
);
}
public async updateSessionExpiration(sessionId: string, expiresAt: Date): Promise<void> {
await this.controller.execute(
`UPDATE ${this.escapedSessionTableName} SET expires_at = ? WHERE id = ?`,
[Math.floor(expiresAt.getTime() / 1000), sessionId],
);
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Comments
Nobody has commented on this val yet: be the first!
September 3, 2024