2026-02-20 13:19:25 +01:00
|
|
|
|
2026-02-20 13:23:29 +01:00
|
|
|
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
2026-02-20 13:32:26 +01:00
|
|
|
import { VendorDailyRow } from '../types';
|
2026-02-20 13:19:25 +01:00
|
|
|
|
|
|
|
|
const supabaseUrl = process.env.SUPABASE_URL || '';
|
|
|
|
|
const supabaseAnonKey = process.env.SUPABASE_ANON_KEY || '';
|
|
|
|
|
|
2026-02-20 13:23:29 +01:00
|
|
|
let _client: SupabaseClient | null = null;
|
|
|
|
|
|
|
|
|
|
const getClient = (): SupabaseClient => {
|
|
|
|
|
if (!_client) {
|
|
|
|
|
if (!supabaseUrl || !supabaseAnonKey) {
|
|
|
|
|
throw new Error('Supabase credentials not configured. Add SUPABASE_URL and SUPABASE_ANON_KEY to environment variables.');
|
|
|
|
|
}
|
|
|
|
|
_client = createClient(supabaseUrl, supabaseAnonKey);
|
|
|
|
|
}
|
|
|
|
|
return _client;
|
|
|
|
|
};
|
2026-02-20 13:19:25 +01:00
|
|
|
|
|
|
|
|
export interface VendorFilters {
|
|
|
|
|
markets?: string[];
|
|
|
|
|
tags?: string[];
|
|
|
|
|
asins?: string[];
|
|
|
|
|
dateFrom?: string;
|
|
|
|
|
dateTo?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const fetchVendorData = async (filters: VendorFilters): Promise<VendorDailyRow[]> => {
|
|
|
|
|
const allRows: VendorDailyRow[] = [];
|
|
|
|
|
let offset = 0;
|
|
|
|
|
const pageSize = 1000;
|
|
|
|
|
let hasMore = true;
|
|
|
|
|
|
|
|
|
|
while (hasMore) {
|
2026-02-20 13:23:29 +01:00
|
|
|
let query = getClient()
|
2026-02-20 13:19:25 +01:00
|
|
|
.from('vendor_daily_data')
|
|
|
|
|
.select('*')
|
|
|
|
|
.order('date', { ascending: true })
|
|
|
|
|
.range(offset, offset + pageSize - 1);
|
|
|
|
|
|
|
|
|
|
if (filters.markets?.length) {
|
|
|
|
|
query = query.in('market', filters.markets);
|
|
|
|
|
}
|
|
|
|
|
if (filters.tags?.length) {
|
|
|
|
|
query = query.in('tags', filters.tags);
|
|
|
|
|
}
|
|
|
|
|
if (filters.asins?.length) {
|
|
|
|
|
query = query.in('asin', filters.asins);
|
|
|
|
|
}
|
|
|
|
|
if (filters.dateFrom) {
|
|
|
|
|
query = query.gte('date', filters.dateFrom);
|
|
|
|
|
}
|
|
|
|
|
if (filters.dateTo) {
|
|
|
|
|
query = query.lte('date', filters.dateTo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { data, error } = await query;
|
|
|
|
|
if (error) throw error;
|
|
|
|
|
if (data) {
|
|
|
|
|
allRows.push(...data);
|
|
|
|
|
hasMore = data.length === pageSize;
|
|
|
|
|
offset += pageSize;
|
|
|
|
|
} else {
|
|
|
|
|
hasMore = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return allRows;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const fetchVendorFilterOptions = async (): Promise<{
|
|
|
|
|
markets: string[];
|
|
|
|
|
tags: string[];
|
|
|
|
|
dateRange: { min: string; max: string } | null;
|
|
|
|
|
}> => {
|
2026-02-20 13:23:29 +01:00
|
|
|
const client = getClient();
|
|
|
|
|
|
|
|
|
|
const { data: marketData } = await client
|
2026-02-20 13:19:25 +01:00
|
|
|
.from('vendor_daily_data')
|
|
|
|
|
.select('market');
|
|
|
|
|
|
2026-02-20 13:23:29 +01:00
|
|
|
const { data: tagData } = await client
|
2026-02-20 13:19:25 +01:00
|
|
|
.from('vendor_daily_data')
|
|
|
|
|
.select('tags');
|
|
|
|
|
|
2026-02-20 13:23:29 +01:00
|
|
|
const { data: dateMin } = await client
|
2026-02-20 13:19:25 +01:00
|
|
|
.from('vendor_daily_data')
|
|
|
|
|
.select('date')
|
|
|
|
|
.order('date', { ascending: true })
|
|
|
|
|
.limit(1);
|
|
|
|
|
|
2026-02-20 13:23:29 +01:00
|
|
|
const { data: dateMax } = await client
|
2026-02-20 13:19:25 +01:00
|
|
|
.from('vendor_daily_data')
|
|
|
|
|
.select('date')
|
|
|
|
|
.order('date', { ascending: false })
|
|
|
|
|
.limit(1);
|
|
|
|
|
|
|
|
|
|
const markets = [...new Set((marketData || []).map(r => r.market))].sort();
|
|
|
|
|
const tags = [...new Set((tagData || []).map(r => r.tags).filter(Boolean))].sort();
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
markets,
|
|
|
|
|
tags,
|
|
|
|
|
dateRange: dateMin?.[0] && dateMax?.[0]
|
|
|
|
|
? { min: dateMin[0].date, max: dateMax[0].date }
|
|
|
|
|
: null,
|
|
|
|
|
};
|
|
|
|
|
};
|