rojects/server/db.ts

125 lines
4.1 KiB
TypeScript

import fs from 'fs';
import path from 'path';
import { randomUUID } from 'crypto';
const DATA_DIR = path.join(__dirname, '..', 'data');
if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR);
export interface User {
id: string;
username: string;
password: string;
created_at: string;
}
export interface Group {
id: string;
name: string;
created_at: string;
}
export interface GroupMember {
id: string;
group_id: string;
member_type: 'user' | 'group';
member_id: string;
}
export interface Project {
id: string;
name: string;
owner_id: string;
created_at: string;
}
export interface ProjectMember {
id: string;
project_id: string;
member_type: 'user' | 'group';
member_id: string;
role: string;
}
function read<T>(table: string): T[] {
const file = path.join(DATA_DIR, `${table}.json`);
if (!fs.existsSync(file)) return [];
return JSON.parse(fs.readFileSync(file, 'utf8')) as T[];
}
function write<T>(table: string, rows: T[]): void {
fs.writeFileSync(path.join(DATA_DIR, `${table}.json`), JSON.stringify(rows, null, 2));
}
export const users = {
all: (): User[] => read<User>('users'),
findById: (id: string): User | undefined => read<User>('users').find(u => u.id === id),
findByUsername: (name: string): User | undefined => read<User>('users').find(u => u.username === name),
create(data: Omit<User, 'id' | 'created_at'>): User {
const rows = read<User>('users');
if (rows.find(u => u.username === data.username)) throw new Error('Taken');
const user: User = { id: randomUUID(), ...data, created_at: new Date().toISOString() };
write('users', [...rows, user]);
return user;
},
delete(id: string): void {
write('users', read<User>('users').filter(u => u.id !== id));
}
};
export const groups = {
all: (): Group[] => read<Group>('groups'),
findById: (id: string): Group | undefined => read<Group>('groups').find(g => g.id === id),
create(data: Omit<Group, 'id' | 'created_at'>): Group {
const rows = read<Group>('groups');
if (rows.find(g => g.name === data.name)) throw new Error('Taken');
const group: Group = { id: randomUUID(), ...data, created_at: new Date().toISOString() };
write('groups', [...rows, group]);
return group;
},
delete(id: string): void {
write('groups', read<Group>('groups').filter(g => g.id !== id));
write('group_members', read<GroupMember>('group_members').filter(m => m.group_id !== id));
}
};
export const groupMembers = {
forGroup: (groupId: string): GroupMember[] => read<GroupMember>('group_members').filter(m => m.group_id === groupId),
add(data: Omit<GroupMember, 'id'>): GroupMember {
const rows = read<GroupMember>('group_members');
const member: GroupMember = { id: randomUUID(), ...data };
write('group_members', [...rows, member]);
return member;
},
remove(id: string): void {
write('group_members', read<GroupMember>('group_members').filter(m => m.id !== id));
}
};
export const projects = {
all: (): Project[] => read<Project>('projects'),
findById: (id: string): Project | undefined => read<Project>('projects').find(p => p.id === id),
create(data: Omit<Project, 'id' | 'created_at'>): Project {
const rows = read<Project>('projects');
const project: Project = { id: randomUUID(), ...data, created_at: new Date().toISOString() };
write('projects', [...rows, project]);
return project;
},
delete(id: string): void {
write('projects', read<Project>('projects').filter(p => p.id !== id));
write('project_members', read<ProjectMember>('project_members').filter(m => m.project_id !== id));
}
};
export const projectMembers = {
forProject: (projectId: string): ProjectMember[] => read<ProjectMember>('project_members').filter(m => m.project_id === projectId),
add(data: Omit<ProjectMember, 'id'>): ProjectMember {
const rows = read<ProjectMember>('project_members');
const member: ProjectMember = { id: randomUUID(), ...data };
write('project_members', [...rows, member]);
return member;
},
remove(id: string): void {
write('project_members', read<ProjectMember>('project_members').filter(m => m.id !== id));
}
};