refactor(account): isRowMissing als gemeinsame Hilfsfunktion statt dreier Kopien
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0ad51bf7c6
commit
04404ffdae
5 files changed
+40
-22
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { errorMessage, errorType, isInvalidLinkError, isUnauthorized, type ErrorContext } from './errors';
|
||||
import { errorMessage, errorType, isInvalidLinkError, isRowMissing, isUnauthorized, type ErrorContext } from './errors';
|
||||
|
||||
/** Fehler wie vom SDK (AppwriteException): Felder code, type, message. */
|
||||
const fail = (code: number, type: string, message = '') => ({ code, type, message });
|
||||
@@ -149,6 +149,33 @@ describe('errorType', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isRowMissing', () => {
|
||||
it('404 mit row_not_found heißt: die Zeile gibt es nicht (oder nicht für mich)', () => {
|
||||
expect(isRowMissing(fail(404, 'row_not_found'))).toBe(true);
|
||||
});
|
||||
|
||||
it('404 ohne Typ (leer oder fehlend) zählt ebenso', () => {
|
||||
expect(isRowMissing(fail(404, ''))).toBe(true);
|
||||
expect(isRowMissing({ code: 404 })).toBe(true);
|
||||
});
|
||||
|
||||
it('eine fehlende Tabelle, Datenbank oder Datei ist ein echter Fehler, kein „Zeile weg“', () => {
|
||||
for (const type of ['table_not_found', 'database_not_found', 'storage_file_not_found']) {
|
||||
expect(isRowMissing(fail(404, type)), type).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('andere Status und Nicht-Fehler nicht', () => {
|
||||
expect(isRowMissing(fail(401, 'row_not_found'))).toBe(false);
|
||||
expect(isRowMissing(fail(500, 'row_not_found'))).toBe(false);
|
||||
expect(isRowMissing({ code: '404', type: 'row_not_found' })).toBe(false);
|
||||
expect(isRowMissing(new TypeError('Failed to fetch'))).toBe(false);
|
||||
expect(isRowMissing('row_not_found')).toBe(false);
|
||||
expect(isRowMissing(null)).toBe(false);
|
||||
expect(isRowMissing(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isInvalidLinkError (Passwort-neu-Seite)', () => {
|
||||
it('Link-Fehler', () => {
|
||||
expect(isInvalidLinkError(fail(401, 'user_invalid_token'))).toBe(true);
|
||||
|
||||
@@ -24,6 +24,15 @@ export function isUnauthorized(err: unknown): boolean {
|
||||
return field(err, 'code') === 401;
|
||||
}
|
||||
|
||||
/**
|
||||
* „Die Zeile gibt es nicht (oder nicht für mich)“: 404 `row_not_found` (auch ein 404 ohne Typ). Eine fehlende Tabelle, Datenbank oder
|
||||
* Datei ist dagegen ein echter Fehler. Die Einzel-Abfragen der Tabellen (`getGalleryCard`, `getLogo`, `getUsername`) werten damit 404 als „nicht da“.
|
||||
*/
|
||||
export function isRowMissing(err: unknown): boolean {
|
||||
const type = field(err, 'type');
|
||||
return field(err, 'code') === 404 && (type === 'row_not_found' || type === undefined || type === '');
|
||||
}
|
||||
|
||||
/** Bei `general_argument_invalid` nennt die Nachricht den Parameter: „Invalid `email` param: …“. */
|
||||
function invalidParam(err: unknown): string | null {
|
||||
const message = field(err, 'message');
|
||||
|
||||
@@ -9,6 +9,7 @@ import { API_MESSAGES } from '../i18n/api-messages';
|
||||
import { msg, t } from '../i18n/i18n';
|
||||
import { IDS, tables } from './appwrite';
|
||||
import { currentUserId } from './auth';
|
||||
import { isRowMissing } from './errors';
|
||||
|
||||
/** Wie im Dienst (deploy/api/common.js): 3–20 Zeichen, das erste ein Buchstabe oder eine Zahl, danach Buchstaben, Zahlen, `.`, `_`, `-`. */
|
||||
export const USERNAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{2,19}$/;
|
||||
@@ -112,13 +113,6 @@ export function myUsername(): string | null {
|
||||
|
||||
// ---- Lesen --------------------------------------------------------------------------------------------------
|
||||
|
||||
/** „Es gibt kein Profil (oder keines für mich)“; eine fehlende Tabelle oder Datenbank ist dagegen ein echter Fehler. */
|
||||
function isRowMissing(err: unknown): boolean {
|
||||
if (typeof err !== 'object' || err === null) return false;
|
||||
const { code, type } = err as { code?: unknown; type?: unknown };
|
||||
return code === 404 && (type === 'row_not_found' || type === undefined || type === '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Name eines Kontos. Hat es kein Profil, ist das Ergebnis null (Appwrite antwortet mit 404); eine ID, die keine Appwrite-ID sein
|
||||
* kann, ergibt null ohne Anfrage. Andere Fehler (Netz, Server) gehen durch.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { AppwriteException, Query, type Models } from 'appwrite';
|
||||
import { ID_PATTERN, fetchFile } from '../account/cards';
|
||||
import { IDS, tables } from '../account/appwrite';
|
||||
import { isRowMissing } from '../account/errors';
|
||||
import { msg } from '../i18n/i18n';
|
||||
|
||||
export interface GalleryCard {
|
||||
@@ -112,13 +113,6 @@ export async function listGallery(opts: GalleryOptions): Promise<{ cards: Galler
|
||||
return { cards, nextCursor: cards.length === PAGE_SIZE ? cards[cards.length - 1].id : null };
|
||||
}
|
||||
|
||||
/** „Die Zeile gibt es nicht (oder nicht für mich)“; fehlende Tabelle oder Datenbank ist dagegen ein echter Fehler. */
|
||||
function isRowMissing(err: unknown): boolean {
|
||||
if (typeof err !== 'object' || err === null) return false;
|
||||
const { code, type } = err as { code?: unknown; type?: unknown };
|
||||
return code === 404 && (type === 'row_not_found' || type === undefined || type === '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Eine Karte per ID. Gibt es sie nicht oder ist sie für mich ausgeblendet (Appwrite antwortet beides mit 404), ist das
|
||||
* Ergebnis null. Eine ID, die keine Appwrite-ID sein kann, ergibt null ohne Anfrage.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { AppwriteException, Query, type Models } from 'appwrite';
|
||||
import { ID_PATTERN, fetchFile } from '../account/cards';
|
||||
import { IDS, tables } from '../account/appwrite';
|
||||
import { isRowMissing } from '../account/errors';
|
||||
|
||||
export interface CommunityLogo {
|
||||
id: string;
|
||||
@@ -95,13 +96,6 @@ export async function listLogos(opts: LogoListOptions): Promise<{ logos: Communi
|
||||
return { logos, nextCursor: logos.length === LOGO_PAGE_SIZE ? logos[logos.length - 1].id : null };
|
||||
}
|
||||
|
||||
/** „Die Zeile gibt es nicht (oder nicht für mich)“; fehlende Tabelle oder Datenbank ist dagegen ein echter Fehler. */
|
||||
function isRowMissing(err: unknown): boolean {
|
||||
if (typeof err !== 'object' || err === null) return false;
|
||||
const { code, type } = err as { code?: unknown; type?: unknown };
|
||||
return code === 404 && (type === 'row_not_found' || type === undefined || type === '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ein Logo per ID. Gibt es das Logo nicht oder ist es für mich ausgeblendet oder gelöscht (Appwrite antwortet beides mit 404),
|
||||
* ist das Ergebnis null. Eine ID, die keine Appwrite-ID sein kann, ergibt null ohne Anfrage.
|
||||
|
||||
Reference in new issue
Block a user