mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-07-30 03:09:50 +08:00
120 lines
5.1 KiB
Markdown
120 lines
5.1 KiB
Markdown
|
|
# Migration — old Data SDK → `@salesforce/platform-sdk`
|
||
|
|
|
||
|
|
The Data SDK changed in two breaking ways (PR #502, shipped in `@salesforce/platform-sdk`
|
||
|
|
v10.10.1):
|
||
|
|
|
||
|
|
1. **Package renamed** — `@salesforce/sdk-data` → **`@salesforce/platform-sdk`**.
|
||
|
|
2. **`sdk.graphql` reshaped** from a **callable method** into a **namespace** with `.query()`
|
||
|
|
and `.mutate()`, both taking an **options object**.
|
||
|
|
|
||
|
|
> Any remaining `@salesforce/sdk-data` strings in the webapps repo are **stale `dist/` build
|
||
|
|
> artifacts only** — not canonical. Always import from `@salesforce/platform-sdk`.
|
||
|
|
|
||
|
|
This is the **only** document where the dead callable API appears, for comparison. Everywhere
|
||
|
|
else in this skill uses the new API exclusively.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Import
|
||
|
|
|
||
|
|
```diff
|
||
|
|
- import { createDataSDK, gql, type NodeOfConnection } from "@salesforce/sdk-data";
|
||
|
|
+ import { createDataSDK, gql, type NodeOfConnection, type CacheControl } from "@salesforce/platform-sdk";
|
||
|
|
```
|
||
|
|
|
||
|
|
`createDataSDK`, `gql`, `NodeOfConnection`, and `CacheControl` all export from
|
||
|
|
`@salesforce/platform-sdk`.
|
||
|
|
|
||
|
|
## 2. Query call
|
||
|
|
|
||
|
|
```diff
|
||
|
|
- // OLD — callable, positional args, returns a response object with .data / .errors
|
||
|
|
- const response = await sdk.graphql?.<GetAccountsQuery, GetAccountsQueryVariables>(GET_ACCOUNTS, variables);
|
||
|
|
- const accounts = response?.data?.uiapi?.query?.Account?.edges ?? [];
|
||
|
|
- if (response?.errors?.length) { /* ... */ }
|
||
|
|
|
||
|
|
+ // NEW — namespace method, options bag, returns a reactive QueryResult
|
||
|
|
+ const result = await sdk.graphql!.query<GetAccountsQuery, GetAccountsQueryVariables>({
|
||
|
|
+ query: GET_ACCOUNTS,
|
||
|
|
+ variables,
|
||
|
|
+ });
|
||
|
|
+ const accounts = result.data?.uiapi?.query?.Account?.edges ?? [];
|
||
|
|
+ if (result.errors?.length) { /* ... */ }
|
||
|
|
```
|
||
|
|
|
||
|
|
Passing the generated `<GetAccountsQuery>` type parameter makes `result.data` fully typed — no
|
||
|
|
`as any` cast needed.
|
||
|
|
|
||
|
|
Mapping:
|
||
|
|
|
||
|
|
| Old | New |
|
||
|
|
|-----|-----|
|
||
|
|
| `sdk.graphql?.(QUERY, vars)` | `sdk.graphql!.query({ query: QUERY, variables: vars })` |
|
||
|
|
| positional `<T, V>(query, variables)` | type params on `query<T, V>(options)` |
|
||
|
|
| `response.data` / `response.errors` | `result.data` / `result.errors` (same fields) |
|
||
|
|
| (none) | `result.subscribe(cb)` / `result.refresh()` — new reactive handle |
|
||
|
|
| (none) | `cacheControl` option — new per-call cache policy |
|
||
|
|
|
||
|
|
## 3. Mutation call
|
||
|
|
|
||
|
|
The old callable form was used for mutations too. Mutations now have their own method, and the
|
||
|
|
operation key is **`mutation`**, not `query`:
|
||
|
|
|
||
|
|
```diff
|
||
|
|
- const response = await sdk.graphql?.<CreateAccountMutation>(CREATE_ACCOUNT, { input });
|
||
|
|
+ const { data, errors } = await sdk.graphql!.mutate<CreateAccountMutation, CreateAccountMutationVariables>({
|
||
|
|
+ mutation: CREATE_ACCOUNT, // key is `mutation`, not `query`
|
||
|
|
+ variables: { input },
|
||
|
|
+ });
|
||
|
|
```
|
||
|
|
|
||
|
|
`mutate()` returns `{ data, errors }` only — **no** `subscribe`/`refresh`, and it is **never
|
||
|
|
cached**. To refresh a list after a mutation, hold the query `result` and call
|
||
|
|
`result.refresh()` (see [caching.md](caching.md)).
|
||
|
|
|
||
|
|
## 4. Optional chaining → non-null assertion
|
||
|
|
|
||
|
|
The old guidance was "always use optional chaining" (`sdk.graphql?.()`). Real consumer code now
|
||
|
|
uses the **non-null assertion** after `createDataSDK()`:
|
||
|
|
|
||
|
|
```diff
|
||
|
|
- const response = await sdk.graphql?.(QUERY, vars);
|
||
|
|
+ const result = await sdk.graphql!.query({ query: QUERY, variables: vars });
|
||
|
|
```
|
||
|
|
|
||
|
|
`sdk.graphql` may still be `undefined` on some surfaces. Use `!` when you know the surface
|
||
|
|
supports data ops; use an explicit guard if it might not:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
if (!sdk.graphql) throw new Error("GraphQL not available on this surface");
|
||
|
|
const result = await sdk.graphql.query({ query: QUERY, variables: vars });
|
||
|
|
```
|
||
|
|
|
||
|
|
## 5. Codegen types — unchanged generation, new call placement
|
||
|
|
|
||
|
|
`npm run graphql:codegen` and the generated type names (`<Op>Query` / `<Op>QueryVariables` /
|
||
|
|
`<Op>Mutation` / `<Op>MutationVariables`) are unchanged. Only **where** the type params attach
|
||
|
|
moves — from the callable to the namespace method:
|
||
|
|
|
||
|
|
```diff
|
||
|
|
- await sdk.graphql?.<GetAccountsQuery, GetAccountsQueryVariables>(GET_ACCOUNTS, variables);
|
||
|
|
+ await sdk.graphql!.query<GetAccountsQuery, GetAccountsQueryVariables>({ query: GET_ACCOUNTS, variables });
|
||
|
|
```
|
||
|
|
|
||
|
|
## 6. New capabilities to consider while migrating
|
||
|
|
|
||
|
|
The reshape also unlocked the freshness features (none required to get back to working). The one
|
||
|
|
migration-specific gotcha: **caching is now on by default** (300s, WebApp) — if any code relied
|
||
|
|
on every call hitting the network, add `cacheControl: "no-cache"` to it. The reactive
|
||
|
|
`subscribe`/`refresh` handle and the rest of `cacheControl` are in [caching.md](caching.md).
|
||
|
|
|
||
|
|
## 7. Migration checklist
|
||
|
|
|
||
|
|
- [ ] Replace every `@salesforce/sdk-data` import with `@salesforce/platform-sdk`
|
||
|
|
- [ ] Convert every `sdk.graphql?.(q, v)` query to `sdk.graphql!.query({ query: q, variables: v })`
|
||
|
|
- [ ] Convert every mutation call to `sdk.graphql!.mutate({ mutation: m, variables: v })` (key is `mutation`)
|
||
|
|
- [ ] Move generated type params onto `query<T,V>` / `mutate<T,V>`
|
||
|
|
- [ ] Rename `response` → `result`; `response.data`/`.errors` → `result.data`/`.errors`
|
||
|
|
- [ ] Add a `cacheControl: "no-cache"` to any call that genuinely must always hit the network
|
||
|
|
- [ ] Re-run `npm run graphql:codegen` and `npx eslint <file>`
|