@salesforce/afv-skills 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/activating-datacloud/CREDITS.md +5 -0
- package/skills/activating-datacloud/README.md +39 -0
- package/skills/activating-datacloud/SKILL.md +118 -0
- package/skills/analyzing-omnistudio-dependencies/CREDITS.md +5 -0
- package/skills/analyzing-omnistudio-dependencies/SKILL.md +477 -0
- package/skills/analyzing-omnistudio-dependencies/references/dependency-patterns.md +508 -0
- package/skills/analyzing-omnistudio-dependencies/references/namespace-guide.md +300 -0
- package/skills/building-omnistudio-callable-apex/CREDITS.md +9 -0
- package/skills/building-omnistudio-callable-apex/README.md +80 -0
- package/skills/building-omnistudio-callable-apex/SKILL.md +276 -0
- package/skills/building-omnistudio-callable-apex/assets/pattern_callable_openinterface.cls +40 -0
- package/skills/building-omnistudio-callable-apex/assets/pattern_callable_vanilla.cls +32 -0
- package/skills/building-omnistudio-callable-apex/assets/pattern_migration.cls +54 -0
- package/skills/building-omnistudio-callable-apex/assets/pattern_openinterface.cls +45 -0
- package/skills/building-omnistudio-callable-apex/assets/pattern_test_class.cls +65 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_QuoteByProductCallable/IndustriesCallableException.cls +7 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_QuoteByProductCallable/Industries_QuoteByProductCallable.cls +115 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_QuoteByProductCallable/Industries_QuoteByProductCallableTest.cls +189 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_QuoteByProductCallable/TRANSCRIPT.md +115 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterface2Conversion/IndustriesCallableException.cls +7 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterface2Conversion/MyCustomCallable.cls +74 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterface2Conversion/MyCustomCallableTest.cls +146 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterface2Conversion/MyCustomRemoteClass.cls +16 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterface2Conversion/TRANSCRIPT.md +120 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterfaceConversion/IndustriesCallableException.cls +7 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterfaceConversion/MyCustomCallable.cls +73 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterfaceConversion/MyCustomCallableTest.cls +128 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterfaceConversion/MyCustomVlocityOpenInterface2.cls +23 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterfaceConversion/TRANSCRIPT.md +75 -0
- package/skills/building-omnistudio-datamapper/CREDITS.md +5 -0
- package/skills/building-omnistudio-datamapper/SKILL.md +270 -0
- package/skills/building-omnistudio-datamapper/assets/completion-summary-template.md +28 -0
- package/skills/building-omnistudio-datamapper/assets/omni-data-transform-extract.json +6 -0
- package/skills/building-omnistudio-datamapper/assets/omni-data-transform-item.json +12 -0
- package/skills/building-omnistudio-datamapper/assets/omni-data-transform-load.json +6 -0
- package/skills/building-omnistudio-datamapper/assets/omni-data-transform-transform.json +6 -0
- package/skills/building-omnistudio-datamapper/references/best-practices.md +277 -0
- package/skills/building-omnistudio-datamapper/references/naming-conventions.md +145 -0
- package/skills/building-omnistudio-flexcard/CREDITS.md +5 -0
- package/skills/building-omnistudio-flexcard/SKILL.md +325 -0
- package/skills/building-omnistudio-flexcard/assets/omni-ui-card.json +10 -0
- package/skills/building-omnistudio-flexcard/references/best-practices.md +291 -0
- package/skills/building-omnistudio-flexcard/references/data-binding-guide.md +311 -0
- package/skills/building-omnistudio-flexcard/references/scoring-rubric.md +66 -0
- package/skills/building-omnistudio-flexcard/scripts/flexcard-commands.sh +24 -0
- package/skills/building-omnistudio-integration-procedure/CREDITS.md +5 -0
- package/skills/building-omnistudio-integration-procedure/SKILL.md +275 -0
- package/skills/building-omnistudio-integration-procedure/assets/omni-process-element-dr-extract.json +10 -0
- package/skills/building-omnistudio-integration-procedure/assets/omni-process-element-set-values.json +10 -0
- package/skills/building-omnistudio-integration-procedure/assets/omni-process-ip.json +12 -0
- package/skills/building-omnistudio-integration-procedure/assets/scoring-report-format.txt +14 -0
- package/skills/building-omnistudio-integration-procedure/references/best-practices.md +388 -0
- package/skills/building-omnistudio-integration-procedure/references/element-types.md +588 -0
- package/skills/building-omnistudio-integration-procedure/scripts/cli-commands.sh +18 -0
- package/skills/building-omnistudio-omniscript/CREDITS.md +5 -0
- package/skills/building-omnistudio-omniscript/SKILL.md +367 -0
- package/skills/building-omnistudio-omniscript/assets/omni-process-element-step.json +10 -0
- package/skills/building-omnistudio-omniscript/assets/omni-process-element-text-block.json +11 -0
- package/skills/building-omnistudio-omniscript/assets/omni-process-omniscript.json +12 -0
- package/skills/building-omnistudio-omniscript/references/best-practices.md +480 -0
- package/skills/building-omnistudio-omniscript/references/element-types.md +1172 -0
- package/skills/building-omnistudio-omniscript/scripts/check-duplicate-omniscript.sh +13 -0
- package/skills/building-omnistudio-omniscript/scripts/cli-reference.sh +21 -0
- package/skills/building-omnistudio-omniscript/scripts/deploy-omniscript.sh +29 -0
- package/skills/building-sf-integrations/CREDITS.md +5 -0
- package/skills/building-sf-integrations/README.md +95 -0
- package/skills/building-sf-integrations/SKILL.md +192 -0
- package/skills/building-sf-integrations/assets/callouts/callout-retry-handler.cls +167 -0
- package/skills/building-sf-integrations/assets/callouts/http-response-handler.cls +257 -0
- package/skills/building-sf-integrations/assets/callouts/rest-queueable-callout.cls +262 -0
- package/skills/building-sf-integrations/assets/callouts/rest-sync-callout.cls +211 -0
- package/skills/building-sf-integrations/assets/cdc/cdc-handler.cls +246 -0
- package/skills/building-sf-integrations/assets/cdc/cdc-subscriber-trigger.trigger +139 -0
- package/skills/building-sf-integrations/assets/endpoint-security/example.cspTrustedSite-meta.xml +58 -0
- package/skills/building-sf-integrations/assets/endpoint-security/example.remoteSite-meta.xml +39 -0
- package/skills/building-sf-integrations/assets/external-credentials/jwt-external-credential.externalCredential-meta.xml +90 -0
- package/skills/building-sf-integrations/assets/external-credentials/oauth-external-credential.externalCredential-meta.xml +87 -0
- package/skills/building-sf-integrations/assets/external-services/external-service-operations.md +221 -0
- package/skills/building-sf-integrations/assets/external-services/openapi-registration.externalServiceRegistration-meta.xml +193 -0
- package/skills/building-sf-integrations/assets/named-credentials/certificate-auth.namedCredential-meta.xml +62 -0
- package/skills/building-sf-integrations/assets/named-credentials/custom-auth.namedCredential-meta.xml +71 -0
- package/skills/building-sf-integrations/assets/named-credentials/oauth-client-credentials.namedCredential-meta.xml +51 -0
- package/skills/building-sf-integrations/assets/named-credentials/oauth-jwt-bearer.namedCredential-meta.xml +67 -0
- package/skills/building-sf-integrations/assets/platform-events/event-publisher.cls +191 -0
- package/skills/building-sf-integrations/assets/platform-events/event-subscriber-action.cls +295 -0
- package/skills/building-sf-integrations/assets/platform-events/event-subscriber-trigger.trigger +108 -0
- package/skills/building-sf-integrations/assets/platform-events/platform-event-definition.object-meta.xml +124 -0
- package/skills/building-sf-integrations/assets/soap/soap-callout-service.cls +186 -0
- package/skills/building-sf-integrations/assets/soap/wsdl2apex-guide.md +213 -0
- package/skills/building-sf-integrations/hooks/scripts/suggest_credential_setup.py +271 -0
- package/skills/building-sf-integrations/hooks/scripts/validate_integration.py +363 -0
- package/skills/building-sf-integrations/references/callout-patterns.md +719 -0
- package/skills/building-sf-integrations/references/cdc-guide.md +288 -0
- package/skills/building-sf-integrations/references/cli-reference.md +94 -0
- package/skills/building-sf-integrations/references/event-driven-architecture-guide.md +266 -0
- package/skills/building-sf-integrations/references/event-patterns.md +838 -0
- package/skills/building-sf-integrations/references/external-services-guide.md +303 -0
- package/skills/building-sf-integrations/references/messaging-api-v2.md +609 -0
- package/skills/building-sf-integrations/references/named-credentials-automation.md +201 -0
- package/skills/building-sf-integrations/references/named-credentials-guide.md +173 -0
- package/skills/building-sf-integrations/references/platform-events-guide.md +288 -0
- package/skills/building-sf-integrations/references/rest-callout-patterns.md +288 -0
- package/skills/building-sf-integrations/references/scoring-rubric.md +59 -0
- package/skills/building-sf-integrations/references/security-best-practices.md +248 -0
- package/skills/building-sf-integrations/scripts/README.md +100 -0
- package/skills/building-sf-integrations/scripts/configure-named-credential.sh +236 -0
- package/skills/building-sf-integrations/scripts/set-api-credential.sh +146 -0
- package/skills/building-sf-integrations/scripts/templates/setup-credentials-with-csp.sh +158 -0
- package/skills/configuring-connected-apps/CREDITS.md +3 -0
- package/skills/configuring-connected-apps/README.md +99 -0
- package/skills/configuring-connected-apps/SKILL.md +224 -0
- package/skills/configuring-connected-apps/assets/connected-app-basic.xml +29 -0
- package/skills/configuring-connected-apps/assets/connected-app-canvas.xml +62 -0
- package/skills/configuring-connected-apps/assets/connected-app-jwt.xml +49 -0
- package/skills/configuring-connected-apps/assets/connected-app-oauth.xml +65 -0
- package/skills/configuring-connected-apps/assets/eca-global-oauth.xml +36 -0
- package/skills/configuring-connected-apps/assets/eca-oauth-settings.xml +36 -0
- package/skills/configuring-connected-apps/assets/eca-policies.xml +36 -0
- package/skills/configuring-connected-apps/assets/external-client-app.xml +35 -0
- package/skills/configuring-connected-apps/references/example-usage.md +256 -0
- package/skills/configuring-connected-apps/references/migration-guide.md +328 -0
- package/skills/configuring-connected-apps/references/oauth-flows-reference.md +660 -0
- package/skills/configuring-connected-apps/references/security-checklist.md +209 -0
- package/skills/configuring-connected-apps/references/testing-validation-guide.md +275 -0
- package/skills/connecting-datacloud/CREDITS.md +5 -0
- package/skills/connecting-datacloud/README.md +59 -0
- package/skills/connecting-datacloud/SKILL.md +155 -0
- package/skills/connecting-datacloud/examples/connections/heroku-postgres.json +15 -0
- package/skills/connecting-datacloud/examples/connections/ingest-api-connection.json +5 -0
- package/skills/connecting-datacloud/examples/connections/ingest-api-schema.json +31 -0
- package/skills/connecting-datacloud/examples/connections/redshift.json +16 -0
- package/skills/connecting-datacloud/examples/connections/sharepoint-unstructured.json +20 -0
- package/skills/connecting-datacloud/examples/connections/snowflake-connection.json +42 -0
- package/skills/debugging-apex-logs/CREDITS.md +22 -0
- package/skills/debugging-apex-logs/README.md +74 -0
- package/skills/debugging-apex-logs/SKILL.md +172 -0
- package/skills/debugging-apex-logs/assets/benchmarking-template.cls +327 -0
- package/skills/debugging-apex-logs/assets/cpu-heap-optimization.cls +307 -0
- package/skills/debugging-apex-logs/assets/dml-in-loop-fix.cls +219 -0
- package/skills/debugging-apex-logs/assets/null-pointer-fix.cls +252 -0
- package/skills/debugging-apex-logs/assets/soql-in-loop-fix.cls +157 -0
- package/skills/debugging-apex-logs/references/analysis-playbook.md +53 -0
- package/skills/debugging-apex-logs/references/benchmarking-guide.md +287 -0
- package/skills/debugging-apex-logs/references/cli-commands.md +368 -0
- package/skills/debugging-apex-logs/references/common-issues.md +68 -0
- package/skills/debugging-apex-logs/references/debug-log-reference.md +328 -0
- package/skills/debugging-apex-logs/references/log-analysis-tools.md +248 -0
- package/skills/debugging-apex-logs/references/scoring-rubric.md +21 -0
- package/skills/deploying-metadata/CREDITS.md +25 -0
- package/skills/deploying-metadata/README.md +104 -0
- package/skills/deploying-metadata/SKILL.md +214 -0
- package/skills/deploying-metadata/assets/destructiveChanges.xml +143 -0
- package/skills/deploying-metadata/assets/package.xml +121 -0
- package/skills/deploying-metadata/references/agent-deployment-guide.md +628 -0
- package/skills/deploying-metadata/references/deploy.sh +73 -0
- package/skills/deploying-metadata/references/deployment-report-template.md +89 -0
- package/skills/deploying-metadata/references/deployment-workflows.md +395 -0
- package/skills/deploying-metadata/references/orchestration.md +183 -0
- package/skills/deploying-metadata/references/trigger-deployment-safety.md +376 -0
- package/skills/deploying-omnistudio-datapacks/CREDITS.md +5 -0
- package/skills/deploying-omnistudio-datapacks/README.md +88 -0
- package/skills/deploying-omnistudio-datapacks/SKILL.md +174 -0
- package/skills/deploying-omnistudio-datapacks/examples/business-internet-plus-bundle/TRANSCRIPT.md +124 -0
- package/skills/deploying-omnistudio-datapacks/examples/business-internet-plus-bundle/deploy-business-internet-plus-bundle.yaml +11 -0
- package/skills/deploying-omnistudio-datapacks/examples/business-internet-plus-bundle-deploy/TRANSCRIPT.md +142 -0
- package/skills/deploying-omnistudio-datapacks/examples/business-internet-plus-bundle-deploy/deploy-business-internet-plus-bundle.yaml +10 -0
- package/skills/deploying-omnistudio-datapacks/references/job-file-template.md +42 -0
- package/skills/deploying-omnistudio-datapacks/references/troubleshooting-matrix.md +24 -0
- package/skills/developing-agentforce/assets/metadata/http-callout-flow.flow-meta.xml +1 -1
- package/skills/developing-agentforce/references/actions-reference.md +8 -8
- package/skills/fetching-salesforce-docs/README.md +66 -0
- package/skills/fetching-salesforce-docs/SKILL.md +209 -0
- package/skills/fetching-salesforce-docs/requirements.txt +2 -0
- package/skills/fetching-salesforce-docs/scripts/extract_help_salesforce.py +497 -0
- package/skills/fetching-salesforce-docs/scripts/extract_salesforce_doc.py +357 -0
- package/skills/fetching-salesforce-docs/scripts/runtime_bootstrap.py +58 -0
- package/skills/generating-apex/CREDITS.md +1 -26
- package/skills/generating-apex-test/CREDITS.md +2 -27
- package/skills/generating-lwc-components/CREDITS.md +5 -0
- package/skills/generating-lwc-components/README.md +126 -0
- package/skills/generating-lwc-components/SKILL.md +191 -0
- package/skills/generating-lwc-components/assets/apex-controller/LwcController.cls +327 -0
- package/skills/generating-lwc-components/assets/basic-component/basicComponent.css +72 -0
- package/skills/generating-lwc-components/assets/basic-component/basicComponent.html +111 -0
- package/skills/generating-lwc-components/assets/basic-component/basicComponent.js +163 -0
- package/skills/generating-lwc-components/assets/basic-component/basicComponent.js-meta.xml +137 -0
- package/skills/generating-lwc-components/assets/datatable-component/datatableComponent.html +111 -0
- package/skills/generating-lwc-components/assets/datatable-component/datatableComponent.js +367 -0
- package/skills/generating-lwc-components/assets/flow-screen-component/flowScreenComponent.css +63 -0
- package/skills/generating-lwc-components/assets/flow-screen-component/flowScreenComponent.html +154 -0
- package/skills/generating-lwc-components/assets/flow-screen-component/flowScreenComponent.js +348 -0
- package/skills/generating-lwc-components/assets/flow-screen-component/flowScreenComponent.js-meta.xml +87 -0
- package/skills/generating-lwc-components/assets/form-component/formComponent.html +165 -0
- package/skills/generating-lwc-components/assets/form-component/formComponent.js +275 -0
- package/skills/generating-lwc-components/assets/graphql-component/graphqlComponent.html +100 -0
- package/skills/generating-lwc-components/assets/graphql-component/graphqlComponent.js +336 -0
- package/skills/generating-lwc-components/assets/jest-test/componentName.test.js.example +371 -0
- package/skills/generating-lwc-components/assets/message-channel/RecordSelected.messageChannel-meta.xml +71 -0
- package/skills/generating-lwc-components/assets/message-channel/lmsPublisher.js +103 -0
- package/skills/generating-lwc-components/assets/message-channel/lmsSubscriber.js +181 -0
- package/skills/generating-lwc-components/assets/modal-component/modalComponent.html +85 -0
- package/skills/generating-lwc-components/assets/modal-component/modalComponent.js +199 -0
- package/skills/generating-lwc-components/assets/record-picker/recordPicker.html +55 -0
- package/skills/generating-lwc-components/assets/record-picker/recordPicker.js +199 -0
- package/skills/generating-lwc-components/assets/state-store/store.js +282 -0
- package/skills/generating-lwc-components/assets/typescript-component/typescriptComponent.css +65 -0
- package/skills/generating-lwc-components/assets/typescript-component/typescriptComponent.html +95 -0
- package/skills/generating-lwc-components/assets/typescript-component/typescriptComponent.js-meta.xml +75 -0
- package/skills/generating-lwc-components/assets/typescript-component/typescriptComponent.test.ts.example +301 -0
- package/skills/generating-lwc-components/assets/typescript-component/typescriptComponent.ts +295 -0
- package/skills/generating-lwc-components/assets/workspace-api/workspaceComponent.html +71 -0
- package/skills/generating-lwc-components/assets/workspace-api/workspaceComponent.js +316 -0
- package/skills/generating-lwc-components/hooks/scripts/lwc-lsp-validate.py +295 -0
- package/skills/generating-lwc-components/hooks/scripts/post-tool-validate.py +347 -0
- package/skills/generating-lwc-components/hooks/scripts/slds_data/deprecated_patterns.json +74 -0
- package/skills/generating-lwc-components/hooks/scripts/slds_data/styling_hooks.json +111 -0
- package/skills/generating-lwc-components/hooks/scripts/slds_data/valid_slds_classes.json +127 -0
- package/skills/generating-lwc-components/hooks/scripts/slds_linter_wrapper.py +294 -0
- package/skills/generating-lwc-components/hooks/scripts/slds_rules/__init__.py +22 -0
- package/skills/generating-lwc-components/hooks/scripts/template_validator.py +332 -0
- package/skills/generating-lwc-components/hooks/scripts/validate_slds.py +595 -0
- package/skills/generating-lwc-components/references/accessibility-guide.md +843 -0
- package/skills/generating-lwc-components/references/advanced-features.md +108 -0
- package/skills/generating-lwc-components/references/async-notification-patterns.md +661 -0
- package/skills/generating-lwc-components/references/cli-commands.md +545 -0
- package/skills/generating-lwc-components/references/component-patterns.md +1476 -0
- package/skills/generating-lwc-components/references/flow-integration-guide.md +675 -0
- package/skills/generating-lwc-components/references/jest-testing.md +1011 -0
- package/skills/generating-lwc-components/references/lms-guide.md +860 -0
- package/skills/generating-lwc-components/references/lwc-best-practices.md +1310 -0
- package/skills/generating-lwc-components/references/performance-guide.md +861 -0
- package/skills/generating-lwc-components/references/scoring-and-testing.md +116 -0
- package/skills/generating-lwc-components/references/slds-blueprints.json +14389 -0
- package/skills/generating-lwc-components/references/slds-design-guide.md +166 -0
- package/skills/generating-lwc-components/references/state-management.md +642 -0
- package/skills/generating-lwc-components/references/template-anti-patterns.md +948 -0
- package/skills/generating-lwc-components/references/triangle-pattern.md +365 -0
- package/skills/generating-lwc-components/scripts/local-dev-preview.sh +34 -0
- package/skills/generating-mermaid-diagrams/CREDITS.md +46 -0
- package/skills/generating-mermaid-diagrams/README.md +114 -0
- package/skills/generating-mermaid-diagrams/SKILL.md +218 -0
- package/skills/generating-mermaid-diagrams/assets/agentforce/agent-flow.md +313 -0
- package/skills/generating-mermaid-diagrams/assets/architecture/system-landscape.md +351 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/b2b-commerce-erd.md +317 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/campaigns-erd.md +195 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/consent-erd.md +262 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/files-erd.md +266 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/forecasting-erd.md +261 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/fsl-erd.md +332 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/party-model-erd.md +237 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/quote-order-erd.md +277 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/revenue-cloud-erd.md +343 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/sales-cloud-erd.md +192 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/salesforce-erd.md +209 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/scheduler-erd.md +276 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/service-cloud-erd.md +217 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/territory-management-erd.md +241 -0
- package/skills/generating-mermaid-diagrams/assets/integration/api-sequence.md +387 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/authorization-code-pkce.md +197 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/authorization-code.md +152 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/client-credentials.md +233 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/device-authorization.md +295 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/jwt-bearer.md +256 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/refresh-token.md +281 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/user-agent-social-sign-on.md +281 -0
- package/skills/generating-mermaid-diagrams/assets/role-hierarchy/user-hierarchy.md +322 -0
- package/skills/generating-mermaid-diagrams/references/color-palette.md +464 -0
- package/skills/generating-mermaid-diagrams/references/diagram-conventions.md +313 -0
- package/skills/generating-mermaid-diagrams/references/erd-conventions.md +320 -0
- package/skills/generating-mermaid-diagrams/references/mermaid-reference.md +434 -0
- package/skills/generating-mermaid-diagrams/references/mermaid-styling.md +81 -0
- package/skills/generating-mermaid-diagrams/references/preview-guide.md +49 -0
- package/skills/generating-mermaid-diagrams/references/usage-examples.md +340 -0
- package/skills/generating-mermaid-diagrams/scripts/README.md +160 -0
- package/skills/generating-mermaid-diagrams/scripts/mermaid_preview.py +654 -0
- package/skills/generating-mermaid-diagrams/scripts/query-org-metadata.py +293 -0
- package/skills/generating-visual-diagrams/CREDITS.md +80 -0
- package/skills/generating-visual-diagrams/README.md +83 -0
- package/skills/generating-visual-diagrams/SKILL.md +208 -0
- package/skills/generating-visual-diagrams/assets/architecture/integration-flow.md +55 -0
- package/skills/generating-visual-diagrams/assets/erd/core-objects.md +131 -0
- package/skills/generating-visual-diagrams/assets/erd/custom-objects.md +60 -0
- package/skills/generating-visual-diagrams/assets/lwc/dashboard-card.md +45 -0
- package/skills/generating-visual-diagrams/assets/lwc/data-table.md +57 -0
- package/skills/generating-visual-diagrams/assets/lwc/record-form.md +60 -0
- package/skills/generating-visual-diagrams/assets/review/apex-review.md +57 -0
- package/skills/generating-visual-diagrams/assets/review/lwc-review.md +48 -0
- package/skills/generating-visual-diagrams/references/architect-aesthetic-guide.md +257 -0
- package/skills/generating-visual-diagrams/references/examples-index.md +35 -0
- package/skills/generating-visual-diagrams/references/gemini-cli-setup.md +65 -0
- package/skills/generating-visual-diagrams/references/interview-questions.md +529 -0
- package/skills/generating-visual-diagrams/references/iteration-workflow.md +173 -0
- package/skills/generating-visual-diagrams/scripts/check-prerequisites.sh +101 -0
- package/skills/generating-visual-diagrams/scripts/generate_image.py +243 -0
- package/skills/handling-sf-data/CREDITS.md +5 -0
- package/skills/handling-sf-data/README.md +112 -0
- package/skills/handling-sf-data/SKILL.md +235 -0
- package/skills/handling-sf-data/assets/bulk/bulk-insert-10000.apex +293 -0
- package/skills/handling-sf-data/assets/bulk/bulk-insert-200.apex +208 -0
- package/skills/handling-sf-data/assets/bulk/bulk-insert-500.apex +219 -0
- package/skills/handling-sf-data/assets/bulk/bulk-upsert-external-id.apex +324 -0
- package/skills/handling-sf-data/assets/cleanup/delete-by-created-date.apex +319 -0
- package/skills/handling-sf-data/assets/cleanup/delete-by-name.apex +240 -0
- package/skills/handling-sf-data/assets/cleanup/delete-test-data.apex +311 -0
- package/skills/handling-sf-data/assets/cleanup/rollback-transaction.apex +266 -0
- package/skills/handling-sf-data/assets/csv/account-import.csv +11 -0
- package/skills/handling-sf-data/assets/csv/contact-import.csv +11 -0
- package/skills/handling-sf-data/assets/csv/custom-object-import.csv +11 -0
- package/skills/handling-sf-data/assets/csv/opportunity-import.csv +11 -0
- package/skills/handling-sf-data/assets/factories/account-factory.apex +165 -0
- package/skills/handling-sf-data/assets/factories/case-factory.apex +237 -0
- package/skills/handling-sf-data/assets/factories/contact-factory.apex +168 -0
- package/skills/handling-sf-data/assets/factories/custom-object-factory.apex +260 -0
- package/skills/handling-sf-data/assets/factories/event-factory.apex +275 -0
- package/skills/handling-sf-data/assets/factories/hierarchy-factory.apex +372 -0
- package/skills/handling-sf-data/assets/factories/lead-factory.apex +190 -0
- package/skills/handling-sf-data/assets/factories/opportunity-factory.apex +206 -0
- package/skills/handling-sf-data/assets/factories/task-factory.apex +246 -0
- package/skills/handling-sf-data/assets/factories/user-factory.apex +278 -0
- package/skills/handling-sf-data/assets/json/account-contact-tree.json +130 -0
- package/skills/handling-sf-data/assets/json/account-opportunity-tree.json +110 -0
- package/skills/handling-sf-data/assets/json/full-hierarchy-tree.json +188 -0
- package/skills/handling-sf-data/assets/soql/aggregate.soql +226 -0
- package/skills/handling-sf-data/assets/soql/child-to-parent.soql +162 -0
- package/skills/handling-sf-data/assets/soql/parent-to-child.soql +153 -0
- package/skills/handling-sf-data/assets/soql/polymorphic.soql +198 -0
- package/skills/handling-sf-data/assets/soql/subquery.soql +287 -0
- package/skills/handling-sf-data/references/anonymous-apex-guide.md +98 -0
- package/skills/handling-sf-data/references/bulk-operations-guide.md +94 -0
- package/skills/handling-sf-data/references/bulk-testing-example.md +194 -0
- package/skills/handling-sf-data/references/cleanup-rollback-example.md +322 -0
- package/skills/handling-sf-data/references/cleanup-rollback-guide.md +84 -0
- package/skills/handling-sf-data/references/crud-workflow-example.md +183 -0
- package/skills/handling-sf-data/references/governor-limits-reference.md +74 -0
- package/skills/handling-sf-data/references/orchestration.md +174 -0
- package/skills/handling-sf-data/references/relationship-query-examples.md +249 -0
- package/skills/handling-sf-data/references/sf-cli-data-commands.md +158 -0
- package/skills/handling-sf-data/references/soql-relationship-guide.md +84 -0
- package/skills/handling-sf-data/references/test-data-best-practices.md +104 -0
- package/skills/handling-sf-data/references/test-data-factory-usage.md +290 -0
- package/skills/handling-sf-data/references/test-data-patterns.md +98 -0
- package/skills/handling-sf-data/scripts/soql_validator.py +292 -0
- package/skills/handling-sf-data/scripts/validate_data_operation.py +379 -0
- package/skills/harmonizing-datacloud/CREDITS.md +3 -0
- package/skills/harmonizing-datacloud/README.md +31 -0
- package/skills/harmonizing-datacloud/SKILL.md +117 -0
- package/skills/modeling-omnistudio-epc-catalog/CREDITS.md +14 -0
- package/skills/modeling-omnistudio-epc-catalog/README.md +89 -0
- package/skills/modeling-omnistudio-epc-catalog/SKILL.md +395 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/attribute-assignment-template.json +402 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/compiled-attribute-overrides-template.json +43 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/completion-block-template.txt +8 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/decomposition-relationships-template.json +233 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_AttributeAssignments.json +514 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_CompiledAttributeOverrides.json +21 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_DataPack.json +649 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_DecompositionRelationships.json +200 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_ObjectFieldAttributes.json +138 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_OrchestrationScenarios.json +54 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_OverrideDefinitions.json +266 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_ParentKeys.json +23 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_PriceListEntries.json +54 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_PricebookEntries.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_ProductChildItems.json +34 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_RuleAssignments.json +21 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_AttributeAssignments.json +410 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_DataPack.json +535 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_DecompositionRelationships.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_ObjectFieldAttributes.json +138 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_OrchestrationScenarios.json +28 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_ParentKeys.json +23 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_PriceListEntries.json +220 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_PricebookEntries.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_ProductChildItems.json +414 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_AttributeAssignments.json +382 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_DataPack.json +565 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_DecompositionRelationships.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_ObjectFieldAttributes.json +104 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_OrchestrationScenarios.json +28 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_ParentKeys.json +13 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_PriceListEntries.json +106 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_PricebookEntries.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_ProductChildItems.json +72 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_AttributeAssignments.json +142 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_DataPack.json +377 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_DecompositionRelationships.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_ObjectFieldAttributes.json +36 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_ParentKeys.json +8 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_PriceListEntries.json +54 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_PricebookEntries.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_ProductChildItems.json +34 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/object-field-attributes-template.json +138 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/orchestration-scenarios-template.json +54 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/override-definitions-template.json +134 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/parent-keys-template.json +29 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/price-list-entries-template.json +158 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/pricebook-entries-template.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/product-child-item-template.json +338 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/product2-offer-template.json +527 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/.gitkeep +1 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_AttributeAssignments.json +95 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_CompiledAttributeOverrides.json +1 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_DataPack.json +214 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_DecompositionRelationships.json +28 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_ObjectFieldAttributes.json +98 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_OrchestrationScenarios.json +22 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_OverrideDefinitions.json +1 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_ParentKeys.json +13 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_PriceListEntries.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_PricebookEntries.json +28 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_ProductChildItems.json +110 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/TRANSCRIPT.md +58 -0
- package/skills/modeling-omnistudio-epc-catalog/references/epc-field-guide.md +90 -0
- package/skills/modeling-omnistudio-epc-catalog/references/naming-conventions.md +80 -0
- package/skills/modeling-omnistudio-epc-catalog/references/scoring-model.md +57 -0
- package/skills/modeling-omnistudio-epc-catalog/scripts/cli-validation-commands.sh +19 -0
- package/skills/modeling-omnistudio-epc-catalog/scripts/sample-invocations.sh +18 -0
- package/skills/orchestrating-datacloud/CREDITS.md +15 -0
- package/skills/orchestrating-datacloud/README.md +129 -0
- package/skills/orchestrating-datacloud/SKILL.md +236 -0
- package/skills/orchestrating-datacloud/UPSTREAM.md +45 -0
- package/skills/orchestrating-datacloud/assets/definitions/activation-target.template.json +5 -0
- package/skills/orchestrating-datacloud/assets/definitions/activation.template.json +7 -0
- package/skills/orchestrating-datacloud/assets/definitions/calculated-insight.template.json +7 -0
- package/skills/orchestrating-datacloud/assets/definitions/data-action-target.template.json +5 -0
- package/skills/orchestrating-datacloud/assets/definitions/data-action.template.json +5 -0
- package/skills/orchestrating-datacloud/assets/definitions/data-graph.template.json +21 -0
- package/skills/orchestrating-datacloud/assets/definitions/data-stream.template.json +55 -0
- package/skills/orchestrating-datacloud/assets/definitions/dmo.template.json +17 -0
- package/skills/orchestrating-datacloud/assets/definitions/identity-resolution.template.json +30 -0
- package/skills/orchestrating-datacloud/assets/definitions/mapping.template.json +14 -0
- package/skills/orchestrating-datacloud/assets/definitions/relationship.template.json +12 -0
- package/skills/orchestrating-datacloud/assets/definitions/search-index.template.json +9 -0
- package/skills/orchestrating-datacloud/assets/definitions/segment.template.json +16 -0
- package/skills/orchestrating-datacloud/references/feature-readiness.md +157 -0
- package/skills/orchestrating-datacloud/references/plugin-setup.md +140 -0
- package/skills/orchestrating-datacloud/scripts/bootstrap-plugin.sh +53 -0
- package/skills/orchestrating-datacloud/scripts/diagnose-org.mjs +511 -0
- package/skills/orchestrating-datacloud/scripts/generate-manifest.mjs +68 -0
- package/skills/orchestrating-datacloud/scripts/verify-plugin.sh +58 -0
- package/skills/preparing-datacloud/CREDITS.md +7 -0
- package/skills/preparing-datacloud/README.md +51 -0
- package/skills/preparing-datacloud/SKILL.md +191 -0
- package/skills/preparing-datacloud/examples/ingestion-api/.env.example +8 -0
- package/skills/preparing-datacloud/examples/ingestion-api/README.md +48 -0
- package/skills/preparing-datacloud/examples/ingestion-api/send-data.py +144 -0
- package/skills/querying-soql/CREDITS.md +21 -0
- package/skills/querying-soql/README.md +41 -0
- package/skills/querying-soql/SKILL.md +143 -0
- package/skills/querying-soql/assets/aggregate-queries.soql +242 -0
- package/skills/querying-soql/assets/basic-queries.soql +188 -0
- package/skills/querying-soql/assets/bulkified-query-pattern.cls +280 -0
- package/skills/querying-soql/assets/optimization-patterns.soql +259 -0
- package/skills/querying-soql/assets/relationship-queries.soql +203 -0
- package/skills/querying-soql/assets/selector-class.cls +219 -0
- package/skills/querying-soql/references/anti-patterns.md +348 -0
- package/skills/querying-soql/references/cli-commands.md +358 -0
- package/skills/querying-soql/references/field-coverage-rules.md +514 -0
- package/skills/querying-soql/references/query-optimization.md +142 -0
- package/skills/querying-soql/references/selector-patterns.md +479 -0
- package/skills/querying-soql/references/soql-reference.md +227 -0
- package/skills/querying-soql/references/soql-syntax-reference.md +208 -0
- package/skills/querying-soql/scripts/post-tool-validate.py +322 -0
- package/skills/retrieving-datacloud/CREDITS.md +7 -0
- package/skills/retrieving-datacloud/README.md +44 -0
- package/skills/retrieving-datacloud/SKILL.md +120 -0
- package/skills/retrieving-datacloud/examples/search-indexes/hybrid-structured.json +44 -0
- package/skills/retrieving-datacloud/examples/search-indexes/vector-knowledge.json +43 -0
- package/skills/running-apex-tests/CREDITS.md +22 -0
- package/skills/running-apex-tests/README.md +94 -0
- package/skills/running-apex-tests/SKILL.md +158 -0
- package/skills/running-apex-tests/assets/basic-test.cls +169 -0
- package/skills/running-apex-tests/assets/bulk-test.cls +255 -0
- package/skills/running-apex-tests/assets/dml-mock.cls +339 -0
- package/skills/running-apex-tests/assets/mock-callout-test.cls +353 -0
- package/skills/running-apex-tests/assets/stub-provider-example.cls +364 -0
- package/skills/running-apex-tests/assets/test-data-factory.cls +328 -0
- package/skills/running-apex-tests/hooks/scripts/parse-test-results.py +364 -0
- package/skills/running-apex-tests/references/cli-commands.md +289 -0
- package/skills/running-apex-tests/references/mocking-patterns.md +500 -0
- package/skills/running-apex-tests/references/performance-optimization.md +283 -0
- package/skills/running-apex-tests/references/test-fix-loop.md +49 -0
- package/skills/running-apex-tests/references/test-patterns.md +154 -0
- package/skills/running-apex-tests/references/testing-best-practices.md +509 -0
- package/skills/segmenting-datacloud/CREDITS.md +3 -0
- package/skills/segmenting-datacloud/README.md +36 -0
- package/skills/segmenting-datacloud/SKILL.md +115 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
<!-- Parent: handling-sf-data/SKILL.md -->
|
|
2
|
+
# Test Data Factory Usage
|
|
3
|
+
|
|
4
|
+
How to use and customize the test data factory templates.
|
|
5
|
+
|
|
6
|
+
## Basic Factory Pattern
|
|
7
|
+
|
|
8
|
+
### Account Factory
|
|
9
|
+
```apex
|
|
10
|
+
public class TestDataFactory_Account {
|
|
11
|
+
|
|
12
|
+
// Basic creation - inserted
|
|
13
|
+
public static List<Account> create(Integer count) {
|
|
14
|
+
return create(count, true);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Control insertion
|
|
18
|
+
public static List<Account> create(Integer count, Boolean doInsert) {
|
|
19
|
+
List<Account> records = new List<Account>();
|
|
20
|
+
for (Integer i = 0; i < count; i++) {
|
|
21
|
+
records.add(new Account(
|
|
22
|
+
Name = 'Test Account ' + i,
|
|
23
|
+
Industry = 'Technology'
|
|
24
|
+
));
|
|
25
|
+
}
|
|
26
|
+
if (doInsert) {
|
|
27
|
+
insert records;
|
|
28
|
+
}
|
|
29
|
+
return records;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Usage Examples
|
|
35
|
+
|
|
36
|
+
```apex
|
|
37
|
+
// Create 10 accounts (inserted)
|
|
38
|
+
List<Account> accounts = TestDataFactory_Account.create(10);
|
|
39
|
+
|
|
40
|
+
// Create 10 accounts (not inserted - for customization)
|
|
41
|
+
List<Account> accounts = TestDataFactory_Account.create(10, false);
|
|
42
|
+
accounts[0].AnnualRevenue = 1000000;
|
|
43
|
+
accounts[1].Rating = 'Hot';
|
|
44
|
+
insert accounts;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Factory with Variations
|
|
48
|
+
|
|
49
|
+
### Industry Variations
|
|
50
|
+
```apex
|
|
51
|
+
public static List<Account> createWithVariedIndustries(Integer count) {
|
|
52
|
+
List<Account> records = new List<Account>();
|
|
53
|
+
List<String> industries = new List<String>{
|
|
54
|
+
'Technology', 'Healthcare', 'Finance', 'Manufacturing', 'Retail'
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
for (Integer i = 0; i < count; i++) {
|
|
58
|
+
records.add(new Account(
|
|
59
|
+
Name = 'Test Account ' + i,
|
|
60
|
+
Industry = industries[Math.mod(i, industries.size())]
|
|
61
|
+
));
|
|
62
|
+
}
|
|
63
|
+
insert records;
|
|
64
|
+
return records;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Revenue Tiers
|
|
69
|
+
```apex
|
|
70
|
+
public static List<Account> createWithRevenueTiers(Integer count) {
|
|
71
|
+
List<Account> records = new List<Account>();
|
|
72
|
+
List<Decimal> tiers = new List<Decimal>{
|
|
73
|
+
100000, 500000, 1000000, 5000000, 10000000
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
for (Integer i = 0; i < count; i++) {
|
|
77
|
+
records.add(new Account(
|
|
78
|
+
Name = 'Test Account ' + i,
|
|
79
|
+
AnnualRevenue = tiers[Math.mod(i, tiers.size())]
|
|
80
|
+
));
|
|
81
|
+
}
|
|
82
|
+
insert records;
|
|
83
|
+
return records;
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Factory with Relationships
|
|
88
|
+
|
|
89
|
+
### Contact Factory with Account
|
|
90
|
+
```apex
|
|
91
|
+
public class TestDataFactory_Contact {
|
|
92
|
+
|
|
93
|
+
// Create contacts for existing accounts
|
|
94
|
+
public static List<Contact> createForAccounts(Set<Id> accountIds, Integer perAccount) {
|
|
95
|
+
List<Contact> contacts = new List<Contact>();
|
|
96
|
+
Integer i = 0;
|
|
97
|
+
|
|
98
|
+
for (Id accId : accountIds) {
|
|
99
|
+
for (Integer j = 0; j < perAccount; j++) {
|
|
100
|
+
contacts.add(new Contact(
|
|
101
|
+
FirstName = 'Test',
|
|
102
|
+
LastName = 'Contact ' + i,
|
|
103
|
+
AccountId = accId,
|
|
104
|
+
Email = 'test' + i + '@example.com'
|
|
105
|
+
));
|
|
106
|
+
i++;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
insert contacts;
|
|
110
|
+
return contacts;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Usage
|
|
116
|
+
```apex
|
|
117
|
+
// Create 10 accounts with 3 contacts each
|
|
118
|
+
List<Account> accounts = TestDataFactory_Account.create(10);
|
|
119
|
+
Set<Id> accountIds = new Map<Id, Account>(accounts).keySet();
|
|
120
|
+
List<Contact> contacts = TestDataFactory_Contact.createForAccounts(accountIds, 3);
|
|
121
|
+
// Total: 10 accounts + 30 contacts
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Hierarchy Factory
|
|
125
|
+
|
|
126
|
+
### Complete Hierarchy in One Call
|
|
127
|
+
```apex
|
|
128
|
+
public class TestDataFactory_Hierarchy {
|
|
129
|
+
|
|
130
|
+
public class HierarchyResult {
|
|
131
|
+
public List<Account> accounts;
|
|
132
|
+
public List<Contact> contacts;
|
|
133
|
+
public List<Opportunity> opportunities;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public static HierarchyResult create(
|
|
137
|
+
Integer accountCount,
|
|
138
|
+
Integer contactsPerAccount,
|
|
139
|
+
Integer oppsPerAccount
|
|
140
|
+
) {
|
|
141
|
+
HierarchyResult result = new HierarchyResult();
|
|
142
|
+
|
|
143
|
+
// Create accounts
|
|
144
|
+
result.accounts = TestDataFactory_Account.create(accountCount);
|
|
145
|
+
Set<Id> accountIds = new Map<Id, Account>(result.accounts).keySet();
|
|
146
|
+
|
|
147
|
+
// Create contacts
|
|
148
|
+
result.contacts = TestDataFactory_Contact.createForAccounts(
|
|
149
|
+
accountIds, contactsPerAccount
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Create opportunities
|
|
153
|
+
result.opportunities = TestDataFactory_Opportunity.createForAccounts(
|
|
154
|
+
accountIds, oppsPerAccount
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Usage
|
|
163
|
+
```apex
|
|
164
|
+
// Create complete test hierarchy
|
|
165
|
+
HierarchyResult data = TestDataFactory_Hierarchy.create(
|
|
166
|
+
10, // accounts
|
|
167
|
+
3, // contacts per account
|
|
168
|
+
2 // opportunities per account
|
|
169
|
+
);
|
|
170
|
+
// Total: 10 accounts + 30 contacts + 20 opportunities
|
|
171
|
+
|
|
172
|
+
System.debug('Accounts: ' + data.accounts.size());
|
|
173
|
+
System.debug('Contacts: ' + data.contacts.size());
|
|
174
|
+
System.debug('Opportunities: ' + data.opportunities.size());
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Edge Case Factories
|
|
178
|
+
|
|
179
|
+
### Boundary Values
|
|
180
|
+
```apex
|
|
181
|
+
public static Account createWithMinValues() {
|
|
182
|
+
return new Account(
|
|
183
|
+
Name = 'A' // Minimum name length
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
public static Account createWithMaxValues() {
|
|
188
|
+
return new Account(
|
|
189
|
+
Name = 'X'.repeat(255), // Maximum name length
|
|
190
|
+
Description = 'Y'.repeat(32000) // Maximum description
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Special Characters
|
|
196
|
+
```apex
|
|
197
|
+
public static Account createWithSpecialCharacters() {
|
|
198
|
+
return new Account(
|
|
199
|
+
Name = 'Test & "Special" <Characters> \'Quotes\''
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Null/Empty Values
|
|
205
|
+
```apex
|
|
206
|
+
public static List<Account> createWithNullableFields(Integer count) {
|
|
207
|
+
List<Account> records = new List<Account>();
|
|
208
|
+
for (Integer i = 0; i < count; i++) {
|
|
209
|
+
Account acc = new Account(Name = 'Test ' + i);
|
|
210
|
+
// Leave optional fields null
|
|
211
|
+
// acc.Industry = null;
|
|
212
|
+
// acc.AnnualRevenue = null;
|
|
213
|
+
records.add(acc);
|
|
214
|
+
}
|
|
215
|
+
insert records;
|
|
216
|
+
return records;
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Using Factories for Testing
|
|
221
|
+
|
|
222
|
+
### Trigger Test Example
|
|
223
|
+
```apex
|
|
224
|
+
@isTest
|
|
225
|
+
public class AccountTriggerTest {
|
|
226
|
+
|
|
227
|
+
@isTest
|
|
228
|
+
static void testBulkInsert() {
|
|
229
|
+
// Setup - 201 records to test batch boundaries
|
|
230
|
+
Test.startTest();
|
|
231
|
+
List<Account> accounts = TestDataFactory_Account.create(201);
|
|
232
|
+
Test.stopTest();
|
|
233
|
+
|
|
234
|
+
// Verify trigger logic executed
|
|
235
|
+
List<Account> results = [
|
|
236
|
+
SELECT Id, Custom_Field__c
|
|
237
|
+
FROM Account
|
|
238
|
+
WHERE Id IN :accounts
|
|
239
|
+
];
|
|
240
|
+
|
|
241
|
+
for (Account acc : results) {
|
|
242
|
+
System.assertNotEquals(null, acc.Custom_Field__c,
|
|
243
|
+
'Trigger should have set Custom_Field__c');
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@isTest
|
|
248
|
+
static void testWithRelatedRecords() {
|
|
249
|
+
// Setup hierarchy
|
|
250
|
+
HierarchyResult data = TestDataFactory_Hierarchy.create(5, 2, 1);
|
|
251
|
+
|
|
252
|
+
Test.startTest();
|
|
253
|
+
// Test logic that involves relationships
|
|
254
|
+
MyClass.processAccountsWithContacts(data.accounts);
|
|
255
|
+
Test.stopTest();
|
|
256
|
+
|
|
257
|
+
// Verify results
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Flow Test Example
|
|
263
|
+
```apex
|
|
264
|
+
@isTest
|
|
265
|
+
static void testRecordTriggeredFlow() {
|
|
266
|
+
// Create data that matches flow entry criteria
|
|
267
|
+
List<Account> accounts = TestDataFactory_Account.create(10, false);
|
|
268
|
+
for (Account acc : accounts) {
|
|
269
|
+
acc.Industry = 'Technology'; // Matches flow filter
|
|
270
|
+
acc.AnnualRevenue = 1000000; // Triggers flow action
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
Test.startTest();
|
|
274
|
+
insert accounts; // Flow fires on insert
|
|
275
|
+
Test.stopTest();
|
|
276
|
+
|
|
277
|
+
// Verify flow results
|
|
278
|
+
List<Task> tasks = [SELECT Id FROM Task WHERE WhatId IN :accounts];
|
|
279
|
+
System.assertEquals(10, tasks.size(), 'Flow should create task for each account');
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Best Practices
|
|
284
|
+
|
|
285
|
+
1. **Always return inserted records** - Caller may need IDs
|
|
286
|
+
2. **Provide doInsert parameter** - Allow customization before insert
|
|
287
|
+
3. **Use bulk patterns** - Single DML for multiple records
|
|
288
|
+
4. **Handle required fields** - Prevent validation errors
|
|
289
|
+
5. **Use unique values** - Avoid duplicate rule violations
|
|
290
|
+
6. **Track IDs for cleanup** - Enable proper test isolation
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<!-- Parent: handling-sf-data/SKILL.md -->
|
|
2
|
+
# Test Data Patterns Guide
|
|
3
|
+
|
|
4
|
+
Best practices for creating realistic and effective test data.
|
|
5
|
+
|
|
6
|
+
## Factory Pattern
|
|
7
|
+
|
|
8
|
+
### Standard Implementation
|
|
9
|
+
|
|
10
|
+
```apex
|
|
11
|
+
public class TestDataFactory_Account {
|
|
12
|
+
|
|
13
|
+
public static List<Account> create(Integer count) {
|
|
14
|
+
return create(count, true);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public static List<Account> create(Integer count, Boolean doInsert) {
|
|
18
|
+
List<Account> records = new List<Account>();
|
|
19
|
+
for (Integer i = 0; i < count; i++) {
|
|
20
|
+
records.add(buildRecord(i));
|
|
21
|
+
}
|
|
22
|
+
if (doInsert) {
|
|
23
|
+
insert records;
|
|
24
|
+
}
|
|
25
|
+
return records;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private static Account buildRecord(Integer index) {
|
|
29
|
+
return new Account(
|
|
30
|
+
Name = 'Test Account ' + index,
|
|
31
|
+
Industry = 'Technology'
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Key Principles
|
|
38
|
+
|
|
39
|
+
1. **Always create in lists** - Support bulk operations
|
|
40
|
+
2. **Provide doInsert parameter** - Caller controls insertion
|
|
41
|
+
3. **Track IDs for cleanup** - Return inserted records
|
|
42
|
+
4. **Use realistic data** - Valid picklist values
|
|
43
|
+
|
|
44
|
+
## Record Count Recommendations
|
|
45
|
+
|
|
46
|
+
| Test Scenario | Record Count | Why |
|
|
47
|
+
|---------------|--------------|-----|
|
|
48
|
+
| Basic unit test | 1-10 | Quick validation |
|
|
49
|
+
| Trigger testing | 201 | Batch boundary |
|
|
50
|
+
| Flow testing | 200 | Single transaction |
|
|
51
|
+
| Batch Apex | 500+ | Multiple batches |
|
|
52
|
+
| Performance | 1000+ | Stress testing |
|
|
53
|
+
|
|
54
|
+
## Edge Cases to Test
|
|
55
|
+
|
|
56
|
+
### Null Values
|
|
57
|
+
```apex
|
|
58
|
+
account.Industry = null; // Test null handling
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Boundary Values
|
|
62
|
+
```apex
|
|
63
|
+
account.Name = 'A'; // Min length
|
|
64
|
+
account.Name = String.valueOf('X').repeat(255); // Max length
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Special Characters
|
|
68
|
+
```apex
|
|
69
|
+
account.Name = 'Test & "Special" <Characters>';
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Date Boundaries
|
|
73
|
+
```apex
|
|
74
|
+
opp.CloseDate = Date.today(); // Today
|
|
75
|
+
opp.CloseDate = Date.today().addDays(-1); // Yesterday
|
|
76
|
+
opp.CloseDate = Date.newInstance(2000, 1, 1); // Old date
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Relationship Testing
|
|
80
|
+
|
|
81
|
+
### Create Hierarchy
|
|
82
|
+
```apex
|
|
83
|
+
// Create parent first
|
|
84
|
+
List<Account> accounts = TestDataFactory_Account.create(10);
|
|
85
|
+
|
|
86
|
+
// Create children with parent references
|
|
87
|
+
List<Contact> contacts = TestDataFactory_Contact.createForAccounts(
|
|
88
|
+
new List<Id>(new Map<Id, Account>(accounts).keySet()),
|
|
89
|
+
5 // 5 contacts per account
|
|
90
|
+
);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Best Practices
|
|
94
|
+
|
|
95
|
+
1. **Avoid hardcoded IDs** - Use dynamic references
|
|
96
|
+
2. **Create all required fields** - Prevent validation errors
|
|
97
|
+
3. **Use unique values** - Prevent duplicate errors
|
|
98
|
+
4. **Document patterns** - Explain test scenarios
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
SOQL Validator Module
|
|
4
|
+
=====================
|
|
5
|
+
|
|
6
|
+
Validates SOQL query syntax and patterns.
|
|
7
|
+
Used by the main validation module for query-specific checks.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
from typing import Dict, List, Any, Optional
|
|
12
|
+
|
|
13
|
+
class SOQLValidator:
|
|
14
|
+
"""Validates SOQL queries for best practices."""
|
|
15
|
+
|
|
16
|
+
# Common SOQL keywords
|
|
17
|
+
KEYWORDS = [
|
|
18
|
+
'SELECT', 'FROM', 'WHERE', 'AND', 'OR', 'NOT', 'IN', 'LIKE',
|
|
19
|
+
'ORDER BY', 'GROUP BY', 'HAVING', 'LIMIT', 'OFFSET',
|
|
20
|
+
'ASC', 'DESC', 'NULLS FIRST', 'NULLS LAST',
|
|
21
|
+
'WITH', 'TYPEOF', 'WHEN', 'THEN', 'ELSE', 'END',
|
|
22
|
+
'COUNT', 'SUM', 'AVG', 'MIN', 'MAX', 'COUNT_DISTINCT',
|
|
23
|
+
'CALENDAR_MONTH', 'CALENDAR_YEAR', 'DAY_IN_WEEK', 'WEEK_IN_YEAR',
|
|
24
|
+
'TODAY', 'YESTERDAY', 'TOMORROW', 'THIS_WEEK', 'LAST_WEEK',
|
|
25
|
+
'THIS_MONTH', 'LAST_MONTH', 'THIS_QUARTER', 'LAST_QUARTER',
|
|
26
|
+
'THIS_YEAR', 'LAST_YEAR', 'NEXT_N_DAYS', 'LAST_N_DAYS'
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
# Indexed standard fields for selectivity
|
|
30
|
+
INDEXED_FIELDS = [
|
|
31
|
+
'Id', 'Name', 'OwnerId', 'CreatedDate', 'LastModifiedDate',
|
|
32
|
+
'SystemModstamp', 'RecordTypeId', 'IsDeleted'
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
def __init__(self, content: str):
|
|
36
|
+
self.content = content
|
|
37
|
+
self.issues: List[Dict[str, Any]] = []
|
|
38
|
+
self.recommendations: List[str] = []
|
|
39
|
+
|
|
40
|
+
def validate(self) -> Dict[str, Any]:
|
|
41
|
+
"""Validate the SOQL content and return results."""
|
|
42
|
+
result = {
|
|
43
|
+
'is_valid': True,
|
|
44
|
+
'has_where_clause': False,
|
|
45
|
+
'has_limit': False,
|
|
46
|
+
'has_order_by': False,
|
|
47
|
+
'has_hardcoded_ids': False,
|
|
48
|
+
'uses_indexed_fields': False,
|
|
49
|
+
'has_subquery': False,
|
|
50
|
+
'has_relationship': False,
|
|
51
|
+
'issues': [],
|
|
52
|
+
'recommendations': []
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Clean content (remove comments)
|
|
56
|
+
clean_content = self._remove_comments(self.content)
|
|
57
|
+
|
|
58
|
+
# Check for WHERE clause
|
|
59
|
+
result['has_where_clause'] = self._has_where_clause(clean_content)
|
|
60
|
+
|
|
61
|
+
# Check for LIMIT
|
|
62
|
+
result['has_limit'] = self._has_limit(clean_content)
|
|
63
|
+
|
|
64
|
+
# Check for ORDER BY
|
|
65
|
+
result['has_order_by'] = bool(re.search(r'\bORDER\s+BY\b', clean_content, re.IGNORECASE))
|
|
66
|
+
|
|
67
|
+
# Check for hardcoded IDs
|
|
68
|
+
result['has_hardcoded_ids'] = self._has_hardcoded_ids(clean_content)
|
|
69
|
+
|
|
70
|
+
# Check for indexed fields in WHERE
|
|
71
|
+
result['uses_indexed_fields'] = self._uses_indexed_fields(clean_content)
|
|
72
|
+
|
|
73
|
+
# Check for subqueries
|
|
74
|
+
result['has_subquery'] = self._has_subquery(clean_content)
|
|
75
|
+
|
|
76
|
+
# Check for relationship queries
|
|
77
|
+
result['has_relationship'] = self._has_relationship(clean_content)
|
|
78
|
+
|
|
79
|
+
# Syntax validation
|
|
80
|
+
syntax_issues = self._validate_syntax(clean_content)
|
|
81
|
+
result['issues'].extend(syntax_issues)
|
|
82
|
+
|
|
83
|
+
# Add recommendations
|
|
84
|
+
if not result['has_where_clause']:
|
|
85
|
+
result['recommendations'].append('Add WHERE clause for better query selectivity')
|
|
86
|
+
|
|
87
|
+
if not result['has_limit']:
|
|
88
|
+
result['recommendations'].append('Add LIMIT clause to prevent large result sets')
|
|
89
|
+
|
|
90
|
+
if result['has_hardcoded_ids']:
|
|
91
|
+
result['recommendations'].append('Avoid hardcoded IDs - use bind variables')
|
|
92
|
+
|
|
93
|
+
result['is_valid'] = len([i for i in result['issues'] if i.get('severity') == 'error']) == 0
|
|
94
|
+
|
|
95
|
+
self.issues = result['issues']
|
|
96
|
+
self.recommendations = result['recommendations']
|
|
97
|
+
|
|
98
|
+
return result
|
|
99
|
+
|
|
100
|
+
def _remove_comments(self, content: str) -> str:
|
|
101
|
+
"""Remove SQL comments from content."""
|
|
102
|
+
# Remove single-line comments
|
|
103
|
+
content = re.sub(r'--.*$', '', content, flags=re.MULTILINE)
|
|
104
|
+
# Remove multi-line comments
|
|
105
|
+
content = re.sub(r'/\*[\s\S]*?\*/', '', content)
|
|
106
|
+
return content
|
|
107
|
+
|
|
108
|
+
def _has_where_clause(self, content: str) -> bool:
|
|
109
|
+
"""Check if query has a WHERE clause."""
|
|
110
|
+
return bool(re.search(r'\bWHERE\b', content, re.IGNORECASE))
|
|
111
|
+
|
|
112
|
+
def _has_limit(self, content: str) -> bool:
|
|
113
|
+
"""Check if query has a LIMIT clause."""
|
|
114
|
+
return bool(re.search(r'\bLIMIT\s+\d+', content, re.IGNORECASE))
|
|
115
|
+
|
|
116
|
+
def _has_hardcoded_ids(self, content: str) -> bool:
|
|
117
|
+
"""Check for hardcoded Salesforce IDs."""
|
|
118
|
+
# Salesforce IDs are 15 or 18 character alphanumeric
|
|
119
|
+
# Starting with specific prefixes: 001 (Account), 003 (Contact), etc.
|
|
120
|
+
id_pattern = r"'[a-zA-Z0-9]{15}'" # 15-char ID
|
|
121
|
+
id_pattern_18 = r"'[a-zA-Z0-9]{18}'" # 18-char ID
|
|
122
|
+
|
|
123
|
+
return bool(re.search(id_pattern, content) or re.search(id_pattern_18, content))
|
|
124
|
+
|
|
125
|
+
def _uses_indexed_fields(self, content: str) -> bool:
|
|
126
|
+
"""Check if WHERE clause uses indexed fields."""
|
|
127
|
+
# Extract WHERE clause
|
|
128
|
+
where_match = re.search(r'\bWHERE\b(.*?)(?:\bORDER\b|\bGROUP\b|\bLIMIT\b|$)',
|
|
129
|
+
content, re.IGNORECASE | re.DOTALL)
|
|
130
|
+
if not where_match:
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
where_clause = where_match.group(1)
|
|
134
|
+
|
|
135
|
+
# Check for indexed fields
|
|
136
|
+
for field in self.INDEXED_FIELDS:
|
|
137
|
+
if re.search(rf'\b{field}\b', where_clause, re.IGNORECASE):
|
|
138
|
+
return True
|
|
139
|
+
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
def _has_subquery(self, content: str) -> bool:
|
|
143
|
+
"""Check if query has subqueries."""
|
|
144
|
+
# Look for nested SELECT in parentheses
|
|
145
|
+
return bool(re.search(r'\(\s*SELECT\b', content, re.IGNORECASE))
|
|
146
|
+
|
|
147
|
+
def _has_relationship(self, content: str) -> bool:
|
|
148
|
+
"""Check if query uses relationship queries."""
|
|
149
|
+
# Look for dot notation (child-to-parent) or __r suffix
|
|
150
|
+
return bool(re.search(r'\w+\.\w+|__r\.', content))
|
|
151
|
+
|
|
152
|
+
def _validate_syntax(self, content: str) -> List[Dict[str, Any]]:
|
|
153
|
+
"""Validate SOQL syntax and return issues."""
|
|
154
|
+
issues = []
|
|
155
|
+
|
|
156
|
+
# Check for SELECT without FROM
|
|
157
|
+
if re.search(r'\bSELECT\b', content, re.IGNORECASE):
|
|
158
|
+
if not re.search(r'\bFROM\b', content, re.IGNORECASE):
|
|
159
|
+
issues.append({
|
|
160
|
+
'severity': 'error',
|
|
161
|
+
'message': 'SELECT statement missing FROM clause'
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
# Check for invalid operators
|
|
165
|
+
if re.search(r'==', content):
|
|
166
|
+
issues.append({
|
|
167
|
+
'severity': 'error',
|
|
168
|
+
'message': 'Invalid operator "==" - use "=" in SOQL'
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
if re.search(r'!=\s*null', content, re.IGNORECASE):
|
|
172
|
+
pass # Valid
|
|
173
|
+
elif re.search(r'<>', content):
|
|
174
|
+
issues.append({
|
|
175
|
+
'severity': 'warning',
|
|
176
|
+
'message': 'Consider using "!=" instead of "<>" for consistency'
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
# Check for SELECT *
|
|
180
|
+
if re.search(r'\bSELECT\s+\*', content, re.IGNORECASE):
|
|
181
|
+
issues.append({
|
|
182
|
+
'severity': 'error',
|
|
183
|
+
'message': 'SELECT * is not valid in SOQL - specify field names'
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
# Check for proper string quoting
|
|
187
|
+
if re.search(r"=\s*\"[^\"]*\"", content):
|
|
188
|
+
issues.append({
|
|
189
|
+
'severity': 'warning',
|
|
190
|
+
'message': 'Use single quotes for string literals in SOQL'
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
# Check for unbalanced parentheses
|
|
194
|
+
open_parens = content.count('(')
|
|
195
|
+
close_parens = content.count(')')
|
|
196
|
+
if open_parens != close_parens:
|
|
197
|
+
issues.append({
|
|
198
|
+
'severity': 'error',
|
|
199
|
+
'message': f'Unbalanced parentheses: {open_parens} open, {close_parens} close'
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
# Check for TYPEOF without END
|
|
203
|
+
if re.search(r'\bTYPEOF\b', content, re.IGNORECASE):
|
|
204
|
+
if not re.search(r'\bEND\b', content, re.IGNORECASE):
|
|
205
|
+
issues.append({
|
|
206
|
+
'severity': 'error',
|
|
207
|
+
'message': 'TYPEOF expression missing END keyword'
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
# Check for reserved words as field names (common issues)
|
|
211
|
+
reserved = ['SELECT', 'FROM', 'WHERE', 'ORDER', 'GROUP', 'LIMIT']
|
|
212
|
+
for word in reserved:
|
|
213
|
+
# Look for patterns like "SELECT SELECT" or "field, SELECT"
|
|
214
|
+
if re.search(rf'\b{word}\s*,|\,\s*{word}\b', content, re.IGNORECASE):
|
|
215
|
+
issues.append({
|
|
216
|
+
'severity': 'warning',
|
|
217
|
+
'message': f'Possible misuse of reserved word "{word}"'
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
return issues
|
|
221
|
+
|
|
222
|
+
def get_query_complexity(self, content: str) -> Dict[str, int]:
|
|
223
|
+
"""Analyze query complexity metrics."""
|
|
224
|
+
clean = self._remove_comments(content)
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
'select_fields': len(re.findall(r'\bSELECT\b.*?\bFROM\b', clean, re.IGNORECASE | re.DOTALL)),
|
|
228
|
+
'where_conditions': len(re.findall(r'\b(AND|OR)\b', clean, re.IGNORECASE)) + 1 if self._has_where_clause(clean) else 0,
|
|
229
|
+
'subqueries': len(re.findall(r'\(\s*SELECT\b', clean, re.IGNORECASE)),
|
|
230
|
+
'joins': len(re.findall(r'__r\.|\.Name|\.Id', clean)),
|
|
231
|
+
'aggregates': len(re.findall(r'\b(COUNT|SUM|AVG|MIN|MAX)\s*\(', clean, re.IGNORECASE))
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
def suggest_optimizations(self, content: str) -> List[str]:
|
|
235
|
+
"""Suggest query optimizations."""
|
|
236
|
+
suggestions = []
|
|
237
|
+
clean = self._remove_comments(content)
|
|
238
|
+
|
|
239
|
+
# Check for missing indexed field in WHERE
|
|
240
|
+
if self._has_where_clause(clean) and not self._uses_indexed_fields(clean):
|
|
241
|
+
suggestions.append('Add an indexed field (Id, Name, CreatedDate) to WHERE for better performance')
|
|
242
|
+
|
|
243
|
+
# Check for ORDER BY without LIMIT
|
|
244
|
+
if re.search(r'\bORDER\s+BY\b', clean, re.IGNORECASE):
|
|
245
|
+
if not self._has_limit(clean):
|
|
246
|
+
suggestions.append('Consider adding LIMIT when using ORDER BY')
|
|
247
|
+
|
|
248
|
+
# Check for SELECT with many fields
|
|
249
|
+
select_match = re.search(r'\bSELECT\b(.*?)\bFROM\b', clean, re.IGNORECASE | re.DOTALL)
|
|
250
|
+
if select_match:
|
|
251
|
+
fields = select_match.group(1)
|
|
252
|
+
field_count = len([f.strip() for f in fields.split(',') if f.strip()])
|
|
253
|
+
if field_count > 20:
|
|
254
|
+
suggestions.append(f'Query selects {field_count} fields - consider selecting only needed fields')
|
|
255
|
+
|
|
256
|
+
# Check for deeply nested subqueries
|
|
257
|
+
subquery_depth = len(re.findall(r'\(\s*SELECT\b', clean, re.IGNORECASE))
|
|
258
|
+
if subquery_depth > 2:
|
|
259
|
+
suggestions.append('Consider simplifying query - deeply nested subqueries may impact performance')
|
|
260
|
+
|
|
261
|
+
return suggestions
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
# Standalone execution for testing
|
|
265
|
+
if __name__ == '__main__':
|
|
266
|
+
import sys
|
|
267
|
+
|
|
268
|
+
if len(sys.argv) < 2:
|
|
269
|
+
print('Usage: python soql_validator.py <soql_file>')
|
|
270
|
+
sys.exit(1)
|
|
271
|
+
|
|
272
|
+
with open(sys.argv[1], 'r') as f:
|
|
273
|
+
content = f.read()
|
|
274
|
+
|
|
275
|
+
validator = SOQLValidator(content)
|
|
276
|
+
result = validator.validate()
|
|
277
|
+
|
|
278
|
+
print('SOQL Validation Results:')
|
|
279
|
+
print('=' * 40)
|
|
280
|
+
for key, value in result.items():
|
|
281
|
+
if key not in ['issues', 'recommendations']:
|
|
282
|
+
print(f'{key}: {value}')
|
|
283
|
+
|
|
284
|
+
if result['issues']:
|
|
285
|
+
print('\nIssues:')
|
|
286
|
+
for issue in result['issues']:
|
|
287
|
+
print(f" [{issue['severity']}] {issue['message']}")
|
|
288
|
+
|
|
289
|
+
if result['recommendations']:
|
|
290
|
+
print('\nRecommendations:')
|
|
291
|
+
for rec in result['recommendations']:
|
|
292
|
+
print(f' - {rec}')
|