diff --git a/skills/using-webapp-salesforce-data/scripts/graphql-search.sh b/skills/using-webapp-salesforce-data/scripts/graphql-search.sh old mode 100644 new mode 100755 index 28f923c..e11f41e --- a/skills/using-webapp-salesforce-data/scripts/graphql-search.sh +++ b/skills/using-webapp-salesforce-data/scripts/graphql-search.sh @@ -1,20 +1,23 @@ #!/usr/bin/env bash +set -euo pipefail # exit on error (-e), undefined vars (-u), and propagate pipeline failures (-o pipefail) # graphql-search.sh — Look up one or more Salesforce entities in schema.graphql. # # Run from the SFDX project root (where schema.graphql lives): -# bash .a4drules/skills/using-salesforce-data/graphql-search.sh Account -# bash .a4drules/skills/using-salesforce-data/graphql-search.sh Account Contact Opportunity +# bash scripts/graphql-search.sh Account +# bash scripts/graphql-search.sh Account Contact Opportunity # # Pass a custom schema path with -s / --schema: -# bash .a4drules/skills/using-salesforce-data/graphql-search.sh -s /path/to/schema.graphql Account -# bash .a4drules/skills/using-salesforce-data/graphql-search.sh --schema ./other/schema.graphql Account Contact +# bash scripts/graphql-search.sh -s /path/to/schema.graphql Account +# bash scripts/graphql-search.sh --schema ./other/schema.graphql Account Contact # # Output sections per entity: -# 1. Type definition — all fields and relationships -# 2. Filter options — _Filter input (for `where:`) -# 3. Sort options — _OrderBy input (for `orderBy:`) -# 4. Create input — CreateRepresentation (for create mutations) -# 5. Update input — UpdateRepresentation (for update mutations) +# 1. Type definition — all fields and relationships +# 2. Filter options — _Filter input (for `where:`) +# 3. Sort options — _OrderBy input (for `orderBy:`) +# 4. Create mutation wrapper — CreateInput +# 5. Create mutation fields — CreateRepresentation (for create mutations) +# 6. Update mutation wrapper — UpdateInput +# 7. Update mutation fields — UpdateRepresentation (for update mutations) SCHEMA="./schema.graphql" @@ -62,6 +65,19 @@ if [ ! -f "$SCHEMA" ]; then exit 1 fi +if [ ! -r "$SCHEMA" ]; then + echo "ERROR: schema.graphql is not readable at $SCHEMA" + echo " Check file permissions: ls -la $SCHEMA" + exit 1 +fi + +if [ ! -s "$SCHEMA" ]; then + echo "ERROR: schema.graphql is empty at $SCHEMA" + echo " Regenerate it from the webapp dir:" + echo " cd force-app/main/default/webapplications/ && npm run graphql:schema" + exit 1 +fi + # ── Helper: extract lines from a grep match through the closing brace ──────── # Prints up to MAX_LINES lines after (and including) the first match of PATTERN. # Uses a generous line count — blocks are always closed by a "}" line. @@ -72,68 +88,104 @@ extract_block() { local max_lines="$3" local match - match=$(grep -nE "$pattern" "$SCHEMA" | head -1) + local grep_exit=0 + match=$(grep -nE "$pattern" "$SCHEMA" | head -1) || grep_exit=$? + + if [ "$grep_exit" -eq 2 ]; then + echo " ERROR: grep failed on pattern: $pattern" >&2 + return 1 + fi if [ -z "$match" ]; then echo " (not found: $pattern)" - return + return 3 fi echo "### $label" grep -E "$pattern" "$SCHEMA" -A "$max_lines" | \ awk '/^\}$/{print; exit} {print}' | \ - head -n "$max_lines" + head -n "$max_lines" || true echo "" } # ── Main loop ──────────────────────────────────────────────────────────────── for ENTITY in "$@"; do + # Validate entity name: must be a valid PascalCase identifier (letters, digits, underscores) + if [[ ! "$ENTITY" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then + echo "ERROR: Invalid entity name: '$ENTITY'" + echo " Entity names must start with a letter or underscore, followed by letters, digits, or underscores." + echo " Examples: Account, My_Custom_Object__c" + continue + fi + echo "" echo "======================================================================" echo " SCHEMA LOOKUP: $ENTITY" echo "======================================================================" echo "" + found=0 + + # Helper: call extract_block, track matches, surface errors + try_extract() { + local rc=0 + extract_block "$@" || rc=$? + if [ "$rc" -eq 0 ]; then + found=$((found + 1)) + elif [ "$rc" -eq 1 ]; then + echo " Aborting lookup for '$ENTITY' due to grep error" >&2 + fi + # rc=3 is not-found — continue silently (already printed by extract_block) + } + # 1. Type definition — all fields and relationships - extract_block \ + try_extract \ "Type definition — fields and relationships" \ "^type ${ENTITY} implements Record" \ 200 # 2. Filter input — used in `where:` arguments - extract_block \ + try_extract \ "Filter options — use in where: { ... }" \ "^input ${ENTITY}_Filter" \ 100 # 3. OrderBy input — used in `orderBy:` arguments - extract_block \ + try_extract \ "Sort options — use in orderBy: { ... }" \ "^input ${ENTITY}_OrderBy" \ 60 - # 4. Create mutation inputs - extract_block \ + # 4. Create mutation wrapper + try_extract \ "Create mutation wrapper — ${ENTITY}CreateInput" \ "^input ${ENTITY}CreateInput" \ 10 - extract_block \ + # 5. Create mutation fields + try_extract \ "Create mutation fields — ${ENTITY}CreateRepresentation" \ "^input ${ENTITY}CreateRepresentation" \ 100 - # 5. Update mutation inputs - extract_block \ + # 6. Update mutation wrapper + try_extract \ "Update mutation wrapper — ${ENTITY}UpdateInput" \ "^input ${ENTITY}UpdateInput" \ 10 - extract_block \ + # 7. Update mutation fields + try_extract \ "Update mutation fields — ${ENTITY}UpdateRepresentation" \ "^input ${ENTITY}UpdateRepresentation" \ 100 + if [ "$found" -eq 0 ]; then + echo "WARNING: No schema entries found for '$ENTITY'." + echo " - Names are PascalCase (e.g., 'Account' not 'account')" + echo " - Custom objects may need deployment first" + fi + echo "" done