Odczytywanie i zapisywanie danych za pomocą języka GraphQL w aplikacjach Fabric

Fabric Apps udostępnia bezpiecznego dla typu klienta GraphQL, który umożliwia wykonywanie operacji tworzenia, odczytu, aktualizowania i usuwania bez zapisywania nieprzetworzonych zapytań. Klient automatycznie generuje zapytania GraphQL na podstawie wywołań metod i zwraca typowane encje zgodnie z definicjami modelu danych.

Wymagania wstępne

  • Projekt Fabric Apps ze zdefiniowanymi modelami danych. Zobacz Definiowanie modeli danych.
  • Usługi zaplecza uruchomione lokalnie lub wdrożone w Fabric.

Inicjowanie klienta

Zainicjuj RayfinClient za pomocą adresu URL backendu, klucza publicznego i typu schematu:

import { RayfinClient } from '@microsoft/rayfin-client';
import type { Note } from '../rayfin/data/Note';
import type { Notebook } from '../rayfin/data/Notebook';

type AppSchema = { 
  Note: Note;
  Notebook: Notebook;
};

const client = new RayfinClient<AppSchema>({
  baseUrl: import.meta.env.VITE_RAYFIN_API_URL ?? 'http://localhost:5168',
  publishableKey: 'pk-your-project-key',
});

Argument typu ogólnego umożliwia językowi TypeScript zapewnienie autouzupełniania i sprawdzania typów dla wszystkich operacji danych.

Odczyt danych

Uzyskiwanie dostępu do kolekcji jednostek za pośrednictwem elementu client.data.<EntityName>. Płynny interfejs API udostępnia metody wykonywania zapytań, filtrowania, sortowania i stronicowania.

Pobieranie wszystkich rekordów

const notes = await client.data.Note.select([
  'id',
  'title',
  'content',
  'createdAt',
  'isPinned',
]).execute();

Pobrać pojedynczy rekord według klucza podstawowego

const note = await client.data.Note.findByPk('00000000-0000-0000-0000-000000000000');

Zwraca pełną encję lub null, jeśli nie istnieje żaden rekord o takim identyfikatorze.

Filtrowanie rekordów

where() Użyj metody , aby filtrować wyniki:

const pinnedNotes = await client.data.Note.select([
  'id',
  'title',
  'isPinned',
])
  .where({ isPinned: { eq: true } })
  .execute();

Operatory filtra

Obsługujący Opis Example
eq Równa się { status: { eq: 'active' } }
ne Nie jest równe { status: { ne: 'archived' } }
gt Większe niż { age: { gt: 18 } }
gte Większe niż lub równe { age: { gte: 21 } }
lt Mniejsze niż { price: { lt: 100 } }
lte Mniejsze lub równe { price: { lte: 50 } }
contains Zawiera podciąg { title: { contains: 'draft' } }

Sortowanie wyników

Użyj orderBy() polecenia , aby posortować wyniki zapytania:

const notes = await client.data.Note.select([
  'id',
  'title',
  'createdAt',
])
  .orderBy({ createdAt: 'desc' })
  .execute();

Sortuj według wielu kolumn:

const notes = await client.data.Note.select([
  'id',
  'title',
  'isPinned',
  'createdAt',
])
  .orderBy({ isPinned: 'desc' })
  .orderBy({ createdAt: 'desc' })
  .execute();

Podczas definiowania relacji za pomocą dekoratorów @one() i @many() możesz uwzględnić pola powiązanych encji w tym samym zapytaniu:

const notes = await client.data.Note.select([
  'id',
  'title',
  'content',
  'notebook.id',
  'notebook.name',
  'notebook.color',
])
  .execute();

Każda notatka zawiera skojarzone z nim dane notesu bez konieczności oddzielnego zapytania.

Stronicowanie dużych zestawów wyników

Użyj stronicowania opartego na kursorach dla dużych list:

const page = await client.data.Note.select([
  'id',
  'title',
  'createdAt',
])
  .orderBy({ createdAt: 'desc' })
  .first(25)
  .executePaginated();

console.log('Items:', page.items);
console.log('Has next page:', page.hasNextPage);
console.log('End cursor:', page.endCursor);

Pobierz następną stronę przy użyciu kursora:

if (page.hasNextPage) {
  const nextPage = await client.data.Note.select([
    'id',
    'title',
    'createdAt',
  ])
    .orderBy({ createdAt: 'desc' })
    .first(25)
    .after(page.endCursor)
    .executePaginated();
}

Uwaga / Notatka

Właściwość totalCount pojawia się w typie PagedResult, ale nie jest uzupełniana przez backend. Użyj items.length, aby policzyć wyniki na aktualnej stronie.

Tworzenie rekordów

create() Użyj metody , aby wstawić nowe rekordy:

const newNote = await client.data.Note.create({
  title: 'Meeting notes',
  content: 'Discussion points from the team sync',
  isPinned: false,
  isArchived: false,
  createdAt: new Date(),
  updatedAt: new Date(),
  user_id: 'user-123',
});

Metoda zwraca utworzoną encję ze wszystkimi polami wypełnionymi, w tym z automatycznie wygenerowanym polem id.

Utwórz rekordy z relacjami

Podczas tworzenia jednostek, które mają relacje, przekaż pełny obiekt powiązany lub obiekt z tylko kluczem podstawowym:

// Option 1: Pass just the ID
const note = await client.data.Note.create({
  title: 'Weekly summary',
  content: 'Summary of this week',
  notebook: { id: 'notebook-456' },
  isPinned: false,
  isArchived: false,
  createdAt: new Date(),
  updatedAt: new Date(),
});

// Option 2: Pass the full object
const notebook = await client.data.Notebook.findByPk('notebook-456');
const note = await client.data.Note.create({
  title: 'Weekly summary',
  content: 'Summary of this week',
  notebook: notebook,
  isPinned: false,
  isArchived: false,
  createdAt: new Date(),
  updatedAt: new Date(),
});

Oba formularze generują ten sam wynik. Użyj pierwszego formularza, gdy znasz już identyfikator powiązanej jednostki i chcesz uniknąć dodatkowego pobierania.

Aktualizacja rekordów

update() Użyj metody , aby zmodyfikować istniejące rekordy. Przekaż obiekt filtru i obiekt zawierający pola, aby zaktualizować:

await client.data.Note.update(
  { id: 'note-123' },
  {
    title: 'Updated title',
    updatedAt: new Date(),
  }
);

Aktualizowanie relacji

Aby zmienić relację, przekaż nową powiązaną jednostkę lub tylko jej identyfikator:

// Move a note to a different notebook
await client.data.Note.update(
  { id: 'note-123' },
  { notebook: { id: 'new-notebook-789' } }
);

Usuwanie rekordów

delete() Użyj metody , aby usunąć rekordy pasujące do filtru:

await client.data.Note.delete({ id: 'note-123' });

Metoda kończy się po potwierdzeniu usunięcia przez backend. Jeśli żaden rekord nie jest zgodny z filtrem, metoda nadal powiedzie się.

Obsługa uwierzytelniania

Po włączeniu uwierzytelniania zaloguj się przed wykonaniem operacji na danych:

await client.auth.signIn({ email, password });

// All subsequent data calls include authentication context
const notes = await client.data.Note.select(['id', 'title']).execute();

Klient automatycznie dołącza sesję uwierzytelniania do wszystkich wywołań interfejsu API danych. Nie musisz przekazywać tokenów ręcznie.

Najlepsze rozwiązania

  • Wybierz tylko wymagane pola — pobierz tylko pola, których używasz, aby zmniejszyć rozmiar ładunku i zwiększyć wydajność.
  • Użyj stronicowania dla dużych list — unikaj pobierania tysięcy rekordów jednocześnie przy użyciu elementów first() i executePaginated().
  • Zapytania dotyczące relacji wsadowych — uwzględniaj powiązane pola jednostek w tym samym zapytaniu, a nie wysyłaj oddzielnych żądań.
  • Buforowanie często używanych danych — przechowuj statyczne dane referencyjne w pamięci, aby zmniejszyć liczbę wywołań interfejsu API.

Bieżące ograniczenia

  • Metoda count() nie jest dostępna w kliencie Fluent. Wybierz minimalne pola i użyj results.length zamiast tego.
  • Relacje wiele-do-wielu nie są obsługiwane. Użyj jawnie zdefiniowanej encji łączącej z dwoma @one() dekoratorami nawigacyjnymi.
  • Właściwość totalCount w PagedResult nie jest uzupełniana przez backend.