CRMలో ఇరవై కాంటాక్ట్‌లను ఆర్కైవ్ చేయాల్సి ఉంది, కానీ UI ఒక గ్రీన్ సక్సెస్ బ్యాడ్జ్‌ను చూపించింది మరియు ఆ ఆపరేషన్ ఏమీ చేయకుండా నిశ్శబ్దంగా ముగిసిపోయింది. Supabase-JS మ్యుటేషన్లలో error ఫీల్డ్‌ను తప్పనిసరి చేసే ఒక TypeScript హెల్పర్, ఇప్పుడు డెవలపర్లు ఆ వైఫల్యాన్ని దాచిపెట్టకుండా నేరుగా ఎదుర్కోవాలని బలవంతం చేస్తుంది.

Supabase-JS యొక్క రిటర్న్ షేప్ (return shape) ఎందుకు ఒక ఉచ్చు?

Supabase యొక్క JavaScript క్లయింట్ (@supabase/supabase-js) డేటాబేస్ రైట్ రిజెక్ట్ అయినప్పుడు ఎక్సెప్షన్లను (exceptions) త్రో చేయదు. దానికి బదులుగా, అది { data, error } అనే ఆబ్జెక్ట్‌తో ప్రామిస్‌ను రిజాల్వ్ చేస్తుంది. ఒక Row-level security (RLS) పాలసీ, యూనిక్-కీ ఉల్లంఘన (unique-key violation), లేదా మరేదైనా కన్‌స్ట్రైంట్ క్వరీని బ్లాక్ చేస్తే, data అనేది null గా వస్తుంది మరియు error లో డేటాబేస్ మెసేజ్ ఉంటుంది. కాల్ చేసిన వ్యక్తి errorను తనిఖీ చేస్తారని క్లయింట్ భావిస్తుంది; అది కాల్‌ను ఎప్పుడూ అబార్ట్ చేయదు.

ఆచరణలో, చాలా కోడ్‌బేస్‌లు ఈ కాల్‌ను 'fire-and-forget' ఆపరేషన్‌గా పరిగణిస్తాయి:

await supabase
  .from('contacts')
  .update({ statut: 'ancien', archived_at: now })
  .eq('id', id)

return { ok: true }

update అనేది RLS రూల్ ద్వారా బ్లాక్ చేయబడినప్పుడు, ప్రామిస్ ఇంకా రిజాల్వ్ అవుతుంది. డెవలపర్ { error }ని డీస్ట్రక్చర్ చేయనందున, ఆ వైఫల్యం కనిపించదు. ఫంక్షన్ { ok: true }ని రిటర్న్ చేస్తుంది, UI సక్సెస్‌ను చూపిస్తుంది, మరియు డేటా మారదు. ఎటువంటి లాగ్‌లు కనిపించవు, Sentry అలర్ట్ రాదు, మరియు ఆ బగ్ రోజుల తరబడి అలాగే ఉండిపోవచ్చు.

ఒక లీంటర్ (linter) సరిపోదు

error ప్రాపర్టీని విస్మరించినప్పుడు స్టాటిక్ అనాలిసిస్ టూల్స్ హెచ్చరించగలవు, కానీ అవి రన్‌టైమ్ కాంట్రాక్ట్‌ను అమలు చేయలేవు. డెవలపర్ ఇంకా const _ = await … అని రాసి హెచ్చరికను సైలెన్స్ చేయవచ్చు, లేదా రూల్‌ను సప్రెస్ చేయడానికి ఒక కామెంట్‌ను జోడించవచ్చు. అసలు సమస్య ఏమిటంటే, error గురించి ఎప్పుడూ ప్రస్తావించకుండానే కాల్ విజయవంతం కావడానికి టైప్ సిస్టమ్ అనుమతిస్తుంది.

mutate() హెల్పర్: ఎర్రర్ హ్యాండ్లింగ్‌ను తప్పనిసరి చేయడం

రచయిత రిటర్న్ టైప్ షేప్‌ను మార్చే mutate() అనే చిన్న రాపర్‌ను రూపొందించారు. { data, error } కి బదులుగా, ఈ హెల్పర్ [data, error] అనే టపుల్‌ను (tuple) రిటర్న్ చేస్తుంది, ఇక్కడ error అనేది ఒక తప్పనిసరి ఫీల్డ్. రెండో ఎలిమెంట్‌ను విస్మరించే ఏ కాల్‌నైనా TypeScript కంపైల్ చేయడానికి నిరాకరిస్తుంది.

async function mutate<T>(promise: Promise<{ data: T | null; error: any }>) {
  const { data, error } = await promise
  // Send error to Sentry immediately
  if (error) Sentry.captureException(error)
  return [data, error] as const
}

దీని వినియోగం స్పష్టంగా ఉంటుంది:

const [result, err] = await mutate(
  supabase
    .from('contacts')
    .update({ statut: 'ancien', archived_at: now })
    .eq('id', id)
)

if (err) {
  // Handle or rethrow
  return { ok: false, message: err.message }
}
return { ok: true, data: result }

ఒకవేళ డెవలపర్ errని క్యాప్చర్ చేయడం మర్చిపోతే, TypeScript ఈ ఎర్రర్‌ను ఇస్తుంది: “Tuple type [T, any] of length 2 has no element at index 1.” ఆ ఎర్రర్‌ను పరిష్కరించే వరకు కోడ్ కంపైల్ కాదు. ఈ హెల్పర్ Sentry ఇన్‌స్ట్రుమెంటేషన్‌ను కూడా ఇంజెక్ట్ చేస్తుంది, దీనివల్ల కాల్ చేసిన వ్యక్తి తర్వాత దానిని విస్మరించినప్పటికీ, ప్రతి డేటాబేస్ రిజెక్షన్ లాగ్ చేయబడుతుంది.

ప్రమాదంలో ఉన్న అంశాలు

  • Data integrity – సైలెంట్ ఫెయిల్యూర్స్ వల్ల ఇన్వాలిడ్ స్టేట్ ప్రొడక్షన్‌లోకి రావచ్చు. యాక్టివ్ లిస్ట్ నుండి ఎప్పుడూ వెళ్ళని ఆర్కైవ్ చేయబడిన కాంటాక్ట్ వల్ల తదుపరి రిపోర్ట్‌లు తప్పుగా వచ్చే అవకాశం ఉంది.
  • User trust – ఏమీ మారనప్పుడు సక్సెస్ అని చెప్పే UI వినియోగదారుల నమ్మకాన్ని దెబ్బతీస్తుంది. కస్టమర్లు "archived" అని చూస్తారు కానీ సెర్చ్ చేసినప్పుడు ఇంకా కాంటాక్ట్‌ను చూస్తుంటారు.
  • Developer time – తెలియని బగ్స్‌ను వెతకడం వల్ల గంటల సమయం వృథా అవుతుంది. స్పష్టమైన ఎర్రర్ హ్యాండ్లింగ్ వైఫల్యం జరిగిన చోటనే సమస్యను బయటపెడుతుంది, తద్వారా డీబగ్గింగ్ సమయాన్ని తగ్గిస్తుంది.
  • Operational cost – సైలెంట్ డేటా లాస్ ఇన్సిడెంట్ వల్ల కలిగే ఖర్చుతో పోలిస్తే, కొన్ని అదనపు లైన్ల కోడ్ మరియు చిన్న రాపర్ జోడించడం చాలా తక్కువ.

లాభనష్టాల విశ్లేషణ (The trade-off)

ఈ హెల్పర్ వల్ల కోడ్ కొంచెం ఎక్కువ అవుతుంది (verbosity): ప్రతి మ్యుటేషన్ కాల్ ఇప్పుడు ఒక టపుల్‌ను రిటర్న్ చేస్తుంది మరియు కాల్ చేసేవారు if (err) బ్లాక్‌ను రాయాలి. కొన్ని టీమ్‌లు దీనిని అనవసరమైన బోయిలర్‌ప్లేట్ (boilerplate) గా భావించవచ్చు, ముఖ్యంగా సక్సెస్ ఆశిస్తున్న సాధారణ CRUD ఆపరేషన్ల విషయంలో. దీనికి వ్యతిరేక వాదన ఏమిటంటే, ఈ అదనపు కోడ్ ఒక రక్షణ కవచం (safeguard), ఇది ఐచ్ఛిక ఫీచర్ కాదు. డేటా ఖచ్చితత్వం అత్యంత ముఖ్యమైన వాతావరణాలలో—CRM సిస్టమ్స్, ఫైనాన్స్, హెల్త్—ఈ చెక్‌ను తప్పనిసరి చేయడం వల్ల కలిగే ప్రయోజనం చాలా ఎక్కువ.

తదుపరి ఏమిటి?

ఎటువంటి వివరణ లేకుండా సున్నా రోస్ (zero rows) రిటర్న్ చేసే RLS పాలసీలను పరిశీలించే మూడవ భాగం వస్తుందని రచయిత వాగ్దానం చేశారు. ఆ ప్యాటర్న్ కూడా, సైలెంట్-ఎర్రర్ కేసు లాగే, విజయవంతమైన క్వరీ వెనుక వైఫల్యాలను దాచిపెడుతుంది. ఈ సిరీస్ యొక్క ఉద్దేశ్యం Supabase API యొక్క "అనిశ్చిత" (rumor) వైపును బయటపెట్టడం మరియు డెవలపర్‌లకు వాస్తవాలను తెలుసుకోవడానికి స్పష్టమైన సాధనాలను అందించడం.

ముఖ్య అంశం (Takeaway): మీరు error ఫీల్డ్‌ను చదవడం మర్చిపోతే, Supabase-JS డిజైన్ ఫెయిల్ అయిన రైట్‌ను కూడా సక్సెస్ లాగా చూపిస్తుంది. errorను తప్పనిసరి చేస్తూ మరియు దానిని Sentryకి లాగ్ చేస్తూ TypeScript-enforced హెల్పర్‌తో కాల్‌లను చుట్టడం (wrapping) ద్వారా, మీరు సైలెంట్ ఫెయిల్యూర్స్‌ను స్పష్టమైన, చర్యలు తీసుకోగలిగే ఈవెంట్‌లుగా మారుస్తారు. కోడ్ పరిమాణం కొంచెం పెరిగినప్పటికీ, అది మీకు డేటా విశ్వసనీయతను మరియు వినియోగదారుల నమ్మకాన్ని అందిస్తుంది—ఈ రెండింటినీ సైలెంట్ సక్సెస్ ఎప్పటికీ అందించలేదు.