(data: {
perspective_id: string;
asset_type: 'cover_image' | 'report' | 'attachment';
file_name: string;
file_mime_type: string;
file_data: Buffer;
uploaded_by_user_id?: string;
})
| 24 | |
| 25 | /** Insert a new asset, returning metadata (no binary). */ |
| 26 | export async function createAsset(data: { |
| 27 | perspective_id: string; |
| 28 | asset_type: 'cover_image' | 'report' | 'attachment'; |
| 29 | file_name: string; |
| 30 | file_mime_type: string; |
| 31 | file_data: Buffer; |
| 32 | uploaded_by_user_id?: string; |
| 33 | }): Promise<PerspectiveAsset> { |
| 34 | const pool = getPool(); |
| 35 | |
| 36 | // For cover_image, replace existing one (upsert) |
| 37 | if (data.asset_type === 'cover_image') { |
| 38 | const result = await pool.query<PerspectiveAsset>( |
| 39 | `INSERT INTO perspective_assets (perspective_id, asset_type, file_name, file_mime_type, file_data, file_size_bytes, uploaded_by_user_id) |
| 40 | VALUES ($1, $2, $3, $4, $5, $6, $7) |
| 41 | ON CONFLICT (perspective_id) WHERE asset_type = 'cover_image' |
| 42 | DO UPDATE SET file_name = EXCLUDED.file_name, |
| 43 | file_mime_type = EXCLUDED.file_mime_type, |
| 44 | file_data = EXCLUDED.file_data, |
| 45 | file_size_bytes = EXCLUDED.file_size_bytes, |
| 46 | uploaded_by_user_id = EXCLUDED.uploaded_by_user_id, |
| 47 | updated_at = NOW() |
| 48 | RETURNING ${METADATA_COLUMNS}`, |
| 49 | [data.perspective_id, data.asset_type, data.file_name, data.file_mime_type, data.file_data, data.file_data.length, data.uploaded_by_user_id || null] |
| 50 | ); |
| 51 | return result.rows[0]; |
| 52 | } |
| 53 | |
| 54 | // For filename conflicts, replace |
| 55 | const result = await pool.query<PerspectiveAsset>( |
| 56 | `INSERT INTO perspective_assets (perspective_id, asset_type, file_name, file_mime_type, file_data, file_size_bytes, uploaded_by_user_id) |
| 57 | VALUES ($1, $2, $3, $4, $5, $6, $7) |
| 58 | ON CONFLICT (perspective_id, file_name) |
| 59 | DO UPDATE SET asset_type = EXCLUDED.asset_type, |
| 60 | file_mime_type = EXCLUDED.file_mime_type, |
| 61 | file_data = EXCLUDED.file_data, |
| 62 | file_size_bytes = EXCLUDED.file_size_bytes, |
| 63 | uploaded_by_user_id = EXCLUDED.uploaded_by_user_id, |
| 64 | updated_at = NOW() |
| 65 | RETURNING ${METADATA_COLUMNS}`, |
| 66 | [data.perspective_id, data.asset_type, data.file_name, data.file_mime_type, data.file_data, data.file_data.length, data.uploaded_by_user_id || null] |
| 67 | ); |
| 68 | return result.rows[0]; |
| 69 | } |
| 70 | |
| 71 | /** Get asset binary data for serving. */ |
| 72 | export async function getAssetData( |
no test coverage detected