Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | 29x 35x 29x 5x 4x 4x 1x 29x 205x 29x 251x 17x 234x 50x 197x 197x 197x 184x 29x 5x 5x 3x 5x 2x 5x 1x 5x 1x 5x 1x 5x 1x 5x 29x 14x 29x 2x 2x 29x 2x 2x 29x 198x 101x 51x | /**
* Supabase 辅助函数
* 提供常用的数据库操作封装
*/
import { logger as appLogger } from '@/src/utils/logger';
import { supabase } from './client';
import type { PostgrestError } from '@supabase/supabase-js';
/**
* Supabase 响应类型
*/
export interface SupabaseResponse<T> {
data: T | null;
error: PostgrestError | null;
success: boolean;
}
/**
* 包装Supabase响应为统一格式
*/
export const wrapResponse = <T>(
data: T | null,
error: PostgrestError | null
): SupabaseResponse<T> => {
return {
data,
error,
success: !error && data !== null,
};
};
/**
* 处理Supabase错误
*/
export const handleSupabaseError = (error: PostgrestError | null, context: string) => {
if (error) {
appLogger.error(`Supabase错误 [${context}]`, new Error(error.message), {
code: error.code,
details: error.details,
hint: error.hint,
});
return {
message: error.message,
code: error.code,
details: error.details,
hint: error.hint,
};
}
return null;
};
/**
* 转换snake_case到camelCase
*/
export const snakeToCamel = (str: string): string => {
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
};
/**
* 递归转换对象的key从snake_case到camelCase
*/
export const convertKeysToCamel = (obj: unknown): unknown => {
if (Array.isArray(obj)) {
return obj.map(convertKeysToCamel);
}
if (obj !== null && typeof obj === 'object' && !(obj instanceof Date)) {
return Object.keys(obj).reduce(
(acc, key) => {
const camelKey = snakeToCamel(key);
acc[camelKey] = convertKeysToCamel((obj as Record<string, unknown>)[key]);
return acc;
},
{} as Record<string, unknown>
);
}
return obj;
};
/**
* 构建percentData从营养成分字段
*/
export const buildPercentData = (data: {
crude_protein?: number;
crude_fat?: number;
carbohydrates?: number;
crude_fiber?: number;
crude_ash?: number;
others?: number;
}) => {
const percentData: Record<string, number> = {};
if (data.crude_protein !== null && data.crude_protein !== undefined) {
percentData.protein = data.crude_protein;
}
if (data.crude_fat !== null && data.crude_fat !== undefined) {
percentData.fat = data.crude_fat;
}
if (data.carbohydrates !== null && data.carbohydrates !== undefined) {
percentData.carbohydrates = data.carbohydrates;
}
if (data.crude_fiber !== null && data.crude_fiber !== undefined) {
percentData.fiber = data.crude_fiber;
}
if (data.crude_ash !== null && data.crude_ash !== undefined) {
percentData.ash = data.crude_ash;
}
if (data.others !== null && data.others !== undefined) {
percentData.others = data.others;
}
return Object.keys(percentData).length > 0 ? percentData : null;
};
/**
* 分页参数
*/
export interface PaginationParams {
page?: number;
pageSize?: number;
}
/**
* 计算分页的offset和limit
*/
export const calculatePagination = ({ page = 1, pageSize = 20 }: PaginationParams) => {
return {
from: (page - 1) * pageSize,
to: page * pageSize - 1,
};
};
/**
* 获取当前用户ID
*/
export const getCurrentUserId = async () => {
const {
data: { user },
} = await supabase.auth.getUser();
return user?.id || null;
};
/**
* 检查用户是否已认证
*/
export const isAuthenticated = async () => {
const {
data: { session },
} = await supabase.auth.getSession();
return !!session;
};
/**
* 日志工具(使用统一的 logger)
*/
export const logger = {
query: (table: string, operation: string, params?: unknown) => {
appLogger.debug('Supabase Query', { table, operation, params: params || null });
},
success: (table: string, operation: string, count?: number | string) => {
appLogger.info('Supabase Success', { table, operation, count });
},
error: (table: string, operation: string, error: unknown) => {
appLogger.error('Supabase Error', error as Error, { table, operation });
},
info: (message: string, data?: Record<string, unknown>) => {
appLogger.info(message, data as any);
},
};
|