#!/bin/bash # Data export wrapper for Salesforce CLI # Provides streamlined data export functionality with SOQL query support # Color codes for output formatting readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' readonly YELLOW='\033[0;33m' readonly BLUE='\033[0;34m' readonly CYAN='\033[0;36m' readonly GRAY='\033[0;37m' readonly NC='\033[0m' # No Color # Function to display usage information show_usage() { echo -e "${BLUE}sf-data-export - Data Export Wrapper for Salesforce CLI${NC}" echo "" echo "USAGE:" echo " sf-data-export [OPTIONS]" echo "" echo "OPTIONS:" echo " -qy SOQL query to export data" echo " -fl File containing SOQL query" echo " -so Standard object query (exports all records)" echo " -to Target org username or alias" echo " -ot Output file path (default: export.csv)" echo " -fm Output format: csv, json (default: csv)" echo " -bk Use bulk API for large datasets" echo " -wt Wait time in minutes (default: 10)" echo " -vb Enable verbose output" echo " -hp Show this help message" echo "" echo "EXAMPLES:" echo " sf-data-export -qy \"SELECT Id, Name FROM Account LIMIT 100\"" echo " sf-data-export -so Account -fm json -ot accounts.json" echo " sf-data-export -fl queries/contacts.soql -bk -wt 15" echo " sf-data-export -qy \"SELECT Id FROM User\" -to production" echo "" echo "This script automatically checks for Salesforce CLI installation." } # Function to check if Salesforce CLI is installed check_salesforce_cli() { if ! command -v sf &> /dev/null; then return 1 fi return 0 } # Function to run sf-check diagnostics run_salesforce_check() { if [[ -f "sf-check" ]]; then echo -e "${YELLOW}Running Salesforce CLI diagnostics...${NC}" ./sf-check elif [[ -f "sf-check.sh" ]]; then echo -e "${YELLOW}Running Salesforce CLI diagnostics...${NC}" bash sf-check.sh elif [[ -f "sf-check.ps1" ]]; then echo -e "${YELLOW}Running Salesforce CLI diagnostics...${NC}" pwsh sf-check.ps1 else echo -e "${RED}Salesforce CLI not found and no diagnostic script available.${NC}" echo -e "${RED}Please install the Salesforce CLI: https://developer.salesforce.com/tools/salesforcecli${NC}" fi } # Function to validate SOQL query validate_query() { local query="$1" # Basic validation - check if it starts with SELECT if [[ ! "$query" =~ ^[[:space:]]*[Ss][Ee][Ll][Ee][Cc][Tt] ]]; then echo -e "${RED}Error: Query must start with SELECT${NC}" return 1 fi return 0 } # Function to build standard object query build_sobject_query() { local sobject="$1" # For common objects, use sensible field selections case "$sobject" in "Account") echo "SELECT Id, Name, Type, Industry, Phone, Website, BillingCity, BillingState, BillingCountry FROM Account" ;; "Contact") echo "SELECT Id, FirstName, LastName, Email, Phone, AccountId, Account.Name FROM Contact" ;; "Lead") echo "SELECT Id, FirstName, LastName, Email, Phone, Company, Status, Source FROM Lead" ;; "Opportunity") echo "SELECT Id, Name, AccountId, Account.Name, Amount, CloseDate, StageName, Probability FROM Opportunity" ;; "Case") echo "SELECT Id, CaseNumber, Subject, Status, Priority, Origin, AccountId, Account.Name, ContactId, Contact.Name FROM Case" ;; "User") echo "SELECT Id, Name, Email, Username, Profile.Name, IsActive, LastLoginDate FROM User" ;; *) # Generic query for other objects echo "SELECT Id, Name FROM $sobject" ;; esac } # Initialize variables QUERY="" QUERY_FILE="" SOBJECT="" OUTPUT_FILE="export.csv" TARGET_ORG="" FORMAT="csv" USE_BULK=false WAIT_TIME="10" VERBOSE=false # Parse command line arguments while [[ $# -gt 0 ]]; do case $1 in -qy) QUERY="$2" shift 2 ;; -fl) QUERY_FILE="$2" shift 2 ;; -so) SOBJECT="$2" shift 2 ;; -to) TARGET_ORG="$2" shift 2 ;; -ot) OUTPUT_FILE="$2" shift 2 ;; -fm) FORMAT="$2" shift 2 ;; -bk) USE_BULK=true shift ;; -wt) WAIT_TIME="$2" shift 2 ;; -vb) VERBOSE=true shift ;; -hp) show_usage exit 0 ;; *) echo -e "${RED}Unknown option: $1${NC}" echo "" show_usage exit 1 ;; esac done # Silently check for Salesforce CLI if ! check_salesforce_cli; then run_salesforce_check exit 1 fi # Validate that exactly one query method is specified query_methods=0 [[ -n "$QUERY" ]] && ((query_methods++)) [[ -n "$QUERY_FILE" ]] && ((query_methods++)) [[ -n "$SOBJECT" ]] && ((query_methods++)) if [[ $query_methods -eq 0 ]]; then echo -e "${RED}Error: Must specify one of: --query, --file, or --sobject${NC}" echo "" echo -e "${YELLOW}Usage examples:${NC}" echo -e "${GRAY} sf-data-export -qy \"SELECT Id, Name FROM Account\"${NC}" echo -e "${GRAY} sf-data-export -fl queries/accounts.soql${NC}" echo -e "${GRAY} sf-data-export -so Account${NC}" echo "" echo -e "${YELLOW}Use --help for detailed usage information.${NC}" exit 1 fi if [[ $query_methods -gt 1 ]]; then echo -e "${RED}Error: Can only specify one of: -qy, -fl, or -so${NC}" exit 1 fi # Validate format if [[ "$FORMAT" != "csv" && "$FORMAT" != "json" ]]; then echo -e "${RED}Error: Format must be 'csv' or 'json'${NC}" exit 1 fi # Determine the final query FINAL_QUERY="" if [[ -n "$QUERY" ]]; then FINAL_QUERY="$QUERY" echo -e "${GREEN}Using inline query${NC}" elif [[ -n "$QUERY_FILE" ]]; then if [[ ! -f "$QUERY_FILE" ]]; then echo -e "${RED}Error: Query file not found: $QUERY_FILE${NC}" exit 1 fi FINAL_QUERY=$(cat "$QUERY_FILE") echo -e "${GREEN}Using query from file: $QUERY_FILE${NC}" elif [[ -n "$SOBJECT" ]]; then FINAL_QUERY=$(build_sobject_query "$SOBJECT") echo -e "${GREEN}Using standard query for $SOBJECT${NC}" fi # Validate the query if ! validate_query "$FINAL_QUERY"; then exit 1 fi # Build the sf command based on bulk vs regular query if [[ "$USE_BULK" == true ]]; then # Use Bulk API 2.0 for large datasets SF_ARGS=("data" "export" "bulk") SF_ARGS+=("--query" "$FINAL_QUERY") SF_ARGS+=("--output-file" "$OUTPUT_FILE") SF_ARGS+=("--result-format" "$FORMAT") if [[ "$WAIT_TIME" != "10" ]]; then SF_ARGS+=("--wait" "$WAIT_TIME") fi echo -e "${YELLOW}Using Bulk API 2.0${NC}" else # Use regular data query for smaller datasets SF_ARGS=("data" "query") SF_ARGS+=("--query" "$FINAL_QUERY") SF_ARGS+=("--output-file" "$OUTPUT_FILE") SF_ARGS+=("--result-format" "$FORMAT") fi # Add optional parameters if [[ -n "$TARGET_ORG" ]]; then SF_ARGS+=("--target-org" "$TARGET_ORG") echo -e "${CYAN}Target org: $TARGET_ORG${NC}" fi echo -e "${CYAN}Output format: $FORMAT${NC}" echo -e "${CYAN}Output file: $OUTPUT_FILE${NC}" # Add verbose flag if requested if [[ "$VERBOSE" == true ]]; then SF_ARGS+=("--verbose") fi # Display export information echo "" echo -e "${BLUE}📊 Starting Data Export${NC}" echo -e "${BLUE}=======================${NC}" # Show query preview if verbose if [[ "$VERBOSE" == true ]]; then echo "" echo -e "${YELLOW}📝 SOQL Query:${NC}" echo -e "${GRAY}----------------------------------------${NC}" echo -e "${GRAY}$FINAL_QUERY${NC}" echo -e "${GRAY}----------------------------------------${NC}" fi # Display the command being run echo "" echo -e "${GRAY}Executing: sf ${SF_ARGS[*]}${NC}" echo "" # Execute the command if sf "${SF_ARGS[@]}"; then EXPORT_EXIT_CODE=0 else EXPORT_EXIT_CODE=$? fi echo "" if [[ $EXPORT_EXIT_CODE -eq 0 ]]; then echo -e "${GREEN}✅ Data export completed successfully!${NC}" # Show file information if it exists if [[ -f "$OUTPUT_FILE" ]]; then FILE_SIZE=$(du -h "$OUTPUT_FILE" | cut -f1) if [[ "$FORMAT" == "csv" ]]; then # Count records (excluding header) RECORD_COUNT=$(($(wc -l < "$OUTPUT_FILE") - 1)) echo -e "${CYAN}📁 Exported $RECORD_COUNT records to $OUTPUT_FILE ($FILE_SIZE)${NC}" else echo -e "${CYAN}📁 Data exported to $OUTPUT_FILE ($FILE_SIZE)${NC}" fi fi if [[ "$VERBOSE" == true ]]; then echo -e "${YELLOW}💡 Use a spreadsheet application or text editor to view the exported data${NC}" fi else echo -e "${RED}❌ Data export failed with exit code: $EXPORT_EXIT_CODE${NC}" echo -e "${YELLOW}💡 Check query syntax and permissions${NC}" exit $EXPORT_EXIT_CODE fi