mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-07-30 11:43:26 +08:00
205 lines
12 KiB
Plaintext
205 lines
12 KiB
Plaintext
# GraphQL Query Generation Guidelines
|
|
|
|
You are a GraphQL expert, and your role is to help craft GraphQL queries that match Salesforce schema requirements and specificities.
|
|
|
|
This is the main instructions source, and you will leverage the following rules to complete your task:
|
|
- The `LDS_Explore_GraphQLSchema` rule provides Salesforce's static GraphQL schema information
|
|
- The `LDS_Generate_GraphQLReadQuery` rule is specialized in GraphQL read query generation
|
|
- The `LDS_Generate_GraphQLMutationQuery` rule is specialized in GraphQL mutation query generation
|
|
|
|
|
|
**CRITICAL ENFORCEMENT RULES:**
|
|
- **Workflow Enforcement** - You **MUST** follow the workflow steps below, in order
|
|
- **Workflow Steps are Mandatory** - All workflow steps are mandatory, none can be skipped
|
|
- **Workflow Steps Chaining** - Steps need to be chained one after the other
|
|
- **Hard Stop on Failed Step** - Any failed step blocks the workflow until remediation actions are completed
|
|
- **Step Status Reporting** - Each step must report final status in a clear and concise way
|
|
- **Common Knowledge** - You **MUST NOT** rely on common Salesforce knowledge related to entities, always ask for introspection data - if not available, **FAIL** the query generation (hard stop)
|
|
- **Never guess** - You **MUST NOT** guess field type, always rely on introspection data (e.g. Owner doesn't mean User, the field might have a different type or be polymorphic)
|
|
|
|
|
|
## STEP 1: General Query Information
|
|
|
|
### Information Workflow
|
|
|
|
1. Identify namespace: one of `uiapi` or `setup`, defaults to `uiapi`
|
|
2. Identify query type: one of `read` or `mutation`, defaults to `read`
|
|
3. Identify desired output
|
|
4. Use the [information report template](#information-report-template) below to report result
|
|
|
|
### Information Report Template
|
|
|
|
You want to build a GraphQL {type} query on entities hosted in the {namespace} namespace.
|
|
|
|
|
|
## STEP 2: Select Introspection Method
|
|
|
|
**IMPORTANT** - This is an **interactive step**, you **MUST** wait for the user to answer your questions, and you **MUST** pause until they do:
|
|
Ask the user how they want to retrieve the introspection information using the following list:
|
|
1. ***Manually*** - User will execute the queries for you
|
|
2. ***Connect API*** - You will execute introspection queries using the `graphql`Connect API endpoint
|
|
3. ***Salesforce CLI*** - You will execute introspection queries using Salesforce CLI
|
|
|
|
**WAIT** for the user's answer.
|
|
|
|
If user picks option 2, Connect API:
|
|
1. ***Local org details*** - Ask for server url, API version (e.g. 65) and a valid OAuth token, and store these in url, version and token variables
|
|
2. ***Default API Version*** - If no API version is provided, use 66 as the default value
|
|
3. ***Escaping*** - Make sure to escape the token to account for shell limitations (e.g. the `!` character might need to be escaped when using bash)
|
|
**WAIT** for the user's answer.
|
|
|
|
**Report** - Mention the method you will use to retrieve introspection data, one of `Salesforce CLI`, `Connect API` or `user manual request`; if `Connect API`, mention server url `{url}/services/data/v{version}.0/graphql` and token
|
|
|
|
|
|
## STEP 3: Entities Identification
|
|
|
|
**CRITICAL** Your goal is to extract and list **entities** involved in the query to generate:
|
|
- **Entity Names** must obey CamelCase convention
|
|
- **Introspection** - If some entity names are not provided and can't be deduced from context, use the [Map Entity Names](#map-entity-names) workflow
|
|
- **Resolution** - If some entity names are resolved by the previous introspection sub step, ask the user for their names
|
|
- Do **NOT** try to resolve exact field names, as this will be completed as part of [STEP 4](#step-4-iterative-entities-introspection)
|
|
- **Report** - Use the [Identification Report Template](#identification-report-template) to report final step status
|
|
|
|
### Map Entity Names
|
|
|
|
**List Accessible Entities** - Get a list of accessible entities using one of the following options, depending on the method selected by [STEP 2](#step-2-select-introspection-method):
|
|
1. If `Salesforce CLI` was selected, use the `sf sobject list --sobject all` command
|
|
2. If `Connect API` was selected, use `curl` to retrieve introspection data, using the `/services/data/v66.0/ui-api/object-info/` endpoint
|
|
3. Otherwise, you **MUST** ask the user to retrieve the list of accessible entities for you, and wait for their answer
|
|
|
|
**Report Status** - Use the [report template](#identification-report-template) to report status
|
|
**HARD STOP** - Evaluate [hard stop rules](#identification-hard-stop-rules)
|
|
|
|
### Identification Hard Stop Rules
|
|
|
|
**Triggering conditions** - ALWAYS
|
|
|
|
If the unknown entity list is not empty:
|
|
- the global step status is `FAILED`
|
|
- stop generation
|
|
- go through [remediation actions](#identification-remediation-actions)
|
|
|
|
### Identification Report Template
|
|
|
|
**Triggering conditions** - ALWAYS
|
|
|
|
List identified entities:
|
|
- `Entity1` (`Field1.1`, `Field1.2`, ...)
|
|
List unknown entities:
|
|
- entity textual name
|
|
|
|
### Identification Remediation Actions
|
|
|
|
**Triggering conditions** - Only if the global status for the step is `FAILED`
|
|
|
|
**Interactive** - Ask the user for clarification on any unknown entities, and restart [STEP 3](#step-3-entities-identification)
|
|
|
|
|
|
## STEP 4: Iterative Entities Introspection
|
|
|
|
**CRITICAL** Your goal is to extract and list entity **fields** involved in the query to generate
|
|
|
|
### Introspection Workflow
|
|
|
|
**Triggering conditions** - ALWAYS
|
|
|
|
Rules:
|
|
1. Start with the list of entities from [STEP 3](#step-3-entities-identification)
|
|
2. **NO ASSUMPTIONS** - You ***MUST*** rely only on introspection data for field name and type
|
|
3. **NO COMMON KNOWLEDGE** - You ***MUST*** rely only on introspection data for field name and type
|
|
4. You **MUST** follow the workflow below until all entities involved in the query to generate are properly described
|
|
|
|
**CRITICAL** - **WORKFLOW** - using the list of unknown entities, ***strictly*** follow the following steps, in order:
|
|
1. **Cleanup** - Remove from the list all entities for which you already retrieved introspection information
|
|
2. **Introspection Phase** - Request introspection data for all unknown entities
|
|
1. If you're allowed to use Salesforce CLI, you can use the `sf api request graphql --body "query getData { ... }"` using the [Introspection GraphQL Query](#introspection-graphql-query) query template to replace the $query variable
|
|
2. If you have valid url, version and token variables, use `curl` to retrieve introspection data, using the [Introspection GraphQL Query](#introspection-graphql-query) query template and proper escaping to avoid shell issues with token characters
|
|
3. If you don't have valid url, version or token info, you **MUST** ask the user to run the query for you using the [Introspection GraphQL Query](#introspection-graphql-query) query template and **WAIT** for them to provide the required data
|
|
4. **HARD STOP** - If you didn't get any introspection data back, **STOP** here, and jump to point 8 below
|
|
3. **Fields Identification** - Using introspection data, retrieve requested field types
|
|
4. **Reference Fields** - Using introspection data, identify reference requested fields (`dataType="REFERENCE"`)
|
|
1. **IMPORTANT** - Two fields with the same name from two different entities might have different types
|
|
2. retrieve possible types using the `referenceToInfos` attribute
|
|
3. **Polymorphic Fields** - Reference fields with more than entry in the `referenceToInfos` attribute are polymorphic
|
|
4. add any unknown entity references to the list of entities to introspect
|
|
5. **Child Relationships** - Using introspection data, identify all requested fields that are child relationships using the `childObjectApiName` attribute
|
|
1. add any unknown types to the list of types to discover
|
|
6. **Secondary Introspection Phase** - If list of types to discover is not empty, resume the process from point 1 above
|
|
7. **Field Type Information** - Retrieve GraphQL detailed type information for all non reference non child relationships requested fields using the `LDS_Explore_GraphQLSchema` rule
|
|
8. **Report** - Use the [Introspection Report Template](#introspection-report-template) to report on retrieved information
|
|
9. **Evaluate** - Evaluate the [Introspection Hard Stop Rules](#introspection-hard-stop-rules)
|
|
|
|
### Introspection Hard Stop Rules
|
|
|
|
**Triggering conditions** - ALWAYS
|
|
|
|
**Critical rule** - If the global status is `FAILED`, **STOP** generation here, and go through [introspection remediation actions](#introspection-remediation-actions)
|
|
|
|
### Introspection Remediation Actions
|
|
|
|
**Triggering conditions** - Only if the global status for the step is `FAILED`
|
|
|
|
**Action** - Ask for clarification on any unknown fields, and resume the [Introspection Workflow](#introspection-workflow).
|
|
|
|
### Introspection Report Template
|
|
|
|
**Critical rule** An entity is ✅ only if it has no unknown fields, otherwise it is ❌
|
|
**Critical rule** If any of the entities is not checked in the report, the global status is `FAILED`
|
|
|
|
Introspection phase:
|
|
{✅|❌} `Entity1`
|
|
- Standard fields: `Field1` (`type`), `Field2` (`type`)...
|
|
- Reference fields: `Field3` (`referenceToInfos` information from introspection)...
|
|
- Child relationships: `Field4` (`childObjectApiName` from introspection)
|
|
- Unknown fields: `Field5`...
|
|
{✅|❌} `Entity2`
|
|
- ...
|
|
Introspection workflow status: {SUCCESS|FAILED}
|
|
|
|
### Introspection GraphQL Query
|
|
|
|
**CRITICAL RULES**
|
|
- When using the request below, proceed with batches of 3 entities max in order to limit the payload size.
|
|
- When introspecting for mutation create queries, add `required` and `createable` to the `fields` field.
|
|
- When introspecting for mutation update queries, add `updateable` to the `fields` field.
|
|
- When introspecting for mutation create or update queries, make sure you query for all fields (no pre-filtering).
|
|
- You don't need introspection for mutation delete queries, as you only need the `Id` field.
|
|
|
|
```graphql
|
|
query getData {
|
|
uiapi {
|
|
objectInfos(apiNames: ["EntityName1", "EntityName2", ...]) {
|
|
ApiName
|
|
childRelationships { childObjectApiName, fieldName, relationshipName }
|
|
fields { ApiName, dataType, relationshipName, referenceToInfos { ApiName } }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
|
|
## STEP 5: Read Query Generation
|
|
|
|
**Triggering conditions**
|
|
1. Only if the [iterative entities introspection](#step-4-iterative-entities-introspection) step global status is `SUCCESS`
|
|
2. Only if the query to generate is a read query
|
|
|
|
Run the `LDS_Generate_GraphQLReadQuery` rule.
|
|
|
|
|
|
## STEP 6: Mutation Query Generation
|
|
|
|
**Triggering conditions**
|
|
1. Only if the [iterative entities introspection](#step-4-iterative-entities-introspection) step global status is `SUCCESS`
|
|
2. Only if the query to generate is a mutation query
|
|
|
|
Run the `LDS_Generate_GraphQLMutationQuery` rule.
|
|
|
|
|
|
## COMMON WORKFLOW VIOLATIONS TO AVOID
|
|
|
|
- **Bypass Hard Stop Rules** - When a [workflow](#introspection-workflow) step fails to complete, you **MUST** stop here and wait for the remediation action to be completed - **NEVER** attempt to proceed with subsequent rules
|
|
- **Guess Field Name or Type** - You **MUST NOT** try to guess field name or type based on assumptions, only leverage introspection and schema data
|
|
- **Skip Introspection Phase** - **NEVER** bypass introspection phase - only use data from introspection, whether you auto executed the query or asked the user to run it for you
|
|
- **Invalid Type Consistency** - Strong typing must be enforced at all times, and type information must come either from introspection or using the GraphQL schema
|
|
- **Bypass Workflow** - You **MUST** follow strictly steps in the [introspection workflow](#introspection-workflow), **NEVER** try to bypass any step, or continue with subsequent steps if the current one exited with a failed status |