Čtení a zápis dat pomocí GraphQL v Fabric Apps

Fabric Apps poskytuje typově bezpečného klienta GraphQL, který umožňuje provádět operace vytváření, čtení, aktualizace a odstraňování bez psaní nezpracovaných dotazů. Klient automaticky generuje GraphQL z volání vaší metody a vrací zadané entity na základě definic datového modelu.

Předpoklady

  • Projekt Fabric Apps s definovanými datovými modely. Viz Definice datových modelů.
  • Back-endové služby spuštěné místně nebo nasazené do Fabric.

Inicializace klienta

Vytvořte instanci objektu RayfinClient s adresou URL backendu, veřejným klíčem a typem schématu:

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 obecného typu umožňuje TypeScriptu poskytovat automatické dokončování a kontrolu typů pro všechny operace s daty.

Čtení dat

Přístup k kolekcům entit prostřednictvím client.data.<EntityName>. Rozhraní API fluent poskytuje metody pro dotazování, filtrování, řazení a stránkování.

Načíst všechny záznamy

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

Načtení jednoho záznamu podle primárního klíče

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

Vrátí celou entitu nebo null, pokud neexistuje žádný záznam se zadaným ID.

Filtrování záznamů

where() Pomocí metody můžete filtrovat výsledky:

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

Operátory filtru

Operator Description Example
eq Rovná se { status: { eq: 'active' } }
ne Nerovná se { status: { ne: 'archived' } }
gt Je větší než { age: { gt: 18 } }
gte Větší nebo rovno { age: { gte: 21 } }
lt Méně než { price: { lt: 100 } }
lte Menší než nebo rovno { price: { lte: 50 } }
contains Obsahuje podřetězce { title: { contains: 'draft' } }

Řazení výsledků

Slouží orderBy() k řazení výsledků dotazu:

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

Seřadit podle více sloupců:

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

Když definujete relace s @one() a @many() dekorátory, můžete do stejného dotazu zahrnout související pole entit:

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

Každá poznámka obsahuje přidružená data poznámkového bloku bez nutnosti samostatného dotazu.

Stránkování velkých sad výsledků

Pro velké seznamy používejte stránkování založené na kurzorech:

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);

Načtěte další stránku pomocí kurzoru:

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

Poznámka:

Vlastnost totalCount se objevuje u typu PagedResult, ale backend ji nevyplňuje. Slouží items.length k počítání výsledků na aktuální stránce.

Vytvoření záznamů

create() Pomocí metody vložte nové záznamy:

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 vrátí vytvořenou entitu se všemi vyplněnými poli, včetně automaticky vygenerované id.

Vytvořte záznamy s vazbami

Při vytváření entit s relacemi předejte celý související objekt nebo objekt pouze s primárním klíčem:

// 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 formuláře vytvoří stejný výsledek. První formulář použijte, pokud už znáte ID související entity a chcete se vyhnout dodatečnému načtení.

Aktualizovat záznamy

Použijte metodu k úpravě update() existujících záznamů. Předejte objekt filtru a objekt obsahující pole, která chcete aktualizovat:

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

Aktualizace relací

Pokud chcete změnit relaci, předejte novou související entitu nebo jen její ID:

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

Odstranění záznamů

delete() Pomocí metody odeberte záznamy odpovídající filtru:

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

Metoda se vyřeší, když back-end potvrdí odstranění. Pokud se filtr neshoduje s žádnými záznamy, metoda bude i nadále úspěšná.

Správa ověřování

Pokud je povolené ověřování, přihlaste se před provedením operací s daty:

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

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

Klient automaticky připojí ověřovací relaci ke všem voláním rozhraní API pro data. Tokeny nemusíte předávat ručně.

Osvědčené postupy

  • Vyberte pouze potřebná pole – Načtěte pouze pole, která používáte, abyste snížili objem přenášených dat a zvýšili výkon.
  • Používejte stránkování pro velké seznamy – Vyhněte se načítání tisíců záznamů najednou pomocí first() a executePaginated().
  • Dávkové relační dotazy – Zahrňte do stejného dotazu pole souvisejících entit, místo abyste odesílali samostatné požadavky.
  • Ukládání často řízených dat do mezipaměti – Ukládání statických referenčních dat do paměti za účelem omezení volání rozhraní API

Aktuální omezení

  • Metoda count() není k dispozici u fluent klienta. Vyberte minimální pole a místo toho použijte results.length .
  • Vztahy mnoho k mnoha nejsou podporovány. Použijte explicitní propojovací entitu se dvěma @one() navigačními dekorátory.
  • Backendem se vlastnost totalCount u PagedResult nenaplňuje.