162 lines
4.1 KiB
TypeScript
162 lines
4.1 KiB
TypeScript
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
import type { Database, Document } from '$lib/supabase/types';
|
|
import { createLogger } from '$lib/utils/logger';
|
|
|
|
const log = createLogger('api.documents');
|
|
|
|
export async function fetchDocuments(
|
|
supabase: SupabaseClient<Database>,
|
|
orgId: string
|
|
): Promise<Document[]> {
|
|
const { data, error } = await supabase
|
|
.from('documents')
|
|
.select('*')
|
|
.eq('org_id', orgId)
|
|
.order('type', { ascending: false }) // folders first
|
|
.order('name');
|
|
|
|
if (error) {
|
|
log.error('fetchDocuments failed', { error, data: { orgId } });
|
|
throw error;
|
|
}
|
|
log.debug('fetchDocuments ok', { data: { count: data?.length ?? 0 } });
|
|
return data ?? [];
|
|
}
|
|
|
|
export async function createDocument(
|
|
supabase: SupabaseClient<Database>,
|
|
orgId: string,
|
|
name: string,
|
|
type: 'folder' | 'document' | 'kanban',
|
|
parentId: string | null = null,
|
|
userId: string,
|
|
options?: { id?: string; content?: import('$lib/supabase/types').Json }
|
|
): Promise<Document> {
|
|
let content: import('$lib/supabase/types').Json | null = options?.content ?? null;
|
|
if (!content && type === 'document') {
|
|
content = { type: 'doc', content: [] };
|
|
}
|
|
|
|
const { data, error } = await supabase
|
|
.from('documents')
|
|
.insert({
|
|
...(options?.id ? { id: options.id } : {}),
|
|
org_id: orgId,
|
|
name,
|
|
type,
|
|
parent_id: parentId,
|
|
created_by: userId,
|
|
content,
|
|
})
|
|
.select()
|
|
.single();
|
|
|
|
if (error) {
|
|
log.error('createDocument failed', { error, data: { orgId, name, type, parentId } });
|
|
throw error;
|
|
}
|
|
log.info('createDocument ok', { data: { id: data.id, name, type } });
|
|
return data;
|
|
}
|
|
|
|
export async function updateDocument(
|
|
supabase: SupabaseClient<Database>,
|
|
id: string,
|
|
updates: Partial<Pick<Document, 'name' | 'content' | 'parent_id'>>
|
|
): Promise<Document> {
|
|
const { data, error } = await supabase
|
|
.from('documents')
|
|
.update({ ...updates, updated_at: new Date().toISOString() })
|
|
.eq('id', id)
|
|
.select()
|
|
.single();
|
|
|
|
if (error) {
|
|
log.error('updateDocument failed', { error, data: { id, updates } });
|
|
throw error;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
export async function deleteDocument(
|
|
supabase: SupabaseClient<Database>,
|
|
id: string
|
|
): Promise<void> {
|
|
const { error } = await supabase.from('documents').delete().eq('id', id);
|
|
if (error) {
|
|
log.error('deleteDocument failed', { error, data: { id } });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function moveDocument(
|
|
supabase: SupabaseClient<Database>,
|
|
id: string,
|
|
newParentId: string | null
|
|
): Promise<void> {
|
|
const { error } = await supabase
|
|
.from('documents')
|
|
.update({ parent_id: newParentId, updated_at: new Date().toISOString() })
|
|
.eq('id', id);
|
|
|
|
if (error) {
|
|
log.error('moveDocument failed', { error, data: { id, newParentId } });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
|
|
export async function copyDocument(
|
|
supabase: SupabaseClient<Database>,
|
|
doc: Pick<Document, 'name' | 'type' | 'parent_id' | 'content'>,
|
|
orgId: string,
|
|
userId: string
|
|
): Promise<Document> {
|
|
const { data, error } = await supabase
|
|
.from('documents')
|
|
.insert({
|
|
org_id: orgId,
|
|
name: `${doc.name} (copy)`,
|
|
type: doc.type,
|
|
parent_id: doc.parent_id,
|
|
created_by: userId,
|
|
content: doc.content,
|
|
})
|
|
.select()
|
|
.single();
|
|
|
|
if (error) {
|
|
log.error('copyDocument failed', { error, data: { orgId, name: doc.name } });
|
|
throw error;
|
|
}
|
|
log.info('copyDocument ok', { data: { id: data.id, name: data.name } });
|
|
return data;
|
|
}
|
|
|
|
export function subscribeToDocuments(
|
|
supabase: SupabaseClient<Database>,
|
|
orgId: string,
|
|
onInsert: (doc: Document) => void,
|
|
onUpdate: (doc: Document) => void,
|
|
onDelete: (id: string) => void
|
|
) {
|
|
return supabase
|
|
.channel(`documents:${orgId}`)
|
|
.on(
|
|
'postgres_changes',
|
|
{ event: 'INSERT', schema: 'public', table: 'documents', filter: `org_id=eq.${orgId}` },
|
|
(payload) => onInsert(payload.new as Document)
|
|
)
|
|
.on(
|
|
'postgres_changes',
|
|
{ event: 'UPDATE', schema: 'public', table: 'documents', filter: `org_id=eq.${orgId}` },
|
|
(payload) => onUpdate(payload.new as Document)
|
|
)
|
|
.on(
|
|
'postgres_changes',
|
|
{ event: 'DELETE', schema: 'public', table: 'documents', filter: `org_id=eq.${orgId}` },
|
|
(payload) => onDelete((payload.old as { id: string }).id)
|
|
)
|
|
.subscribe();
|
|
}
|