ਇੱਕ CRM ਵਿੱਚ ਵੀਹ ਸੰਪਰਕਾਂ (contacts) ਨੂੰ ਆਰਕਾਈਵ (archive) ਕੀਤਾ ਜਾਣਾ ਸੀ, ਫਿਰ ਵੀ UI 'ਤੇ ਇੱਕ ਹਰਾ ਸਫਲਤਾ ਬੈਜ (success badge) ਦਿਖਾਈ ਦਿੱਤਾ ਅਤੇ ਕਾਰਜ ਚੁੱਪਚਾਪ ਕੁਝ ਵੀ ਨਹੀਂ ਕੀਤਾ। ਇੱਕ TypeScript ਹੈਲਪਰ ਜੋ Supabase-JS ਮਿਊਟੇਸ਼ਨਾਂ (mutations) ਵਿੱਚ error ਫੀਲਡ ਨੂੰ ਲਾਜ਼ਮੀ ਬਣਾਉਂਦਾ ਹੈ, ਹੁਣ ਡਿਵੈਲਪਰਾਂ ਨੂੰ ਉਸ ਅਸਫਲਤਾ ਦਾ ਸਾਹਮਣਾ ਕਰਨ ਲਈ ਮਜਬੂਰ ਕਰਦਾ ਹੈ, ਨਾ ਕਿ ਇਸਨੂੰ ਨਜ਼ਰਅੰਦਾਜ਼ ਕਰਨ ਲਈ।
ਕਿਉਂ Supabase-JS ਦਾ ਰਿਟਰਨ ਸ਼ੇਪ (return shape) ਇੱਕ ਜਾਲ ਹੈ
Supabase ਦਾ JavaScript ਕਲਾਇੰਟ (@supabase/supabase-js) ਡਾਟਾਬੇਸ ਰਾਈਟ (database write) ਰੱਦ ਹੋਣ 'ਤੇ ਕੋਈ ਐਕਸੈਪਸ਼ਨ (exception) ਨਹੀਂ ਸੁੱਟਦਾ। ਇਸ ਦੀ ਬਜਾਏ, ਇਹ ਇੱਕ ਆਬਜੈਕਟ { data, error } ਦੇ ਨਾਲ ਪ੍ਰੋਮਿਸ (promise) ਨੂੰ ਰੈਜ਼ੋਲਵ (resolve) ਕਰਦਾ ਹੈ। ਜੇਕਰ ਕੋਈ ਰੋ-ਲੈਵਲ ਸੁਰੱਖਿਆ (RLS) ਪਾਲਿਸੀ, ਯੂਨੀਕ-ਕੀ ਵਿਓਲੇਸ਼ਨ (unique-key violation), ਜਾਂ ਕੋਈ ਹੋਰ ਕੰਸਟ੍ਰੇਂਟ (constraint) ਕੁਐਰੀ ਨੂੰ ਰੋਕਦਾ ਹੈ, ਤਾਂ data null ਵਜੋਂ ਵਾਪਸ ਆਉਂਦਾ ਹੈ ਅਤੇ error ਵਿੱਚ ਡਾਟਾਬੇਸ ਦਾ ਸੁਨੇਹਾ ਹੁੰਦਾ ਹੈ। ਕਲਾਇੰਟ ਇਹ ਮੰਨ ਕੇ ਚੱਲਦਾ ਹੈ ਕਿ ਕਾਲਰ error ਦੀ ਜਾਂਚ ਕਰੇਗਾ; ਇਹ ਕਾਲ ਨੂੰ ਕਦੇ ਵੀ ਰੋਕਦਾ (abort) ਨਹੀਂ ਹੈ।
ਅਸਲ ਵਿੱਚ, ਕਈ ਕੋਡਬੇਸ (codebases) ਇਸ ਕਾਲ ਨੂੰ 'ਫਾਇਰ-ਐਂਡ-ਫੋਰਗੇਟ' (fire-and-forget) ਕਾਰਜ ਵਜੋਂ ਮੰਨਦੇ ਹਨ:
await supabase
.from('contacts')
.update({ statut: 'ancien', archived_at: now })
.eq('id', id)
return { ok: true }
ਜਦੋਂ update ਨੂੰ RLS ਨਿਯਮ ਦੁਆਰਾ ਰੋਕਿਆ ਜਾਂਦਾ ਹੈ, ਤਾਂ ਪ੍ਰੋਮਿਸ ਫਿਰ ਵੀ ਰੈਜ਼ੋਲਵ ਹੋ ਜਾਂਦਾ ਹੈ। ਕਿਉਂਕਿ ਡਿਵੈਲਪਰ ਕਦੇ ਵੀ { error } ਨੂੰ ਡੈਸਟ੍ਰਕਚਰ (destructure) ਨਹੀਂ ਕਰਦਾ, ਇਸ ਲਈ ਅਸਫਲਤਾ ਦਿਖਾਈ ਨਹੀਂ ਦਿੰਦੀ। ਫੰਕਸ਼ਨ { ok: true } ਰਿਟਰਨ ਕਰਦਾ ਹੈ, UI ਸਫਲਤਾ ਦਿਖਾਉਂਦਾ ਹੈ, ਅਤੇ ਡਾਟਾ ਬਦਲਿਆ ਨਹੀਂ ਜਾਂਦਾ। ਕੋਈ ਲੌਗ (logs) ਨਹੀਂ ਦਿਖਾਈ ਦਿੰਦੇ, ਕੋਈ Sentry ਅਲਰਟ ਨਹੀਂ ਚੱਲਦਾ, ਅਤੇ ਬੱਗ (bug) ਕਈ ਦਿਨਾਂ ਤੱਕ ਰਹਿ ਸਕਦਾ ਹੈ।
ਇੱਕ ਲਿੰਟਰ (linter) ਕਾਫ਼ੀ ਨਹੀਂ ਹੈ
ਸਟੈਟਿਕ ਐਨਾਲਿਸਿਸ ਟੂਲ (Static analysis tools) ਚੇਤਾਵਨੀ ਦੇ ਸਕਦੇ ਹਨ ਜਦੋਂ error ਪ੍ਰਾਪਰਟੀ ਨੂੰ ਨਜ਼ਰਅੰਦਾਜ਼ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਪਰ ਉਹ ਰਨਟਾਈਮ ਕੰਟਰੈਕਟ (runtime contract) ਨੂੰ ਲਾਗੂ ਨਹੀਂ ਕਰ ਸਕਦੇ। ਇੱਕ ਡਿਵੈਲਪਰ ਅਜੇ ਵੀ const _ = await … ਲਿਖ ਸਕਦਾ ਹੈ ਅਤੇ ਚੇਤਾਵਨੀ ਨੂੰ ਚੁੱਪ ਕਰਾ ਸਕਦਾ ਹੈ, ਜਾਂ ਉਹ ਨਿਯਮ ਨੂੰ ਦਬਾਉਣ ਲਈ ਇੱਕ ਕੁਮੈਂਟ ਜੋੜ ਸਕਦਾ ਹੈ। ਅਸਲ ਸਮੱਸਿਆ ਇਹ ਹੈ ਕਿ ਟਾਈਪ ਸਿਸਟਮ error ਦਾ ਜ਼ਿਕਰ ਕੀਤੇ ਬਿਨਾਂ ਹੀ ਕਾਲ ਨੂੰ ਸਫਲ ਹੋਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿੰਦਾ ਹੈ।
mutate() ਹੈਲਪਰ: ਐਰਰ ਹੈਂਡਲਿੰਗ ਨੂੰ ਲਾਜ਼ਮੀ ਬਣਾਉਣਾ
ਲੇਖਕ ਨੇ mutate() ਨਾਮ ਦਾ ਇੱਕ ਛੋਟਾ ਵੈਪਰ (wrapper) ਬਣਾਇਆ ਹੈ ਜੋ ਰਿਟਰਨ ਟਾਈਪ ਦੇ ਸ਼ੇਪ ਨੂੰ ਬਦਲ ਦਿੰਦਾ ਹੈ। { data, error } ਦੀ ਬਜਾਏ, ਹੈਲਪਰ ਇੱਕ ਟੂਪਲ (tuple) [data, error] ਰਿਟਰਨ ਕਰਦਾ ਹੈ ਜਿੱਥੇ 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 ਇੰਸਟ੍ਰੂਮੈਂਟੇਸ਼ਨ (instrumentation) ਨੂੰ ਵੀ ਇੰਜੈਕਟ ਕਰਦਾ ਹੈ, ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਹਰ ਡਾਟਾਬੇਸ ਰੈਜੈਕਸ਼ਨ (rejection) ਨੂੰ ਲੌਗ ਕੀਤਾ ਜਾਵੇ, ਭਾਵੇਂ ਕਾਲਰ ਬਾਅਦ ਵਿੱਚ ਇਸਨੂੰ ਨਜ਼ਰਅੰਦਾਜ਼ ਕਰ ਦੇਵੇ।
ਕੀ ਖਤਰੇ ਵਿੱਚ ਹੈ
- ਡਾਟਾ ਇੰਟੈਗਰਿਟੀ (Data integrity) – ਚੁੱਪਚਾਪ ਹੋਣ ਵਾਲੀਆਂ ਅਸਫਲਤਾਵਾਂ ਗਲਤ ਸਟੇਟ ਨੂੰ ਪ੍ਰੋਡਕਸ਼ਨ ਵਿੱਚ ਆਉਣ ਦਿੰਦੀਆਂ ਹਨ। ਇੱਕ ਆਰਕਾਈਵ ਕੀਤਾ ਸੰਪਰਕ ਜੋ ਕਦੇ ਵੀ ਐਕਟਿਵ ਲਿਸਟ ਤੋਂ ਬਾਹਰ ਨਹੀਂ ਗਿਆ, ਉਹ ਅਗਲੇਰੀ ਰਿਪੋਰਟਾਂ ਨੂੰ ਗਲਤ ਕਰ ਸਕਦਾ ਹੈ।
- ਯੂਜ਼ਰ ਭਰੋਸਾ (User trust) – ਇੱਕ UI ਜੋ ਸਫਲਤਾ ਦਾ ਦਾਅਵਾ ਕਰਦਾ ਹੈ ਜਦੋਂ ਕੁਝ ਵੀ ਨਹੀਂ ਬਦਲਿਆ, ਉਹ ਵਿਸ਼ਵਾਸ ਨੂੰ ਘਟਾਉਂਦਾ ਹੈ। ਗਾਹਕ "archived" ਦੇਖਦੇ ਹਨ ਪਰ ਫਿਰ ਵੀ ਸਰਚ ਵਿੱਚ ਸੰਪਰਕ ਲੱਭ ਲੈਂਦੇ ਹਨ।
- ਡਿਵੈਲਪਰ ਦਾ ਸਮਾਂ (Developer time) – ਭਵਿੱਖ ਦੇ ਅਣਜਾਣ ਬੱਗਸ (phantom bugs) ਦਾ ਪਿੱਛਾ ਕਰਨਾ ਘੰਟਿਆਂ ਬਰਬਾਦ ਕਰਦਾ ਹੈ। ਸਪੱਸ਼ਟ ਐਰਰ ਹੈਂਡਲਿੰਗ ਅਸਫਲਤਾ ਦੇ ਬਿੰਦੂ 'ਤੇ ਹੀ ਸਮੱਸਿਆ ਨੂੰ ਸਾਹਮਣੇ ਲਿਆਉਂਦੀ ਹੈ, ਜਿਸ ਨਾਲ ਡੀਬੱਗਿੰਗ ਲੂਪ ਛੋਟਾ ਹੋ ਜਾਂਦਾ ਹੈ।
- ਕਾਰਜਸ਼ੀਲ ਲਾਗਤ (Operational cost) – ਚੁੱਪਚਾਪ ਡਾਟਾ ਨੁਕਸਾਨ ਦੀ ਘਟਨਾ ਦੀ ਲਾਗਤ ਦੇ ਮੁਕਾਬਲੇ ਕੁਝ ਵਾਧੂ ਲਾਈਨਾਂ ਦਾ ਕੋਡ ਅਤੇ ਇੱਕ ਛੋਟਾ ਵੈਪਰ ਜੋੜਨਾ ਨਗਾਨੀ ਹੈ।
ਸਮਝੌਤਾ (The trade-off)
ਹੈਲਪਰ ਵਰਬੋਸਿਟੀ (verbosity) ਵਧਾਉਂਦਾ ਹੈ: ਹਰ ਮਿਊਟੇਸ਼ਨ ਕਾਲ ਹੁਣ ਇੱਕ ਟੂਪਲ ਰਿਟਰਨ ਕਰਦੀ ਹੈ, ਅਤੇ ਕਾਲਰਾਂ ਨੂੰ if (err) ਬਲਾਕ ਲਿਖਣਾ ਪਵੇਗਾ। ਕੁਝ ਟੀਮਾਂ ਇਸਨੂੰ ਬੋਇਲਰਪਲੇਟ ਨੋਇਜ਼ (boilerplate noise) ਵਜੋਂ ਦੇਖ ਸਕਦੀਆਂ ਹਨ, ਖਾਸ ਕਰਕੇ ਸਧਾਰਨ CRUD ਐਕਸ਼ਨਾਂ ਲਈ ਜਿੱਥੇ ਉਹ ਸਫਲਤਾ ਦੀ ਉਮੀਦ ਕਰਦੇ ਹਨ। ਵਿਰੋਧੀ ਦਲੀਲ ਇਹ ਹੈ ਕਿ ਵਾਧੂ ਕੋਡ ਇੱਕ ਸੁਰੱਖਿਆ ਹੈ, ਕੋਈ ਵਿਕਲਪਿਕ ਵਿਸ਼ੇਸ਼ਤਾ ਨਹੀਂ। ਉਹਨਾਂ ਵਾਤਾਵਰਣਾਂ ਵਿੱਚ ਜਿੱਥੇ ਡਾਟਾ ਦੀ ਸਹੀਤਾ ਸਭ ਤੋਂ ਮਹੱਤਵਪੂਰਨ ਹੈ—CRM ਸਿਸਟਮ, ਵਿੱਤ, ਸਿਹਤ—ਚੈੱਕ ਕਰਨਾ ਲਾਜ਼ਮੀ ਬਣਾਉਣਾ ਆਪਣੇ ਆਪ ਵਿੱਚ ਫਾਇਦੇਮੰਦ ਹੈ।
ਅੱਗੇ ਕੀ ਹੈ
ਲੇਖਕ ਤੀਜੇ ਭਾਗ ਦਾ ਵਾਅਦਾ ਕਰਦਾ ਹੈ ਜੋ ਬਿਨਾਂ ਕਿਸੇ ਵਿਆਖਿਆ ਦੇ ਜ਼ੀਰੋ ਰੋਅ (zero rows) ਰਿਟਰਨ ਕਰਨ ਵਾਲੀਆਂ RLS ਪਾਲਿਸੀਆਂ ਦੀ ਜਾਂਚ ਕਰੇਗਾ। ਉਹ ਪੈਟਰਨ, ਚੁੱਪਚਾਪ-ਐਰਰ ਕੇਸ ਵਾਂਗ, ਇੱਕ ਦਿਖਣ ਵਿੱਚ ਸਫਲ ਕੁਐਰੀ ਦੇ ਪਿੱਛੇ ਅਸਫਲਤਾਵਾਂ ਨੂੰ ਲੁਕਾਉਂਦਾ ਹੈ। ਇਕੱਠੇ ਮਿਲ ਕੇ, ਇਸ ਲੜੀ ਦਾ ਉਦੇਸ਼ Supabase ਦੇ API ਦੇ "ਰੂਮਰ" (rumor) ਪੱਖ ਨੂੰ ਉਜਾਗਰ ਕਰਨਾ ਅਤੇ ਡਿਵੈਲਪਰਾਂ ਨੂੰ ਤੱਥਾਂ ਦੀ ਮੰਗ ਕਰਨ ਲਈ ਠੋਸ ਸਾਧਨ ਦੇਣਾ ਹੈ।
ਸਿੱਖਿਆ (Takeaway): Supabase-JS ਦਾ ਡਿਜ਼ਾਈਨ ਇੱਕ ਅਸਫਲ ਰਾਈਟ ਨੂੰ ਸਫਲਤਾ ਵਾਂਗ ਦਿਖਾਉਣ ਦਿੰਦਾ ਹੈ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ error ਫੀਲਡ ਨੂੰ ਪੜ੍ਹਨਾ ਯਾਦ ਨਹੀਂ ਰੱਖਦੇ। ਕਾਲਾਂ ਨੂੰ TypeScript-ਲਾਗੂ ਹੈਲਪਰ ਵਿੱਚ ਲਪੇਟ ਕੇ, ਜੋ error ਨੂੰ ਲਾਜ਼ਮੀ ਬਣਾਉਂਦਾ ਹੈ ਅਤੇ ਇਸਨੂੰ Sentry ਵਿੱਚ ਲੌਗ ਕਰਦਾ ਹੈ, ਤੁਸੀਂ ਚੁੱਪਚਾਪ ਹੋਣ ਵਾਲੀਆਂ ਅਸਫਲਤਾਵਾਂ ਨੂੰ ਦਿਖਾਈ ਦੇਣਯੋਗ, ਕਾਰਵਾਈਯੋਗ ਘਟਨਾਵਾਂ ਵਿੱਚ ਬਦਲ ਦਿੰਦੇ ਹੋ। ਕੋਡ ਦੇ ਆਕਾਰ ਵਿੱਚ ਮਾਮੂਲੀ ਵਾਧਾ ਤੁਹਾਨੂੰ ਡਾਟਾ ਭਰੋਸੇਯੋਗਤਾ ਅਤੇ ਯੂਜ਼ਰ ਭਰੋਸਾ ਦਿੰਦਾ ਹੈ—ਦੋ ਚੀਜ਼ਾਂ ਜੋ ਕੋਈ ਵੀ ਚੁੱਪਚਾਪ ਸਫਲਤਾ ਕਦੇ ਨਹੀਂ ਦੇ ਸਕਦੀ।
