mirror of
https://github.com/zen-browser/rices.git
synced 2025-07-07 17:05:40 +02:00
- The rice database now includes new fields: - `version`: Represents the version of the rice entry. - `os`: Represents the operating system associated with the rice entry. - These fields are required for all new rice entries. refactor: Stop uploading rice.json to GitHub - The `rice.json` file is no longer uploaded to GitHub during rice creation or updates. - This reduces redundancy as all metadata is now managed directly in the database (Supabase). fix: Improve exception handling with proper HTTP status codes - Enhanced exception handling to align with standard HTTP status codes: - `BadRequestException` for validation errors. - `ConflictException` for duplicate entries. - `NotFoundException` for missing resources. - Generic `InternalServerErrorException` for unexpected errors. - This ensures the API returns meaningful and accurate responses. feat: Enhance rice download to act as a standard HTTP GET - The `findOne` method now returns the raw content of the rice file directly as the response body. - Removes unnecessary JSON wrappers, allowing the endpoint to behave like a typical HTTP GET request. - Improved usability for clients consuming the API.
135 lines
3.7 KiB
TypeScript
135 lines
3.7 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
|
|
|
@Injectable()
|
|
export class SupabaseService {
|
|
private supabase: SupabaseClient;
|
|
private supabase_url: string;
|
|
private supabase_key: string;
|
|
private readonly logger = new Logger(SupabaseService.name);
|
|
|
|
constructor(private configService: ConfigService) {
|
|
// Initialize properties in the constructor
|
|
this.supabase_url = this.configService.get<string>('SUPABASE_URL') || '';
|
|
this.supabase_key = this.configService.get<string>('SUPABASE_KEY') || '';
|
|
|
|
this.supabase = createClient(this.supabase_url, this.supabase_key);
|
|
}
|
|
|
|
async insertRice(metadata: any) {
|
|
const { error } = await this.supabase.from('rices').insert(metadata);
|
|
if (error) {
|
|
this.logger.error(
|
|
`Failed to insert rice: ${error.message}`,
|
|
error.details,
|
|
);
|
|
throw new Error(`Failed to insert rice: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
async getRiceById(id: string) {
|
|
const { data, error } = await this.supabase
|
|
.from('rices')
|
|
.select('*')
|
|
.eq('id', id)
|
|
.single();
|
|
if (error) {
|
|
this.logger.error(
|
|
`Failed to fetch rice with ID ${id}: ${error.message}`,
|
|
error.details,
|
|
);
|
|
throw new Error(`Failed to fetch rice: ${error.message}`);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
async getRiceBySlug(slug: string) {
|
|
const { data, error } = await this.supabase
|
|
.from('rices')
|
|
.select('*')
|
|
.eq('slug', slug)
|
|
.single();
|
|
if (error) {
|
|
this.logger.error(
|
|
`Failed to fetch rice with slug ${slug}: ${error.message}`,
|
|
error.details,
|
|
);
|
|
return null;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
async getRiceByName(name: string) {
|
|
const { data, error } = await this.supabase
|
|
.from('rices')
|
|
.select('*')
|
|
.eq('name', name)
|
|
.single();
|
|
if (error && error.code !== 'PGRST116') {
|
|
// Handle "no rows found" separately
|
|
this.logger.error(
|
|
`Failed to fetch rice with name ${name}: ${error.message}`,
|
|
error.details,
|
|
);
|
|
throw new Error(`Failed to fetch rice: ${error.message}`);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
async updateRice(slug: string, metadata: any) {
|
|
const { error } = await this.supabase
|
|
.from('rices')
|
|
.update(metadata)
|
|
.eq('slug', slug);
|
|
if (error) {
|
|
this.logger.error(
|
|
`Failed to update rice with slug ${slug}: ${error.message}`,
|
|
error.details,
|
|
);
|
|
throw new Error(`Failed to update rice: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
async deleteRice(slug: string) {
|
|
const { error } = await this.supabase
|
|
.from('rices')
|
|
.delete()
|
|
.eq('slug', slug);
|
|
if (error) {
|
|
this.logger.error(
|
|
`Failed to delete rice with slug ${slug}: ${error.message}`,
|
|
error.details,
|
|
);
|
|
throw new Error(`Failed to delete rice: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
async incrementVisits(slug: string) {
|
|
const { error } = await this.supabase.rpc('increment_visits', {
|
|
slug_param: slug,
|
|
});
|
|
|
|
if (error) {
|
|
this.logger.error(
|
|
`Failed to increment visits for rice with slug ${slug}: ${error.message}`,
|
|
error.details,
|
|
);
|
|
throw new Error(`Failed to increment visits: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
async updateLevel(slug: string, level: number) {
|
|
const { error } = await this.supabase
|
|
.from('rices')
|
|
.update({ level })
|
|
.eq('slug', slug);
|
|
if (error) {
|
|
this.logger.error(
|
|
`Failed to update level for rice with slug ${slug}: ${error.message}`,
|
|
error.details,
|
|
);
|
|
throw new Error(`Failed to update rice level: ${error.message}`);
|
|
}
|
|
}
|
|
}
|