@devo-bmad-custom/agent-orchestration 1.0.1 → 1.0.3
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/lib/installer.js +44 -11
- package/package.json +1 -1
- package/src/.agents/skills/audit-website/README.md +20 -20
- package/src/.agents/skills/audit-website/SKILL.md +470 -470
- package/src/.agents/skills/audit-website/agents/openai.yaml +6 -6
- package/src/.agents/skills/audit-website/assets/icon-small.svg +41 -41
- package/src/.agents/skills/audit-website/references/OUTPUT-FORMAT.md +250 -250
- package/src/.agents/skills/clean-code-standards/SKILL.md +104 -104
- package/src/.agents/skills/excalidraw-dark-standard/SKILL.md +281 -281
- package/src/.agents/skills/frontend-responsive-design-standards/SKILL.md +434 -434
- package/src/.agents/skills/java-fundamentals/SKILL.md +116 -116
- package/src/.agents/skills/java-performance/SKILL.md +119 -119
- package/src/.agents/skills/next-best-practices/SKILL.md +153 -153
- package/src/.agents/skills/next-best-practices/async-patterns.md +87 -87
- package/src/.agents/skills/next-best-practices/bundling.md +180 -180
- package/src/.agents/skills/next-best-practices/data-patterns.md +297 -297
- package/src/.agents/skills/next-best-practices/debug-tricks.md +105 -105
- package/src/.agents/skills/next-best-practices/directives.md +73 -73
- package/src/.agents/skills/next-best-practices/error-handling.md +227 -227
- package/src/.agents/skills/next-best-practices/file-conventions.md +140 -140
- package/src/.agents/skills/next-best-practices/font.md +245 -245
- package/src/.agents/skills/next-best-practices/functions.md +108 -108
- package/src/.agents/skills/next-best-practices/hydration-error.md +91 -91
- package/src/.agents/skills/next-best-practices/image.md +173 -173
- package/src/.agents/skills/next-best-practices/metadata.md +301 -301
- package/src/.agents/skills/next-best-practices/parallel-routes.md +287 -287
- package/src/.agents/skills/next-best-practices/route-handlers.md +146 -146
- package/src/.agents/skills/next-best-practices/rsc-boundaries.md +159 -159
- package/src/.agents/skills/next-best-practices/runtime-selection.md +39 -39
- package/src/.agents/skills/next-best-practices/scripts.md +141 -141
- package/src/.agents/skills/next-best-practices/self-hosting.md +371 -371
- package/src/.agents/skills/next-best-practices/suspense-boundaries.md +67 -67
- package/src/.agents/skills/nextjs-app-router-patterns/SKILL.md +537 -537
- package/src/.agents/skills/postgresql-optimization/SKILL.md +404 -404
- package/src/.agents/skills/python-backend/SKILL.md +153 -153
- package/src/.agents/skills/python-fundamentals/SKILL.md +234 -234
- package/src/.agents/skills/python-performance/SKILL.md +404 -404
- package/src/.agents/skills/react-expert/SKILL.md +335 -335
- package/src/.agents/skills/redis-best-practices/SKILL.md +438 -438
- package/src/.agents/skills/security-best-practices/SKILL.md +288 -288
- package/src/.agents/skills/security-review/LICENSE +22 -22
- package/src/.agents/skills/security-review/SKILL.md +312 -312
- package/src/.agents/skills/security-review/infrastructure/docker.md +432 -432
- package/src/.agents/skills/security-review/languages/javascript.md +388 -388
- package/src/.agents/skills/security-review/languages/python.md +363 -363
- package/src/.agents/skills/security-review/references/api-security.md +519 -519
- package/src/.agents/skills/security-review/references/authentication.md +353 -353
- package/src/.agents/skills/security-review/references/authorization.md +372 -372
- package/src/.agents/skills/security-review/references/business-logic.md +443 -443
- package/src/.agents/skills/security-review/references/cryptography.md +329 -329
- package/src/.agents/skills/security-review/references/csrf.md +398 -398
- package/src/.agents/skills/security-review/references/data-protection.md +378 -378
- package/src/.agents/skills/security-review/references/deserialization.md +410 -410
- package/src/.agents/skills/security-review/references/error-handling.md +436 -436
- package/src/.agents/skills/security-review/references/file-security.md +457 -457
- package/src/.agents/skills/security-review/references/injection.md +259 -259
- package/src/.agents/skills/security-review/references/logging.md +433 -433
- package/src/.agents/skills/security-review/references/misconfiguration.md +435 -435
- package/src/.agents/skills/security-review/references/modern-threats.md +475 -475
- package/src/.agents/skills/security-review/references/ssrf.md +415 -415
- package/src/.agents/skills/security-review/references/supply-chain.md +405 -405
- package/src/.agents/skills/security-review/references/xss.md +336 -336
- package/src/.agents/skills/subagent-driven-development/SKILL.md +275 -275
- package/src/.agents/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -26
- package/src/.agents/skills/subagent-driven-development/implementer-prompt.md +113 -113
- package/src/.agents/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -61
- package/src/.agents/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/src/.agents/skills/systematic-debugging/SKILL.md +296 -296
- package/src/.agents/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/src/.agents/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/src/.agents/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/src/.agents/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/src/.agents/skills/systematic-debugging/test-academic.md +14 -14
- package/src/.agents/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/src/.agents/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/src/.agents/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/src/.agents/skills/typescript-best-practices/SKILL.md +373 -373
- package/src/.agents/skills/ui-ux-pro-custom/SKILL.md +348 -348
- package/src/.agents/skills/ui-ux-pro-custom/data/charts.csv +26 -26
- package/src/.agents/skills/ui-ux-pro-custom/data/colors.csv +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/icons.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/SKILL.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/accessibility.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/animation.md +466 -466
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/composition-locals.md +231 -231
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/deprecated-patterns.md +323 -323
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/lists-scrolling.md +400 -400
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/modifiers.md +331 -331
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/navigation.md +416 -416
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/performance.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/side-effects.md +516 -516
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/foundation-source.md +13327 -13327
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/material3-source.md +19097 -19097
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/navigation-source.md +2947 -2947
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/runtime-source.md +11316 -11316
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/ui-source.md +7896 -7896
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/state-management.md +377 -377
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/styles-experimental.md +470 -470
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/theming-material3.md +349 -349
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/view-composition.md +595 -595
- package/src/.agents/skills/ui-ux-pro-custom/data/landing.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/data/mobile-ui-layout.md +654 -654
- package/src/.agents/skills/ui-ux-pro-custom/data/products.csv +96 -96
- package/src/.agents/skills/ui-ux-pro-custom/data/react-performance.csv +45 -45
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/astro.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/flutter.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/html-tailwind.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/jetpack-compose.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nextjs.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxt-ui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxtjs.csv +59 -59
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react-native.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/shadcn.csv +61 -61
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/svelte.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/swiftui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/vue.csv +50 -50
- package/src/.agents/skills/ui-ux-pro-custom/data/styles.csv +68 -68
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/SKILL.md +438 -438
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/references/alarmkit-patterns.md +584 -584
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-clips/SKILL.md +436 -436
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/SKILL.md +489 -489
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/references/appintents-advanced.md +1076 -1076
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/SKILL.md +340 -340
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/privacy-manifest.md +90 -90
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/review-checklists.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-conversion.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-optimization.md +344 -344
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/foundation-models.md +508 -508
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/mlx-swift.md +285 -285
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/references/keychain-biometric.md +211 -211
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/SKILL.md +499 -499
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/references/background-task-patterns.md +390 -390
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/SKILL.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/references/callkit-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/SKILL.md +492 -492
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/references/cloudkit-patterns.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/codable-patterns/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/SKILL.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/references/contacts-patterns.md +409 -409
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/references/ble-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/SKILL.md +388 -388
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/references/motion-patterns.md +405 -405
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/SKILL.md +495 -495
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/references/nfc-patterns.md +420 -420
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/SKILL.md +459 -459
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/references/coreml-swift-integration.md +765 -765
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/SKILL.md +422 -422
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/instruments-guide.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/lldb-patterns.md +298 -298
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/device-integrity/SKILL.md +477 -477
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/SKILL.md +460 -460
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/references/energykit-patterns.md +541 -541
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/references/eventkit-patterns.md +326 -326
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/references/healthkit-patterns.md +602 -602
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/references/matter-commissioning.md +455 -455
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/SKILL.md +301 -301
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/references/a11y-patterns.md +140 -140
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/SKILL.md +418 -418
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/formatstyle-locale.md +627 -627
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/string-catalogs.md +462 -462
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/SKILL.md +441 -441
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/background-websocket.md +862 -862
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/lightweight-clients.md +93 -93
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/network-framework.md +563 -563
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/urlsession-patterns.md +1116 -1116
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/app-review-guidelines.md +174 -174
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/cryptokit-advanced.md +296 -296
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/file-storage-patterns.md +354 -354
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/privacy-manifest.md +117 -117
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/references/live-activity-patterns.md +868 -868
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/corelocation-patterns.md +730 -730
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/mapkit-patterns.md +748 -748
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/metrickit-diagnostics/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/SKILL.md +395 -395
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/references/musickit-patterns.md +363 -363
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/SKILL.md +412 -412
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/references/translation-patterns.md +311 -311
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/SKILL.md +398 -398
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/references/wallet-passes.md +254 -254
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/SKILL.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/paperkit-integration.md +376 -376
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/pencilkit-patterns.md +302 -302
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/SKILL.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/references/permissionkit-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/av-playback.md +701 -701
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/camera-capture.md +774 -774
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/image-loading-caching.md +869 -869
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/photospicker-patterns.md +597 -597
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/notification-patterns.md +677 -677
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/rich-notifications.md +745 -745
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/references/realitykit-patterns.md +480 -480
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/references/shareplay-patterns.md +544 -544
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/speech-recognition/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/SKILL.md +478 -478
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/app-review-guidelines.md +58 -58
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/storekit-advanced.md +755 -755
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/SKILL.md +487 -487
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/references/charts-patterns.md +895 -895
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/SKILL.md +408 -408
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/approachable-concurrency.md +80 -80
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swift-6-2-concurrency.md +233 -233
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swiftui-concurrency.md +187 -187
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/synchronization-primitives.md +341 -341
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/references/swift-patterns-extended.md +505 -505
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/references/testing-patterns.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/SKILL.md +334 -334
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/core-data-coexistence.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-advanced.md +975 -975
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-queries.md +675 -675
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/SKILL.md +481 -481
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/animation-advanced.md +804 -804
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/core-animation-bridge.md +553 -553
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/SKILL.md +450 -450
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/references/gesture-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/SKILL.md +336 -336
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/form.md +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/grids.md +69 -69
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/list.md +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/scrollview.md +147 -147
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/SKILL.md +325 -325
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/references/liquid-glass.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/SKILL.md +262 -262
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/deeplinks.md +207 -207
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/navigationstack.md +177 -177
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/sheets.md +169 -169
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/tabview.md +178 -178
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/SKILL.md +381 -381
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/architecture-patterns.md +486 -486
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/deprecated-migration.md +1097 -1097
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/design-polish.md +780 -780
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/platform-and-sharing.md +696 -696
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +46 -46
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +29 -29
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-hangs-in-your-app.md +33 -33
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-improving-swiftui-performance.md +52 -52
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/SKILL.md +428 -428
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/hosting-migration.md +534 -534
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/representable-recipes.md +1133 -1133
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/SKILL.md +494 -494
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/references/tipkit-patterns.md +782 -782
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/SKILL.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/vision-requests.md +736 -736
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/visionkit-scanner.md +738 -738
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/SKILL.md +410 -410
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/references/weatherkit-patterns.md +567 -567
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/SKILL.md +497 -497
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/references/widgetkit-advanced.md +871 -871
- package/src/.agents/skills/ui-ux-pro-custom/data/typography.csv +57 -57
- package/src/.agents/skills/ui-ux-pro-custom/data/ui-reasoning.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/ux-guidelines.csv +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/web-interface.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/scripts/core.py +253 -253
- package/src/.agents/skills/ui-ux-pro-custom/scripts/design_system.py +1067 -1067
- package/src/.agents/skills/ui-ux-pro-custom/scripts/search.py +114 -114
- package/src/.agents/skills/ux-audit/SKILL.md +150 -150
- package/src/.agents/skills/websocket-engineer/SKILL.md +168 -168
- package/src/.agents/skills/websocket-engineer/references/alternatives.md +391 -391
- package/src/.agents/skills/websocket-engineer/references/patterns.md +400 -400
- package/src/.agents/skills/websocket-engineer/references/protocol.md +195 -195
- package/src/.agents/skills/websocket-engineer/references/scaling.md +333 -333
- package/src/.agents/skills/websocket-engineer/references/security.md +474 -474
- package/src/.agents/skills/writing-skills/SKILL.md +655 -655
- package/src/.agents/skills/writing-skills/anthropic-best-practices.md +1150 -1150
- package/src/.agents/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
- package/src/.agents/skills/writing-skills/graphviz-conventions.dot +171 -171
- package/src/.agents/skills/writing-skills/persuasion-principles.md +187 -187
- package/src/.agents/skills/writing-skills/render-graphs.js +168 -168
- package/src/.agents/skills/writing-skills/testing-skills-with-subagents.md +384 -384
- package/src/.claude/commands/bmad-track-compact.md +1 -1
- package/src/.claude/commands/bmad-track-extended.md +1 -1
- package/src/.claude/commands/bmad-track-large.md +1 -1
- package/src/.claude/commands/bmad-track-medium.md +1 -1
- package/src/.claude/commands/bmad-track-nano.md +1 -1
- package/src/.claude/commands/bmad-track-rv.md +1 -1
- package/src/.claude/commands/bmad-track-small.md +1 -1
- package/src/.claude/commands/master-orchestrator.md +15 -0
- package/src/_memory/config.yaml +11 -11
- package/src/_memory/master-orchestrator-sidecar/instructions.md +85 -32
- package/src/_memory/skills/nimbalyst-tracking/SKILL.md +103 -103
- package/src/_memory/skills/writing-skills/SKILL.md +655 -655
- package/src/bmb/agents/agent-builder.md +59 -59
- package/src/bmb/agents/module-builder.md +60 -60
- package/src/bmb/agents/workflow-builder.md +61 -61
- package/src/bmb/config.yaml +12 -12
- package/src/bmb/module-help.csv +13 -13
- package/src/bmb/workflows/agent/data/agent-architecture.md +258 -258
- package/src/bmb/workflows/agent/data/agent-compilation.md +185 -185
- package/src/bmb/workflows/agent/data/agent-menu-patterns.md +189 -189
- package/src/bmb/workflows/agent/data/agent-metadata.md +133 -133
- package/src/bmb/workflows/agent/data/agent-validation.md +111 -111
- package/src/bmb/workflows/agent/data/brainstorm-context.md +96 -96
- package/src/bmb/workflows/agent/data/communication-presets.csv +61 -61
- package/src/bmb/workflows/agent/data/critical-actions.md +75 -75
- package/src/bmb/workflows/agent/data/persona-properties.md +252 -252
- package/src/bmb/workflows/agent/data/principles-crafting.md +142 -142
- package/src/bmb/workflows/agent/data/reference/module-examples/architect.md +68 -68
- package/src/bmb/workflows/agent/data/reference/with-sidecar/journal-keeper/journal-keeper-sidecar/entries/yy-mm-dd-entry-template.md +16 -16
- package/src/bmb/workflows/agent/data/understanding-agent-types.md +126 -126
- package/src/bmb/workflows/agent/steps-c/step-01-brainstorm.md +129 -129
- package/src/bmb/workflows/agent/steps-c/step-02-discovery.md +170 -170
- package/src/bmb/workflows/agent/steps-c/step-03-sidecar-metadata.md +309 -309
- package/src/bmb/workflows/agent/steps-c/step-04-persona.md +213 -213
- package/src/bmb/workflows/agent/steps-c/step-05-commands-menu.md +179 -179
- package/src/bmb/workflows/agent/steps-c/step-06-activation.md +278 -278
- package/src/bmb/workflows/agent/steps-c/step-07-build-agent.md +316 -316
- package/src/bmb/workflows/agent/steps-c/step-08-celebrate.md +247 -247
- package/src/bmb/workflows/agent/steps-e/e-01-load-existing.md +221 -221
- package/src/bmb/workflows/agent/steps-e/e-02-discover-edits.md +195 -195
- package/src/bmb/workflows/agent/steps-e/e-04-sidecar-metadata.md +126 -126
- package/src/bmb/workflows/agent/steps-e/e-05-persona.md +135 -135
- package/src/bmb/workflows/agent/steps-e/e-06-commands-menu.md +123 -123
- package/src/bmb/workflows/agent/steps-e/e-07-activation.md +124 -124
- package/src/bmb/workflows/agent/steps-e/e-08-edit-agent.md +197 -197
- package/src/bmb/workflows/agent/steps-e/e-09-celebrate.md +155 -155
- package/src/bmb/workflows/agent/steps-v/v-01-load-review.md +137 -137
- package/src/bmb/workflows/agent/steps-v/v-02a-validate-metadata.md +116 -116
- package/src/bmb/workflows/agent/steps-v/v-02b-validate-persona.md +124 -124
- package/src/bmb/workflows/agent/steps-v/v-02c-validate-menu.md +127 -127
- package/src/bmb/workflows/agent/steps-v/v-02d-validate-structure.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-02e-validate-sidecar.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-03-summary.md +104 -104
- package/src/bmb/workflows/agent/templates/agent-plan.template.md +5 -5
- package/src/bmb/workflows/agent/templates/agent-template.md +89 -89
- package/src/bmb/workflows/agent/workflow-create-agent.md +72 -72
- package/src/bmb/workflows/agent/workflow-edit-agent.md +75 -75
- package/src/bmb/workflows/agent/workflow-validate-agent.md +73 -73
- package/src/bmb/workflows/module/data/agent-architecture.md +179 -179
- package/src/bmb/workflows/module/data/agent-spec-template.md +79 -79
- package/src/bmb/workflows/module/data/module-standards.md +263 -263
- package/src/bmb/workflows/module/data/module-yaml-conventions.md +392 -392
- package/src/bmb/workflows/module/module-help-generate.md +254 -254
- package/src/bmb/workflows/module/steps-b/step-01-welcome.md +148 -148
- package/src/bmb/workflows/module/steps-b/step-02-spark.md +141 -141
- package/src/bmb/workflows/module/steps-b/step-03-module-type.md +149 -149
- package/src/bmb/workflows/module/steps-b/step-04-vision.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-05-identity.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-06-users.md +86 -86
- package/src/bmb/workflows/module/steps-b/step-07-value.md +76 -76
- package/src/bmb/workflows/module/steps-b/step-08-agents.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-09-workflows.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-10-tools.md +91 -91
- package/src/bmb/workflows/module/steps-b/step-11-scenarios.md +84 -84
- package/src/bmb/workflows/module/steps-b/step-12-creative.md +95 -95
- package/src/bmb/workflows/module/steps-b/step-13-review.md +105 -105
- package/src/bmb/workflows/module/steps-b/step-14-finalize.md +117 -117
- package/src/bmb/workflows/module/steps-c/step-01-load-brief.md +179 -179
- package/src/bmb/workflows/module/steps-c/step-01b-continue.md +82 -82
- package/src/bmb/workflows/module/steps-c/step-02-structure.md +105 -105
- package/src/bmb/workflows/module/steps-c/step-03-config.md +119 -119
- package/src/bmb/workflows/module/steps-c/step-04-agents.md +168 -168
- package/src/bmb/workflows/module/steps-c/step-05-workflows.md +184 -184
- package/src/bmb/workflows/module/steps-c/step-06-docs.md +401 -401
- package/src/bmb/workflows/module/steps-c/step-07-complete.md +152 -152
- package/src/bmb/workflows/module/steps-e/step-01-load-target.md +81 -81
- package/src/bmb/workflows/module/steps-e/step-02-select-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-03-apply-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-04-review.md +80 -80
- package/src/bmb/workflows/module/steps-e/step-05-confirm.md +75 -75
- package/src/bmb/workflows/module/steps-v/step-01-load-target.md +96 -96
- package/src/bmb/workflows/module/steps-v/step-02-file-structure.md +93 -93
- package/src/bmb/workflows/module/steps-v/step-03-module-yaml.md +99 -99
- package/src/bmb/workflows/module/steps-v/step-04-agent-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-05-workflow-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-06-documentation.md +143 -143
- package/src/bmb/workflows/module/steps-v/step-07-installation.md +102 -102
- package/src/bmb/workflows/module/steps-v/step-08-report.md +197 -197
- package/src/bmb/workflows/module/templates/brief-template.md +154 -154
- package/src/bmb/workflows/module/templates/workflow-spec-template.md +96 -96
- package/src/bmb/workflows/module/workflow-create-module-brief.md +71 -71
- package/src/bmb/workflows/module/workflow-create-module.md +86 -86
- package/src/bmb/workflows/module/workflow-edit-module.md +66 -66
- package/src/bmb/workflows/module/workflow-validate-module.md +66 -66
- package/src/bmb/workflows/workflow/data/architecture.md +150 -150
- package/src/bmb/workflows/workflow/data/common-workflow-tools.csv +19 -19
- package/src/bmb/workflows/workflow/data/csv-data-file-standards.md +53 -53
- package/src/bmb/workflows/workflow/data/frontmatter-standards.md +184 -184
- package/src/bmb/workflows/workflow/data/input-discovery-standards.md +191 -191
- package/src/bmb/workflows/workflow/data/intent-vs-prescriptive-spectrum.md +44 -44
- package/src/bmb/workflows/workflow/data/menu-handling-standards.md +133 -133
- package/src/bmb/workflows/workflow/data/output-format-standards.md +135 -135
- package/src/bmb/workflows/workflow/data/step-file-rules.md +235 -235
- package/src/bmb/workflows/workflow/data/step-type-patterns.md +257 -257
- package/src/bmb/workflows/workflow/data/subprocess-optimization-patterns.md +188 -188
- package/src/bmb/workflows/workflow/data/trimodal-workflow-structure.md +164 -164
- package/src/bmb/workflows/workflow/data/workflow-chaining-standards.md +222 -222
- package/src/bmb/workflows/workflow/data/workflow-examples.md +232 -232
- package/src/bmb/workflows/workflow/data/workflow-type-criteria.md +134 -134
- package/src/bmb/workflows/workflow/steps-c/step-00-conversion.md +263 -263
- package/src/bmb/workflows/workflow/steps-c/step-01-discovery.md +194 -194
- package/src/bmb/workflows/workflow/steps-c/step-01b-continuation.md +3 -3
- package/src/bmb/workflows/workflow/steps-c/step-02-classification.md +270 -270
- package/src/bmb/workflows/workflow/steps-c/step-03-requirements.md +283 -283
- package/src/bmb/workflows/workflow/steps-c/step-04-tools.md +282 -282
- package/src/bmb/workflows/workflow/steps-c/step-05-plan-review.md +243 -243
- package/src/bmb/workflows/workflow/steps-c/step-06-design.md +330 -330
- package/src/bmb/workflows/workflow/steps-c/step-07-foundation.md +239 -239
- package/src/bmb/workflows/workflow/steps-c/step-08-build-step-01.md +379 -379
- package/src/bmb/workflows/workflow/steps-c/step-09-build-next-step.md +350 -350
- package/src/bmb/workflows/workflow/steps-c/step-10-confirmation.md +322 -322
- package/src/bmb/workflows/workflow/steps-c/step-11-completion.md +191 -191
- package/src/bmb/workflows/workflow/steps-e/step-e-01-assess-workflow.md +237 -237
- package/src/bmb/workflows/workflow/steps-e/step-e-02-discover-edits.md +251 -251
- package/src/bmb/workflows/workflow/steps-e/step-e-03-fix-validation.md +254 -254
- package/src/bmb/workflows/workflow/steps-e/step-e-04-direct-edit.md +277 -277
- package/src/bmb/workflows/workflow/steps-e/step-e-05-apply-edit.md +154 -154
- package/src/bmb/workflows/workflow/steps-e/step-e-06-validate-after.md +190 -190
- package/src/bmb/workflows/workflow/steps-e/step-e-07-complete.md +206 -206
- package/src/bmb/workflows/workflow/steps-v/step-01-validate-max-mode.md +109 -109
- package/src/bmb/workflows/workflow/steps-v/step-01-validate.md +221 -221
- package/src/bmb/workflows/workflow/steps-v/step-01b-structure.md +152 -152
- package/src/bmb/workflows/workflow/steps-v/step-02-frontmatter-validation.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-02b-path-violations.md +265 -265
- package/src/bmb/workflows/workflow/steps-v/step-03-menu-validation.md +164 -164
- package/src/bmb/workflows/workflow/steps-v/step-04-step-type-validation.md +211 -211
- package/src/bmb/workflows/workflow/steps-v/step-05-output-format-validation.md +200 -200
- package/src/bmb/workflows/workflow/steps-v/step-06-validation-design-check.md +195 -195
- package/src/bmb/workflows/workflow/steps-v/step-07-instruction-style-check.md +209 -209
- package/src/bmb/workflows/workflow/steps-v/step-08-collaborative-experience-check.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-08b-subprocess-optimization.md +179 -179
- package/src/bmb/workflows/workflow/steps-v/step-09-cohesive-review.md +186 -186
- package/src/bmb/workflows/workflow/steps-v/step-10-report-complete.md +154 -154
- package/src/bmb/workflows/workflow/steps-v/step-11-plan-validation.md +237 -237
- package/src/bmb/workflows/workflow/templates/minimal-output-template.md +11 -11
- package/src/bmb/workflows/workflow/templates/step-01-init-continuable-template.md +241 -241
- package/src/bmb/workflows/workflow/templates/step-1b-template.md +224 -224
- package/src/bmb/workflows/workflow/templates/step-template.md +294 -294
- package/src/bmb/workflows/workflow/templates/workflow-template.md +102 -102
- package/src/bmb/workflows/workflow/workflow-create-workflow.md +79 -79
- package/src/bmb/workflows/workflow/workflow-edit-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-rework-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-validate-max-parallel-workflow.md +66 -66
- package/src/bmb/workflows/workflow/workflow-validate-workflow.md +65 -65
- package/src/bmm/agents/analyst.md +104 -104
- package/src/bmm/agents/dev.md +100 -100
- package/src/bmm/agents/qa.md +100 -90
- package/src/bmm/agents/review-agent.md +1 -1
- package/src/bmm/agents/tech-writer/tech-writer.md +94 -94
- package/src/bmm/module-help.csv +31 -31
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +115 -115
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +107 -107
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +141 -141
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +144 -144
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +147 -147
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +161 -161
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +99 -99
- package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +57 -57
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +156 -156
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +165 -165
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +140 -140
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +152 -152
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +345 -345
- package/src/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +92 -92
- package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +164 -164
- package/src/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +174 -174
- package/src/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +184 -184
- package/src/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +105 -105
- package/src/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +360 -360
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +165 -165
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +174 -174
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +141 -141
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +159 -159
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +387 -387
- package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +54 -54
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +100 -100
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +160 -160
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +88 -88
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +99 -99
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +169 -169
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +156 -156
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +176 -176
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +184 -184
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +174 -174
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +175 -175
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +189 -189
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +162 -162
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +79 -79
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +183 -183
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +149 -149
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +187 -187
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-04-complete.md +108 -108
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +166 -166
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +131 -131
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +150 -150
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +155 -155
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +170 -170
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +158 -158
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +147 -147
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +182 -182
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +202 -202
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +148 -148
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +201 -201
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +179 -179
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +164 -164
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +106 -106
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +111 -111
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +115 -115
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +127 -127
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +167 -167
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +143 -143
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +154 -154
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +165 -165
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +135 -135
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +101 -101
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +45 -45
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +185 -185
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +130 -130
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +93 -93
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +196 -196
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +54 -54
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +82 -82
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +106 -106
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +138 -138
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +129 -129
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +166 -166
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +186 -186
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +163 -163
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +38 -38
- package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +49 -49
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +124 -124
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +122 -122
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +84 -84
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +58 -58
- package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +43 -43
- package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +53 -53
- package/src/bmm/workflows/4-implementation/create-story/checklist.md +159 -159
- package/src/bmm/workflows/4-implementation/create-story/template.md +79 -79
- package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +20 -20
- package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +25 -25
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +158 -158
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +122 -122
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +87 -87
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +146 -146
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -50
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +152 -152
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +123 -123
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +201 -201
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -79
- package/src/bmm/workflows/document-project/workflow.yaml +22 -22
- package/src/bmm/workflows/generate-project-context/steps/step-01-discover.md +184 -184
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +322 -322
- package/src/bmm/workflows/generate-project-context/steps/step-03-complete.md +235 -235
- package/src/bmm/workflows/generate-project-context/workflow.md +49 -49
- package/src/bmm/workflows/qa/automate/workflow.yaml +233 -233
- package/src/bmm/workflows/qa-generate-e2e-tests/workflow.yaml +42 -42
- package/src/core/agents/master-orchestrator.md +3 -3
- package/src/core/config.yaml +9 -9
- package/src/core/module-help.csv +10 -10
- package/src/core/scripts/generate-loop-report.py +72 -72
- package/src/core/tasks/editorial-review-prose.xml +101 -101
- package/src/core/tasks/editorial-review-structure.xml +207 -207
- package/src/core/tasks/help.md +86 -86
- package/src/core/tasks/index-docs.xml +64 -64
- package/src/core/tasks/review-adversarial-general.xml +66 -66
- package/src/core/tasks/review-adversarial-loop.xml +46 -46
- package/src/core/tasks/review-edge-case-hunter.xml +63 -63
- package/src/core/tasks/review-party-loop.xml +46 -46
- package/src/core/tasks/shard-doc.xml +107 -107
- package/src/core/tasks/workflow.xml +235 -235
- package/src/core/templates/review-loop-report.html +88 -88
- package/src/core/templates/review-loop-report.md +5 -5
- package/src/core/workflows/advanced-elicitation/workflow.xml +117 -117
- package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +212 -212
- package/src/core/workflows/brainstorming/steps/step-01b-continue.md +122 -122
- package/src/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -225
- package/src/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -237
- package/src/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -209
- package/src/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -264
- package/src/core/workflows/brainstorming/steps/step-02e-deep-dive.md +68 -68
- package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +403 -403
- package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -303
- package/src/core/workflows/brainstorming/workflow.md +60 -60
- package/src/core/workflows/extract-trackers/workflow.md +45 -45
- package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +142 -142
- package/src/core/workflows/party-mode/workflow.md +194 -194
- package/src/docs/dev/tmux/actions_popup.py +291 -291
- package/src/docs/dev/tmux/tmux-setup.md +62 -1
|
@@ -1,675 +1,675 @@
|
|
|
1
|
-
# SwiftData Queries Reference
|
|
2
|
-
|
|
3
|
-
Deep reference for all @Query initializer variants, FetchDescriptor options,
|
|
4
|
-
sort descriptors, sectioned queries, dynamic query switching, background fetch
|
|
5
|
-
patterns, and aggregate queries.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Contents
|
|
10
|
-
|
|
11
|
-
- [@Query Initializer Variants](#query-initializer-variants)
|
|
12
|
-
- [FetchDescriptor Deep Dive](#fetchdescriptor-deep-dive)
|
|
13
|
-
- [Complex Sort Descriptors](#complex-sort-descriptors)
|
|
14
|
-
- [Sectioned Queries Pattern](#sectioned-queries-pattern)
|
|
15
|
-
- [Dynamic Query Switching](#dynamic-query-switching)
|
|
16
|
-
- [Background Fetch Patterns with @ModelActor](#background-fetch-patterns-with-modelactor)
|
|
17
|
-
- [Aggregate Queries](#aggregate-queries)
|
|
18
|
-
- [Enumerate for Large Datasets](#enumerate-for-large-datasets)
|
|
19
|
-
|
|
20
|
-
## @Query Initializer Variants
|
|
21
|
-
|
|
22
|
-
`@Query` is a SwiftUI property wrapper (`DynamicProperty`) that automatically
|
|
23
|
-
fetches and observes persistent model data. All variants are `@MainActor`.
|
|
24
|
-
|
|
25
|
-
### Basic (No Filter, No Sort)
|
|
26
|
-
|
|
27
|
-
```swift
|
|
28
|
-
// Fetch all, default order
|
|
29
|
-
@Query private var trips: [Trip]
|
|
30
|
-
|
|
31
|
-
// With animation
|
|
32
|
-
@Query(animation: .default) private var trips: [Trip]
|
|
33
|
-
|
|
34
|
-
// With transaction
|
|
35
|
-
@Query(transaction: Transaction(animation: .spring)) private var trips: [Trip]
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### Filter + SortDescriptor Array
|
|
39
|
-
|
|
40
|
-
```swift
|
|
41
|
-
@Query(
|
|
42
|
-
filter: #Predicate<Trip> { $0.isFavorite == true },
|
|
43
|
-
sort: [SortDescriptor(\.startDate, order: .reverse)]
|
|
44
|
-
)
|
|
45
|
-
private var favoriteTrips: [Trip]
|
|
46
|
-
|
|
47
|
-
// With animation
|
|
48
|
-
@Query(
|
|
49
|
-
filter: #Predicate<Trip> { $0.isFavorite == true },
|
|
50
|
-
sort: [SortDescriptor(\.startDate, order: .reverse)],
|
|
51
|
-
animation: .default
|
|
52
|
-
)
|
|
53
|
-
private var favoriteTrips: [Trip]
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Filter + KeyPath Sort
|
|
57
|
-
|
|
58
|
-
```swift
|
|
59
|
-
@Query(
|
|
60
|
-
filter: #Predicate<Trip> { $0.destination != "" },
|
|
61
|
-
sort: \.startDate,
|
|
62
|
-
order: .forward
|
|
63
|
-
)
|
|
64
|
-
private var upcomingTrips: [Trip]
|
|
65
|
-
|
|
66
|
-
// With optional key path sort
|
|
67
|
-
@Query(
|
|
68
|
-
sort: \.endDate, // KeyPath<Trip, Date?> -- optional sort key
|
|
69
|
-
order: .reverse
|
|
70
|
-
)
|
|
71
|
-
private var tripsByEndDate: [Trip]
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### FetchDescriptor
|
|
75
|
-
|
|
76
|
-
```swift
|
|
77
|
-
static var recentDescriptor: FetchDescriptor<Trip> {
|
|
78
|
-
var d = FetchDescriptor<Trip>(
|
|
79
|
-
predicate: #Predicate { $0.startDate > Date.now },
|
|
80
|
-
sortBy: [SortDescriptor(\.startDate)]
|
|
81
|
-
)
|
|
82
|
-
d.fetchLimit = 10
|
|
83
|
-
return d
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
@Query(RecentTripsView.recentDescriptor) private var recentTrips: [Trip]
|
|
87
|
-
|
|
88
|
-
// With animation
|
|
89
|
-
@Query(RecentTripsView.recentDescriptor, animation: .default)
|
|
90
|
-
private var recentTrips: [Trip]
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Query Properties
|
|
94
|
-
|
|
95
|
-
| Property | Type | Description |
|
|
96
|
-
|----------|------|-------------|
|
|
97
|
-
| `wrappedValue` | `Result` (typically `[Element]`) | Most recent fetched results |
|
|
98
|
-
| `modelContext` | `ModelContext` | The context used for fetching |
|
|
99
|
-
| `fetchError` | `(any Error)?` | Error from most recent fetch, if any |
|
|
100
|
-
|
|
101
|
-
Access `fetchError` to detect query failures:
|
|
102
|
-
|
|
103
|
-
```swift
|
|
104
|
-
struct TripListView: View {
|
|
105
|
-
@Query private var trips: [Trip]
|
|
106
|
-
|
|
107
|
-
var body: some View {
|
|
108
|
-
Group {
|
|
109
|
-
if let error = $trips.fetchError {
|
|
110
|
-
ContentUnavailableView("Fetch Error",
|
|
111
|
-
systemImage: "exclamationmark.triangle",
|
|
112
|
-
description: Text(error.localizedDescription))
|
|
113
|
-
} else {
|
|
114
|
-
List(trips) { trip in
|
|
115
|
-
Text(trip.name)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## FetchDescriptor Deep Dive
|
|
126
|
-
|
|
127
|
-
### Full Property Reference
|
|
128
|
-
|
|
129
|
-
```swift
|
|
130
|
-
var descriptor = FetchDescriptor<Trip>()
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
| Property | Type | Default | Description |
|
|
134
|
-
|----------|------|---------|-------------|
|
|
135
|
-
| `predicate` | `Predicate<T>?` | `nil` | Filter condition |
|
|
136
|
-
| `sortBy` | `[SortDescriptor<T>]` | `[]` | Sort order |
|
|
137
|
-
| `fetchLimit` | `Int?` | `nil` | Maximum results |
|
|
138
|
-
| `fetchOffset` | `Int?` | `nil` | Skip first N results |
|
|
139
|
-
| `includePendingChanges` | `Bool` | `true` | Include unsaved in-memory changes |
|
|
140
|
-
| `propertiesToFetch` | `[PartialKeyPath<T>]` | all | Specific properties to load |
|
|
141
|
-
| `relationshipKeyPathsForPrefetching` | `[PartialKeyPath<T>]` | `[]` | Related models to eagerly load |
|
|
142
|
-
|
|
143
|
-
### fetchLimit and fetchOffset (Pagination)
|
|
144
|
-
|
|
145
|
-
```swift
|
|
146
|
-
func fetchPage(page: Int, pageSize: Int) throws -> [Trip] {
|
|
147
|
-
var descriptor = FetchDescriptor<Trip>(
|
|
148
|
-
sortBy: [SortDescriptor(\.startDate)]
|
|
149
|
-
)
|
|
150
|
-
descriptor.fetchLimit = pageSize
|
|
151
|
-
descriptor.fetchOffset = page * pageSize
|
|
152
|
-
return try modelContext.fetch(descriptor)
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### includePendingChanges
|
|
157
|
-
|
|
158
|
-
When `true` (default), the fetch includes objects inserted or modified in the
|
|
159
|
-
current context but not yet saved. Set to `false` for read-only queries against
|
|
160
|
-
the persisted store only.
|
|
161
|
-
|
|
162
|
-
```swift
|
|
163
|
-
var descriptor = FetchDescriptor<Trip>()
|
|
164
|
-
descriptor.includePendingChanges = false // Only persisted data
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
Note: `includePendingChanges: true` cannot be used with batched fetches
|
|
168
|
-
(`fetch(_:batchSize:)`). This will throw
|
|
169
|
-
`SwiftDataError.includePendingChangesWithBatchSize`.
|
|
170
|
-
|
|
171
|
-
### propertiesToFetch (Partial Loading)
|
|
172
|
-
|
|
173
|
-
Load only specific attributes to reduce memory footprint:
|
|
174
|
-
|
|
175
|
-
```swift
|
|
176
|
-
var descriptor = FetchDescriptor<Trip>()
|
|
177
|
-
descriptor.propertiesToFetch = [\.name, \.destination, \.startDate]
|
|
178
|
-
let trips = try modelContext.fetch(descriptor)
|
|
179
|
-
// Only name, destination, startDate are loaded; other properties fault on access
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### relationshipKeyPathsForPrefetching
|
|
183
|
-
|
|
184
|
-
Eagerly load related objects to avoid N+1 query patterns:
|
|
185
|
-
|
|
186
|
-
```swift
|
|
187
|
-
var descriptor = FetchDescriptor<Trip>()
|
|
188
|
-
descriptor.relationshipKeyPathsForPrefetching = [
|
|
189
|
-
\.accommodation,
|
|
190
|
-
\.tags
|
|
191
|
-
]
|
|
192
|
-
let trips = try modelContext.fetch(descriptor)
|
|
193
|
-
// Accessing trip.accommodation does not trigger a separate fetch
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Fetch Variants on ModelContext
|
|
197
|
-
|
|
198
|
-
| Method | Returns | Use Case |
|
|
199
|
-
|--------|---------|----------|
|
|
200
|
-
| `fetch(_:)` | `[T]` | Standard fetch, all results in memory |
|
|
201
|
-
| `fetch(_:batchSize:)` | `FetchResultsCollection<T>` | Lazy batched loading |
|
|
202
|
-
| `fetchCount(_:)` | `Int` | Count only, no objects loaded |
|
|
203
|
-
| `fetchIdentifiers(_:)` | `[PersistentIdentifier]` | IDs only, lightweight |
|
|
204
|
-
| `fetchIdentifiers(_:batchSize:)` | `FetchResultsCollection<PersistentIdentifier>` | Batched ID loading |
|
|
205
|
-
| `enumerate(_:batchSize:...)` | `Void` | Process large sets in batches |
|
|
206
|
-
|
|
207
|
-
### FetchResultsCollection (Batched Fetch)
|
|
208
|
-
|
|
209
|
-
```swift
|
|
210
|
-
let results: FetchResultsCollection<Trip> = try modelContext.fetch(
|
|
211
|
-
FetchDescriptor<Trip>(sortBy: [SortDescriptor(\.name)]),
|
|
212
|
-
batchSize: 100
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
// Iterate lazily -- only 100 objects in memory at a time
|
|
216
|
-
for trip in results {
|
|
217
|
-
print(trip.name)
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
Requirements for batched fetch:
|
|
222
|
-
- `includePendingChanges` must be `false` (or will throw).
|
|
223
|
-
- Results are read-only snapshots.
|
|
224
|
-
|
|
225
|
-
---
|
|
226
|
-
|
|
227
|
-
## Complex Sort Descriptors
|
|
228
|
-
|
|
229
|
-
### Single Sort
|
|
230
|
-
|
|
231
|
-
```swift
|
|
232
|
-
SortDescriptor(\.name, order: .forward) // A-Z
|
|
233
|
-
SortDescriptor(\.name, order: .reverse) // Z-A
|
|
234
|
-
SortDescriptor(\.startDate) // Ascending (default)
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
### Multi-Level Sort
|
|
238
|
-
|
|
239
|
-
```swift
|
|
240
|
-
let descriptor = FetchDescriptor<Trip>(
|
|
241
|
-
sortBy: [
|
|
242
|
-
SortDescriptor(\.isFavorite, order: .reverse), // Favorites first
|
|
243
|
-
SortDescriptor(\.startDate, order: .forward), // Then by date
|
|
244
|
-
SortDescriptor(\.name, order: .forward) // Then alphabetical
|
|
245
|
-
]
|
|
246
|
-
)
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### Optional Key Path Sort
|
|
250
|
-
|
|
251
|
-
Sort on optional properties -- nil values sort to the end:
|
|
252
|
-
|
|
253
|
-
```swift
|
|
254
|
-
@Query(sort: \.endDate, order: .reverse) private var trips: [Trip]
|
|
255
|
-
// endDate is Date? -- trips without endDate appear last
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### Dynamic Sort Switching
|
|
259
|
-
|
|
260
|
-
```swift
|
|
261
|
-
struct TripListView: View {
|
|
262
|
-
@State private var sortOrder: SortOrder = .forward
|
|
263
|
-
@State private var sortKey: TripSortKey = .name
|
|
264
|
-
|
|
265
|
-
var body: some View {
|
|
266
|
-
SortedTripList(sortKey: sortKey, sortOrder: sortOrder)
|
|
267
|
-
.toolbar {
|
|
268
|
-
Picker("Sort", selection: $sortKey) {
|
|
269
|
-
Text("Name").tag(TripSortKey.name)
|
|
270
|
-
Text("Date").tag(TripSortKey.date)
|
|
271
|
-
Text("Destination").tag(TripSortKey.destination)
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
enum TripSortKey: String, CaseIterable {
|
|
278
|
-
case name, date, destination
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
struct SortedTripList: View {
|
|
282
|
-
@Query private var trips: [Trip]
|
|
283
|
-
|
|
284
|
-
init(sortKey: TripSortKey, sortOrder: SortOrder) {
|
|
285
|
-
let sortDescriptor: SortDescriptor<Trip> = switch sortKey {
|
|
286
|
-
case .name: SortDescriptor(\.name, order: sortOrder)
|
|
287
|
-
case .date: SortDescriptor(\.startDate, order: sortOrder)
|
|
288
|
-
case .destination: SortDescriptor(\.destination, order: sortOrder)
|
|
289
|
-
}
|
|
290
|
-
_trips = Query(sort: [sortDescriptor])
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
var body: some View {
|
|
294
|
-
List(trips) { trip in
|
|
295
|
-
TripRow(trip: trip)
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
---
|
|
302
|
-
|
|
303
|
-
## Sectioned Queries Pattern
|
|
304
|
-
|
|
305
|
-
SwiftData does not provide a built-in sectioned query like Core Data's
|
|
306
|
-
`NSFetchedResultsController`. Build sectioned views manually:
|
|
307
|
-
|
|
308
|
-
### Using Dictionary Grouping
|
|
309
|
-
|
|
310
|
-
```swift
|
|
311
|
-
struct SectionedTripListView: View {
|
|
312
|
-
@Query(sort: \.startDate) private var trips: [Trip]
|
|
313
|
-
|
|
314
|
-
private var sections: [(String, [Trip])] {
|
|
315
|
-
let formatter = DateFormatter()
|
|
316
|
-
formatter.dateFormat = "MMMM yyyy"
|
|
317
|
-
let grouped = Dictionary(grouping: trips) { trip in
|
|
318
|
-
formatter.string(from: trip.startDate)
|
|
319
|
-
}
|
|
320
|
-
return grouped.sorted { $0.key < $1.key }
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
var body: some View {
|
|
324
|
-
List {
|
|
325
|
-
ForEach(sections, id: \.0) { section, trips in
|
|
326
|
-
Section(section) {
|
|
327
|
-
ForEach(trips) { trip in
|
|
328
|
-
TripRow(trip: trip)
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Using Enum-Based Sections
|
|
338
|
-
|
|
339
|
-
```swift
|
|
340
|
-
enum TripStatus: String, CaseIterable {
|
|
341
|
-
case upcoming = "Upcoming"
|
|
342
|
-
case current = "Current"
|
|
343
|
-
case past = "Past"
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
struct StatusSectionedView: View {
|
|
347
|
-
@Query(sort: \.startDate) private var trips: [Trip]
|
|
348
|
-
|
|
349
|
-
private func trips(for status: TripStatus) -> [Trip] {
|
|
350
|
-
let now = Date.now
|
|
351
|
-
return trips.filter { trip in
|
|
352
|
-
switch status {
|
|
353
|
-
case .upcoming: trip.startDate > now
|
|
354
|
-
case .current: trip.startDate <= now && trip.endDate >= now
|
|
355
|
-
case .past: trip.endDate < now
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
var body: some View {
|
|
361
|
-
List {
|
|
362
|
-
ForEach(TripStatus.allCases, id: \.self) { status in
|
|
363
|
-
let sectionTrips = trips(for: status)
|
|
364
|
-
if !sectionTrips.isEmpty {
|
|
365
|
-
Section(status.rawValue) {
|
|
366
|
-
ForEach(sectionTrips) { trip in
|
|
367
|
-
TripRow(trip: trip)
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
---
|
|
378
|
-
|
|
379
|
-
## Dynamic Query Switching
|
|
380
|
-
|
|
381
|
-
### Filter + Sort Controlled by Parent
|
|
382
|
-
|
|
383
|
-
```swift
|
|
384
|
-
struct TripBrowserView: View {
|
|
385
|
-
@State private var searchText = ""
|
|
386
|
-
@State private var showFavoritesOnly = false
|
|
387
|
-
|
|
388
|
-
var body: some View {
|
|
389
|
-
NavigationStack {
|
|
390
|
-
FilteredTripList(
|
|
391
|
-
searchText: searchText,
|
|
392
|
-
favoritesOnly: showFavoritesOnly
|
|
393
|
-
)
|
|
394
|
-
.searchable(text: $searchText)
|
|
395
|
-
.toolbar {
|
|
396
|
-
Toggle("Favorites", isOn: $showFavoritesOnly)
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
struct FilteredTripList: View {
|
|
403
|
-
@Query private var trips: [Trip]
|
|
404
|
-
|
|
405
|
-
init(searchText: String, favoritesOnly: Bool) {
|
|
406
|
-
let predicate = #Predicate<Trip> { trip in
|
|
407
|
-
(searchText.isEmpty || trip.name.localizedStandardContains(searchText))
|
|
408
|
-
&& (!favoritesOnly || trip.isFavorite == true)
|
|
409
|
-
}
|
|
410
|
-
_trips = Query(
|
|
411
|
-
filter: predicate,
|
|
412
|
-
sort: [SortDescriptor(\.startDate, order: .reverse)]
|
|
413
|
-
)
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
var body: some View {
|
|
417
|
-
List(trips) { trip in
|
|
418
|
-
NavigationLink(trip.name) {
|
|
419
|
-
TripDetailView(trip: trip)
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### Full Dynamic Descriptor
|
|
427
|
-
|
|
428
|
-
```swift
|
|
429
|
-
struct AdvancedTripList: View {
|
|
430
|
-
@Query private var trips: [Trip]
|
|
431
|
-
|
|
432
|
-
init(
|
|
433
|
-
destination: String?,
|
|
434
|
-
minDate: Date?,
|
|
435
|
-
sortKey: KeyPath<Trip, some Comparable>,
|
|
436
|
-
ascending: Bool,
|
|
437
|
-
limit: Int?
|
|
438
|
-
) {
|
|
439
|
-
var descriptor = FetchDescriptor<Trip>(
|
|
440
|
-
sortBy: [SortDescriptor(\.startDate, order: ascending ? .forward : .reverse)]
|
|
441
|
-
)
|
|
442
|
-
|
|
443
|
-
if let destination {
|
|
444
|
-
descriptor.predicate = #Predicate<Trip> { trip in
|
|
445
|
-
trip.destination == destination
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
if let limit {
|
|
450
|
-
descriptor.fetchLimit = limit
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
_trips = Query(descriptor)
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
var body: some View {
|
|
457
|
-
List(trips) { trip in
|
|
458
|
-
TripRow(trip: trip)
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
---
|
|
465
|
-
|
|
466
|
-
## Background Fetch Patterns with @ModelActor
|
|
467
|
-
|
|
468
|
-
### Basic Background Fetch
|
|
469
|
-
|
|
470
|
-
```swift
|
|
471
|
-
@ModelActor
|
|
472
|
-
actor TripDataHandler {
|
|
473
|
-
func fetchUpcomingTrips() throws -> [PersistentIdentifier] {
|
|
474
|
-
let descriptor = FetchDescriptor<Trip>(
|
|
475
|
-
predicate: #Predicate { $0.startDate > Date.now },
|
|
476
|
-
sortBy: [SortDescriptor(\.startDate)]
|
|
477
|
-
)
|
|
478
|
-
return try modelContext.fetchIdentifiers(descriptor)
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
func fetchTripCount(destination: String) throws -> Int {
|
|
482
|
-
let descriptor = FetchDescriptor<Trip>(
|
|
483
|
-
predicate: #Predicate<Trip> { trip in
|
|
484
|
-
trip.destination == destination
|
|
485
|
-
}
|
|
486
|
-
)
|
|
487
|
-
return try modelContext.fetchCount(descriptor)
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// Usage from SwiftUI view
|
|
492
|
-
struct TripDashboardView: View {
|
|
493
|
-
@Environment(\.modelContext) private var modelContext
|
|
494
|
-
@State private var upcomingCount = 0
|
|
495
|
-
|
|
496
|
-
var body: some View {
|
|
497
|
-
Text("Upcoming: \(upcomingCount)")
|
|
498
|
-
.task {
|
|
499
|
-
let handler = TripDataHandler(
|
|
500
|
-
modelContainer: modelContext.container
|
|
501
|
-
)
|
|
502
|
-
upcomingCount = (try? await handler.fetchTripCount(
|
|
503
|
-
destination: "Paris"
|
|
504
|
-
)) ?? 0
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
### Background Import with Progress
|
|
511
|
-
|
|
512
|
-
```swift
|
|
513
|
-
@ModelActor
|
|
514
|
-
actor ImportHandler {
|
|
515
|
-
func importTrips(
|
|
516
|
-
_ records: [TripRecord],
|
|
517
|
-
progress: @Sendable (Int) -> Void
|
|
518
|
-
) throws -> Int {
|
|
519
|
-
var imported = 0
|
|
520
|
-
for (index, record) in records.enumerated() {
|
|
521
|
-
let trip = Trip(
|
|
522
|
-
name: record.name,
|
|
523
|
-
destination: record.destination,
|
|
524
|
-
startDate: record.startDate,
|
|
525
|
-
endDate: record.endDate
|
|
526
|
-
)
|
|
527
|
-
modelContext.insert(trip)
|
|
528
|
-
imported += 1
|
|
529
|
-
|
|
530
|
-
// Save periodically to flush memory
|
|
531
|
-
if index % 500 == 0 {
|
|
532
|
-
try modelContext.save()
|
|
533
|
-
progress(imported)
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
try modelContext.save()
|
|
537
|
-
return imported
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
### Resolving Identifiers on MainActor
|
|
543
|
-
|
|
544
|
-
```swift
|
|
545
|
-
@ModelActor
|
|
546
|
-
actor DataHandler {
|
|
547
|
-
func findDuplicateIDs() throws -> [PersistentIdentifier] {
|
|
548
|
-
// Complex logic to find duplicates
|
|
549
|
-
let all = try modelContext.fetch(FetchDescriptor<Trip>())
|
|
550
|
-
var seen = Set<String>()
|
|
551
|
-
var duplicateIDs: [PersistentIdentifier] = []
|
|
552
|
-
for trip in all {
|
|
553
|
-
if seen.contains(trip.name) {
|
|
554
|
-
duplicateIDs.append(trip.persistentModelID)
|
|
555
|
-
}
|
|
556
|
-
seen.insert(trip.name)
|
|
557
|
-
}
|
|
558
|
-
return duplicateIDs
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// On MainActor, resolve IDs to objects
|
|
563
|
-
struct DuplicateReviewView: View {
|
|
564
|
-
@Environment(\.modelContext) private var modelContext
|
|
565
|
-
@State private var duplicates: [Trip] = []
|
|
566
|
-
|
|
567
|
-
var body: some View {
|
|
568
|
-
List(duplicates) { trip in
|
|
569
|
-
Text(trip.name)
|
|
570
|
-
}
|
|
571
|
-
.task {
|
|
572
|
-
let handler = DataHandler(modelContainer: modelContext.container)
|
|
573
|
-
let ids = (try? await handler.findDuplicateIDs()) ?? []
|
|
574
|
-
duplicates = ids.compactMap { id in
|
|
575
|
-
modelContext.registeredModel(for: id) as Trip?
|
|
576
|
-
?? (try? modelContext.model(for: id) as? Trip)
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
---
|
|
584
|
-
|
|
585
|
-
## Aggregate Queries
|
|
586
|
-
|
|
587
|
-
SwiftData does not provide built-in aggregate functions (SUM, AVG, etc.).
|
|
588
|
-
Compute aggregates using fetch + Swift computation.
|
|
589
|
-
|
|
590
|
-
### Count
|
|
591
|
-
|
|
592
|
-
```swift
|
|
593
|
-
let count = try modelContext.fetchCount(
|
|
594
|
-
FetchDescriptor<Trip>(predicate: #Predicate { $0.isFavorite == true })
|
|
595
|
-
)
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
### Sum, Average, Min, Max
|
|
599
|
-
|
|
600
|
-
```swift
|
|
601
|
-
let trips = try modelContext.fetch(FetchDescriptor<Trip>())
|
|
602
|
-
|
|
603
|
-
let totalBudget = trips.reduce(0.0) { $0 + $1.budget }
|
|
604
|
-
let averageBudget = trips.isEmpty ? 0 : totalBudget / Double(trips.count)
|
|
605
|
-
let maxBudget = trips.map(\.budget).max() ?? 0
|
|
606
|
-
let minBudget = trips.map(\.budget).min() ?? 0
|
|
607
|
-
```
|
|
608
|
-
|
|
609
|
-
### Efficient Aggregates with Partial Fetch
|
|
610
|
-
|
|
611
|
-
Fetch only the property needed for aggregation:
|
|
612
|
-
|
|
613
|
-
```swift
|
|
614
|
-
var descriptor = FetchDescriptor<Trip>()
|
|
615
|
-
descriptor.propertiesToFetch = [\.budget]
|
|
616
|
-
let trips = try modelContext.fetch(descriptor)
|
|
617
|
-
let total = trips.reduce(0.0) { $0 + $1.budget }
|
|
618
|
-
```
|
|
619
|
-
|
|
620
|
-
### Background Aggregate Computation
|
|
621
|
-
|
|
622
|
-
```swift
|
|
623
|
-
@ModelActor
|
|
624
|
-
actor StatsHandler {
|
|
625
|
-
struct TripStats: Sendable {
|
|
626
|
-
let totalCount: Int
|
|
627
|
-
let favoriteCount: Int
|
|
628
|
-
let averageDuration: TimeInterval
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
func computeStats() throws -> TripStats {
|
|
632
|
-
let allTrips = try modelContext.fetch(FetchDescriptor<Trip>())
|
|
633
|
-
let favoriteCount = try modelContext.fetchCount(
|
|
634
|
-
FetchDescriptor<Trip>(predicate: #Predicate { $0.isFavorite == true })
|
|
635
|
-
)
|
|
636
|
-
|
|
637
|
-
let totalDuration = allTrips.reduce(0.0) { sum, trip in
|
|
638
|
-
sum + trip.endDate.timeIntervalSince(trip.startDate)
|
|
639
|
-
}
|
|
640
|
-
let avgDuration = allTrips.isEmpty ? 0 : totalDuration / Double(allTrips.count)
|
|
641
|
-
|
|
642
|
-
return TripStats(
|
|
643
|
-
totalCount: allTrips.count,
|
|
644
|
-
favoriteCount: favoriteCount,
|
|
645
|
-
averageDuration: avgDuration
|
|
646
|
-
)
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
```
|
|
650
|
-
|
|
651
|
-
---
|
|
652
|
-
|
|
653
|
-
## Enumerate for Large Datasets
|
|
654
|
-
|
|
655
|
-
Use `enumerate` instead of `fetch` when processing many records to keep memory
|
|
656
|
-
usage constant:
|
|
657
|
-
|
|
658
|
-
```swift
|
|
659
|
-
// Process all trips without loading all into memory
|
|
660
|
-
try modelContext.enumerate(
|
|
661
|
-
FetchDescriptor<Trip>(sortBy: [SortDescriptor(\.startDate)]),
|
|
662
|
-
batchSize: 1000,
|
|
663
|
-
allowEscapingMutations: false
|
|
664
|
-
) { trip in
|
|
665
|
-
// Process each trip
|
|
666
|
-
trip.isProcessed = true
|
|
667
|
-
}
|
|
668
|
-
try modelContext.save()
|
|
669
|
-
```
|
|
670
|
-
|
|
671
|
-
Parameters:
|
|
672
|
-
- `batchSize`: Objects per batch (default 5000). Lower values use less memory.
|
|
673
|
-
- `allowEscapingMutations`: When `false`, objects are autoreleased after the
|
|
674
|
-
block. Set to `true` only if mutations must persist beyond the block.
|
|
675
|
-
|
|
1
|
+
# SwiftData Queries Reference
|
|
2
|
+
|
|
3
|
+
Deep reference for all @Query initializer variants, FetchDescriptor options,
|
|
4
|
+
sort descriptors, sectioned queries, dynamic query switching, background fetch
|
|
5
|
+
patterns, and aggregate queries.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Contents
|
|
10
|
+
|
|
11
|
+
- [@Query Initializer Variants](#query-initializer-variants)
|
|
12
|
+
- [FetchDescriptor Deep Dive](#fetchdescriptor-deep-dive)
|
|
13
|
+
- [Complex Sort Descriptors](#complex-sort-descriptors)
|
|
14
|
+
- [Sectioned Queries Pattern](#sectioned-queries-pattern)
|
|
15
|
+
- [Dynamic Query Switching](#dynamic-query-switching)
|
|
16
|
+
- [Background Fetch Patterns with @ModelActor](#background-fetch-patterns-with-modelactor)
|
|
17
|
+
- [Aggregate Queries](#aggregate-queries)
|
|
18
|
+
- [Enumerate for Large Datasets](#enumerate-for-large-datasets)
|
|
19
|
+
|
|
20
|
+
## @Query Initializer Variants
|
|
21
|
+
|
|
22
|
+
`@Query` is a SwiftUI property wrapper (`DynamicProperty`) that automatically
|
|
23
|
+
fetches and observes persistent model data. All variants are `@MainActor`.
|
|
24
|
+
|
|
25
|
+
### Basic (No Filter, No Sort)
|
|
26
|
+
|
|
27
|
+
```swift
|
|
28
|
+
// Fetch all, default order
|
|
29
|
+
@Query private var trips: [Trip]
|
|
30
|
+
|
|
31
|
+
// With animation
|
|
32
|
+
@Query(animation: .default) private var trips: [Trip]
|
|
33
|
+
|
|
34
|
+
// With transaction
|
|
35
|
+
@Query(transaction: Transaction(animation: .spring)) private var trips: [Trip]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Filter + SortDescriptor Array
|
|
39
|
+
|
|
40
|
+
```swift
|
|
41
|
+
@Query(
|
|
42
|
+
filter: #Predicate<Trip> { $0.isFavorite == true },
|
|
43
|
+
sort: [SortDescriptor(\.startDate, order: .reverse)]
|
|
44
|
+
)
|
|
45
|
+
private var favoriteTrips: [Trip]
|
|
46
|
+
|
|
47
|
+
// With animation
|
|
48
|
+
@Query(
|
|
49
|
+
filter: #Predicate<Trip> { $0.isFavorite == true },
|
|
50
|
+
sort: [SortDescriptor(\.startDate, order: .reverse)],
|
|
51
|
+
animation: .default
|
|
52
|
+
)
|
|
53
|
+
private var favoriteTrips: [Trip]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Filter + KeyPath Sort
|
|
57
|
+
|
|
58
|
+
```swift
|
|
59
|
+
@Query(
|
|
60
|
+
filter: #Predicate<Trip> { $0.destination != "" },
|
|
61
|
+
sort: \.startDate,
|
|
62
|
+
order: .forward
|
|
63
|
+
)
|
|
64
|
+
private var upcomingTrips: [Trip]
|
|
65
|
+
|
|
66
|
+
// With optional key path sort
|
|
67
|
+
@Query(
|
|
68
|
+
sort: \.endDate, // KeyPath<Trip, Date?> -- optional sort key
|
|
69
|
+
order: .reverse
|
|
70
|
+
)
|
|
71
|
+
private var tripsByEndDate: [Trip]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### FetchDescriptor
|
|
75
|
+
|
|
76
|
+
```swift
|
|
77
|
+
static var recentDescriptor: FetchDescriptor<Trip> {
|
|
78
|
+
var d = FetchDescriptor<Trip>(
|
|
79
|
+
predicate: #Predicate { $0.startDate > Date.now },
|
|
80
|
+
sortBy: [SortDescriptor(\.startDate)]
|
|
81
|
+
)
|
|
82
|
+
d.fetchLimit = 10
|
|
83
|
+
return d
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@Query(RecentTripsView.recentDescriptor) private var recentTrips: [Trip]
|
|
87
|
+
|
|
88
|
+
// With animation
|
|
89
|
+
@Query(RecentTripsView.recentDescriptor, animation: .default)
|
|
90
|
+
private var recentTrips: [Trip]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Query Properties
|
|
94
|
+
|
|
95
|
+
| Property | Type | Description |
|
|
96
|
+
|----------|------|-------------|
|
|
97
|
+
| `wrappedValue` | `Result` (typically `[Element]`) | Most recent fetched results |
|
|
98
|
+
| `modelContext` | `ModelContext` | The context used for fetching |
|
|
99
|
+
| `fetchError` | `(any Error)?` | Error from most recent fetch, if any |
|
|
100
|
+
|
|
101
|
+
Access `fetchError` to detect query failures:
|
|
102
|
+
|
|
103
|
+
```swift
|
|
104
|
+
struct TripListView: View {
|
|
105
|
+
@Query private var trips: [Trip]
|
|
106
|
+
|
|
107
|
+
var body: some View {
|
|
108
|
+
Group {
|
|
109
|
+
if let error = $trips.fetchError {
|
|
110
|
+
ContentUnavailableView("Fetch Error",
|
|
111
|
+
systemImage: "exclamationmark.triangle",
|
|
112
|
+
description: Text(error.localizedDescription))
|
|
113
|
+
} else {
|
|
114
|
+
List(trips) { trip in
|
|
115
|
+
Text(trip.name)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## FetchDescriptor Deep Dive
|
|
126
|
+
|
|
127
|
+
### Full Property Reference
|
|
128
|
+
|
|
129
|
+
```swift
|
|
130
|
+
var descriptor = FetchDescriptor<Trip>()
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
| Property | Type | Default | Description |
|
|
134
|
+
|----------|------|---------|-------------|
|
|
135
|
+
| `predicate` | `Predicate<T>?` | `nil` | Filter condition |
|
|
136
|
+
| `sortBy` | `[SortDescriptor<T>]` | `[]` | Sort order |
|
|
137
|
+
| `fetchLimit` | `Int?` | `nil` | Maximum results |
|
|
138
|
+
| `fetchOffset` | `Int?` | `nil` | Skip first N results |
|
|
139
|
+
| `includePendingChanges` | `Bool` | `true` | Include unsaved in-memory changes |
|
|
140
|
+
| `propertiesToFetch` | `[PartialKeyPath<T>]` | all | Specific properties to load |
|
|
141
|
+
| `relationshipKeyPathsForPrefetching` | `[PartialKeyPath<T>]` | `[]` | Related models to eagerly load |
|
|
142
|
+
|
|
143
|
+
### fetchLimit and fetchOffset (Pagination)
|
|
144
|
+
|
|
145
|
+
```swift
|
|
146
|
+
func fetchPage(page: Int, pageSize: Int) throws -> [Trip] {
|
|
147
|
+
var descriptor = FetchDescriptor<Trip>(
|
|
148
|
+
sortBy: [SortDescriptor(\.startDate)]
|
|
149
|
+
)
|
|
150
|
+
descriptor.fetchLimit = pageSize
|
|
151
|
+
descriptor.fetchOffset = page * pageSize
|
|
152
|
+
return try modelContext.fetch(descriptor)
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### includePendingChanges
|
|
157
|
+
|
|
158
|
+
When `true` (default), the fetch includes objects inserted or modified in the
|
|
159
|
+
current context but not yet saved. Set to `false` for read-only queries against
|
|
160
|
+
the persisted store only.
|
|
161
|
+
|
|
162
|
+
```swift
|
|
163
|
+
var descriptor = FetchDescriptor<Trip>()
|
|
164
|
+
descriptor.includePendingChanges = false // Only persisted data
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Note: `includePendingChanges: true` cannot be used with batched fetches
|
|
168
|
+
(`fetch(_:batchSize:)`). This will throw
|
|
169
|
+
`SwiftDataError.includePendingChangesWithBatchSize`.
|
|
170
|
+
|
|
171
|
+
### propertiesToFetch (Partial Loading)
|
|
172
|
+
|
|
173
|
+
Load only specific attributes to reduce memory footprint:
|
|
174
|
+
|
|
175
|
+
```swift
|
|
176
|
+
var descriptor = FetchDescriptor<Trip>()
|
|
177
|
+
descriptor.propertiesToFetch = [\.name, \.destination, \.startDate]
|
|
178
|
+
let trips = try modelContext.fetch(descriptor)
|
|
179
|
+
// Only name, destination, startDate are loaded; other properties fault on access
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### relationshipKeyPathsForPrefetching
|
|
183
|
+
|
|
184
|
+
Eagerly load related objects to avoid N+1 query patterns:
|
|
185
|
+
|
|
186
|
+
```swift
|
|
187
|
+
var descriptor = FetchDescriptor<Trip>()
|
|
188
|
+
descriptor.relationshipKeyPathsForPrefetching = [
|
|
189
|
+
\.accommodation,
|
|
190
|
+
\.tags
|
|
191
|
+
]
|
|
192
|
+
let trips = try modelContext.fetch(descriptor)
|
|
193
|
+
// Accessing trip.accommodation does not trigger a separate fetch
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Fetch Variants on ModelContext
|
|
197
|
+
|
|
198
|
+
| Method | Returns | Use Case |
|
|
199
|
+
|--------|---------|----------|
|
|
200
|
+
| `fetch(_:)` | `[T]` | Standard fetch, all results in memory |
|
|
201
|
+
| `fetch(_:batchSize:)` | `FetchResultsCollection<T>` | Lazy batched loading |
|
|
202
|
+
| `fetchCount(_:)` | `Int` | Count only, no objects loaded |
|
|
203
|
+
| `fetchIdentifiers(_:)` | `[PersistentIdentifier]` | IDs only, lightweight |
|
|
204
|
+
| `fetchIdentifiers(_:batchSize:)` | `FetchResultsCollection<PersistentIdentifier>` | Batched ID loading |
|
|
205
|
+
| `enumerate(_:batchSize:...)` | `Void` | Process large sets in batches |
|
|
206
|
+
|
|
207
|
+
### FetchResultsCollection (Batched Fetch)
|
|
208
|
+
|
|
209
|
+
```swift
|
|
210
|
+
let results: FetchResultsCollection<Trip> = try modelContext.fetch(
|
|
211
|
+
FetchDescriptor<Trip>(sortBy: [SortDescriptor(\.name)]),
|
|
212
|
+
batchSize: 100
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
// Iterate lazily -- only 100 objects in memory at a time
|
|
216
|
+
for trip in results {
|
|
217
|
+
print(trip.name)
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Requirements for batched fetch:
|
|
222
|
+
- `includePendingChanges` must be `false` (or will throw).
|
|
223
|
+
- Results are read-only snapshots.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Complex Sort Descriptors
|
|
228
|
+
|
|
229
|
+
### Single Sort
|
|
230
|
+
|
|
231
|
+
```swift
|
|
232
|
+
SortDescriptor(\.name, order: .forward) // A-Z
|
|
233
|
+
SortDescriptor(\.name, order: .reverse) // Z-A
|
|
234
|
+
SortDescriptor(\.startDate) // Ascending (default)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Multi-Level Sort
|
|
238
|
+
|
|
239
|
+
```swift
|
|
240
|
+
let descriptor = FetchDescriptor<Trip>(
|
|
241
|
+
sortBy: [
|
|
242
|
+
SortDescriptor(\.isFavorite, order: .reverse), // Favorites first
|
|
243
|
+
SortDescriptor(\.startDate, order: .forward), // Then by date
|
|
244
|
+
SortDescriptor(\.name, order: .forward) // Then alphabetical
|
|
245
|
+
]
|
|
246
|
+
)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Optional Key Path Sort
|
|
250
|
+
|
|
251
|
+
Sort on optional properties -- nil values sort to the end:
|
|
252
|
+
|
|
253
|
+
```swift
|
|
254
|
+
@Query(sort: \.endDate, order: .reverse) private var trips: [Trip]
|
|
255
|
+
// endDate is Date? -- trips without endDate appear last
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Dynamic Sort Switching
|
|
259
|
+
|
|
260
|
+
```swift
|
|
261
|
+
struct TripListView: View {
|
|
262
|
+
@State private var sortOrder: SortOrder = .forward
|
|
263
|
+
@State private var sortKey: TripSortKey = .name
|
|
264
|
+
|
|
265
|
+
var body: some View {
|
|
266
|
+
SortedTripList(sortKey: sortKey, sortOrder: sortOrder)
|
|
267
|
+
.toolbar {
|
|
268
|
+
Picker("Sort", selection: $sortKey) {
|
|
269
|
+
Text("Name").tag(TripSortKey.name)
|
|
270
|
+
Text("Date").tag(TripSortKey.date)
|
|
271
|
+
Text("Destination").tag(TripSortKey.destination)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
enum TripSortKey: String, CaseIterable {
|
|
278
|
+
case name, date, destination
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
struct SortedTripList: View {
|
|
282
|
+
@Query private var trips: [Trip]
|
|
283
|
+
|
|
284
|
+
init(sortKey: TripSortKey, sortOrder: SortOrder) {
|
|
285
|
+
let sortDescriptor: SortDescriptor<Trip> = switch sortKey {
|
|
286
|
+
case .name: SortDescriptor(\.name, order: sortOrder)
|
|
287
|
+
case .date: SortDescriptor(\.startDate, order: sortOrder)
|
|
288
|
+
case .destination: SortDescriptor(\.destination, order: sortOrder)
|
|
289
|
+
}
|
|
290
|
+
_trips = Query(sort: [sortDescriptor])
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
var body: some View {
|
|
294
|
+
List(trips) { trip in
|
|
295
|
+
TripRow(trip: trip)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Sectioned Queries Pattern
|
|
304
|
+
|
|
305
|
+
SwiftData does not provide a built-in sectioned query like Core Data's
|
|
306
|
+
`NSFetchedResultsController`. Build sectioned views manually:
|
|
307
|
+
|
|
308
|
+
### Using Dictionary Grouping
|
|
309
|
+
|
|
310
|
+
```swift
|
|
311
|
+
struct SectionedTripListView: View {
|
|
312
|
+
@Query(sort: \.startDate) private var trips: [Trip]
|
|
313
|
+
|
|
314
|
+
private var sections: [(String, [Trip])] {
|
|
315
|
+
let formatter = DateFormatter()
|
|
316
|
+
formatter.dateFormat = "MMMM yyyy"
|
|
317
|
+
let grouped = Dictionary(grouping: trips) { trip in
|
|
318
|
+
formatter.string(from: trip.startDate)
|
|
319
|
+
}
|
|
320
|
+
return grouped.sorted { $0.key < $1.key }
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
var body: some View {
|
|
324
|
+
List {
|
|
325
|
+
ForEach(sections, id: \.0) { section, trips in
|
|
326
|
+
Section(section) {
|
|
327
|
+
ForEach(trips) { trip in
|
|
328
|
+
TripRow(trip: trip)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Using Enum-Based Sections
|
|
338
|
+
|
|
339
|
+
```swift
|
|
340
|
+
enum TripStatus: String, CaseIterable {
|
|
341
|
+
case upcoming = "Upcoming"
|
|
342
|
+
case current = "Current"
|
|
343
|
+
case past = "Past"
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
struct StatusSectionedView: View {
|
|
347
|
+
@Query(sort: \.startDate) private var trips: [Trip]
|
|
348
|
+
|
|
349
|
+
private func trips(for status: TripStatus) -> [Trip] {
|
|
350
|
+
let now = Date.now
|
|
351
|
+
return trips.filter { trip in
|
|
352
|
+
switch status {
|
|
353
|
+
case .upcoming: trip.startDate > now
|
|
354
|
+
case .current: trip.startDate <= now && trip.endDate >= now
|
|
355
|
+
case .past: trip.endDate < now
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
var body: some View {
|
|
361
|
+
List {
|
|
362
|
+
ForEach(TripStatus.allCases, id: \.self) { status in
|
|
363
|
+
let sectionTrips = trips(for: status)
|
|
364
|
+
if !sectionTrips.isEmpty {
|
|
365
|
+
Section(status.rawValue) {
|
|
366
|
+
ForEach(sectionTrips) { trip in
|
|
367
|
+
TripRow(trip: trip)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Dynamic Query Switching
|
|
380
|
+
|
|
381
|
+
### Filter + Sort Controlled by Parent
|
|
382
|
+
|
|
383
|
+
```swift
|
|
384
|
+
struct TripBrowserView: View {
|
|
385
|
+
@State private var searchText = ""
|
|
386
|
+
@State private var showFavoritesOnly = false
|
|
387
|
+
|
|
388
|
+
var body: some View {
|
|
389
|
+
NavigationStack {
|
|
390
|
+
FilteredTripList(
|
|
391
|
+
searchText: searchText,
|
|
392
|
+
favoritesOnly: showFavoritesOnly
|
|
393
|
+
)
|
|
394
|
+
.searchable(text: $searchText)
|
|
395
|
+
.toolbar {
|
|
396
|
+
Toggle("Favorites", isOn: $showFavoritesOnly)
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
struct FilteredTripList: View {
|
|
403
|
+
@Query private var trips: [Trip]
|
|
404
|
+
|
|
405
|
+
init(searchText: String, favoritesOnly: Bool) {
|
|
406
|
+
let predicate = #Predicate<Trip> { trip in
|
|
407
|
+
(searchText.isEmpty || trip.name.localizedStandardContains(searchText))
|
|
408
|
+
&& (!favoritesOnly || trip.isFavorite == true)
|
|
409
|
+
}
|
|
410
|
+
_trips = Query(
|
|
411
|
+
filter: predicate,
|
|
412
|
+
sort: [SortDescriptor(\.startDate, order: .reverse)]
|
|
413
|
+
)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
var body: some View {
|
|
417
|
+
List(trips) { trip in
|
|
418
|
+
NavigationLink(trip.name) {
|
|
419
|
+
TripDetailView(trip: trip)
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Full Dynamic Descriptor
|
|
427
|
+
|
|
428
|
+
```swift
|
|
429
|
+
struct AdvancedTripList: View {
|
|
430
|
+
@Query private var trips: [Trip]
|
|
431
|
+
|
|
432
|
+
init(
|
|
433
|
+
destination: String?,
|
|
434
|
+
minDate: Date?,
|
|
435
|
+
sortKey: KeyPath<Trip, some Comparable>,
|
|
436
|
+
ascending: Bool,
|
|
437
|
+
limit: Int?
|
|
438
|
+
) {
|
|
439
|
+
var descriptor = FetchDescriptor<Trip>(
|
|
440
|
+
sortBy: [SortDescriptor(\.startDate, order: ascending ? .forward : .reverse)]
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
if let destination {
|
|
444
|
+
descriptor.predicate = #Predicate<Trip> { trip in
|
|
445
|
+
trip.destination == destination
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if let limit {
|
|
450
|
+
descriptor.fetchLimit = limit
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
_trips = Query(descriptor)
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
var body: some View {
|
|
457
|
+
List(trips) { trip in
|
|
458
|
+
TripRow(trip: trip)
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## Background Fetch Patterns with @ModelActor
|
|
467
|
+
|
|
468
|
+
### Basic Background Fetch
|
|
469
|
+
|
|
470
|
+
```swift
|
|
471
|
+
@ModelActor
|
|
472
|
+
actor TripDataHandler {
|
|
473
|
+
func fetchUpcomingTrips() throws -> [PersistentIdentifier] {
|
|
474
|
+
let descriptor = FetchDescriptor<Trip>(
|
|
475
|
+
predicate: #Predicate { $0.startDate > Date.now },
|
|
476
|
+
sortBy: [SortDescriptor(\.startDate)]
|
|
477
|
+
)
|
|
478
|
+
return try modelContext.fetchIdentifiers(descriptor)
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
func fetchTripCount(destination: String) throws -> Int {
|
|
482
|
+
let descriptor = FetchDescriptor<Trip>(
|
|
483
|
+
predicate: #Predicate<Trip> { trip in
|
|
484
|
+
trip.destination == destination
|
|
485
|
+
}
|
|
486
|
+
)
|
|
487
|
+
return try modelContext.fetchCount(descriptor)
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Usage from SwiftUI view
|
|
492
|
+
struct TripDashboardView: View {
|
|
493
|
+
@Environment(\.modelContext) private var modelContext
|
|
494
|
+
@State private var upcomingCount = 0
|
|
495
|
+
|
|
496
|
+
var body: some View {
|
|
497
|
+
Text("Upcoming: \(upcomingCount)")
|
|
498
|
+
.task {
|
|
499
|
+
let handler = TripDataHandler(
|
|
500
|
+
modelContainer: modelContext.container
|
|
501
|
+
)
|
|
502
|
+
upcomingCount = (try? await handler.fetchTripCount(
|
|
503
|
+
destination: "Paris"
|
|
504
|
+
)) ?? 0
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Background Import with Progress
|
|
511
|
+
|
|
512
|
+
```swift
|
|
513
|
+
@ModelActor
|
|
514
|
+
actor ImportHandler {
|
|
515
|
+
func importTrips(
|
|
516
|
+
_ records: [TripRecord],
|
|
517
|
+
progress: @Sendable (Int) -> Void
|
|
518
|
+
) throws -> Int {
|
|
519
|
+
var imported = 0
|
|
520
|
+
for (index, record) in records.enumerated() {
|
|
521
|
+
let trip = Trip(
|
|
522
|
+
name: record.name,
|
|
523
|
+
destination: record.destination,
|
|
524
|
+
startDate: record.startDate,
|
|
525
|
+
endDate: record.endDate
|
|
526
|
+
)
|
|
527
|
+
modelContext.insert(trip)
|
|
528
|
+
imported += 1
|
|
529
|
+
|
|
530
|
+
// Save periodically to flush memory
|
|
531
|
+
if index % 500 == 0 {
|
|
532
|
+
try modelContext.save()
|
|
533
|
+
progress(imported)
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
try modelContext.save()
|
|
537
|
+
return imported
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### Resolving Identifiers on MainActor
|
|
543
|
+
|
|
544
|
+
```swift
|
|
545
|
+
@ModelActor
|
|
546
|
+
actor DataHandler {
|
|
547
|
+
func findDuplicateIDs() throws -> [PersistentIdentifier] {
|
|
548
|
+
// Complex logic to find duplicates
|
|
549
|
+
let all = try modelContext.fetch(FetchDescriptor<Trip>())
|
|
550
|
+
var seen = Set<String>()
|
|
551
|
+
var duplicateIDs: [PersistentIdentifier] = []
|
|
552
|
+
for trip in all {
|
|
553
|
+
if seen.contains(trip.name) {
|
|
554
|
+
duplicateIDs.append(trip.persistentModelID)
|
|
555
|
+
}
|
|
556
|
+
seen.insert(trip.name)
|
|
557
|
+
}
|
|
558
|
+
return duplicateIDs
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// On MainActor, resolve IDs to objects
|
|
563
|
+
struct DuplicateReviewView: View {
|
|
564
|
+
@Environment(\.modelContext) private var modelContext
|
|
565
|
+
@State private var duplicates: [Trip] = []
|
|
566
|
+
|
|
567
|
+
var body: some View {
|
|
568
|
+
List(duplicates) { trip in
|
|
569
|
+
Text(trip.name)
|
|
570
|
+
}
|
|
571
|
+
.task {
|
|
572
|
+
let handler = DataHandler(modelContainer: modelContext.container)
|
|
573
|
+
let ids = (try? await handler.findDuplicateIDs()) ?? []
|
|
574
|
+
duplicates = ids.compactMap { id in
|
|
575
|
+
modelContext.registeredModel(for: id) as Trip?
|
|
576
|
+
?? (try? modelContext.model(for: id) as? Trip)
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## Aggregate Queries
|
|
586
|
+
|
|
587
|
+
SwiftData does not provide built-in aggregate functions (SUM, AVG, etc.).
|
|
588
|
+
Compute aggregates using fetch + Swift computation.
|
|
589
|
+
|
|
590
|
+
### Count
|
|
591
|
+
|
|
592
|
+
```swift
|
|
593
|
+
let count = try modelContext.fetchCount(
|
|
594
|
+
FetchDescriptor<Trip>(predicate: #Predicate { $0.isFavorite == true })
|
|
595
|
+
)
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Sum, Average, Min, Max
|
|
599
|
+
|
|
600
|
+
```swift
|
|
601
|
+
let trips = try modelContext.fetch(FetchDescriptor<Trip>())
|
|
602
|
+
|
|
603
|
+
let totalBudget = trips.reduce(0.0) { $0 + $1.budget }
|
|
604
|
+
let averageBudget = trips.isEmpty ? 0 : totalBudget / Double(trips.count)
|
|
605
|
+
let maxBudget = trips.map(\.budget).max() ?? 0
|
|
606
|
+
let minBudget = trips.map(\.budget).min() ?? 0
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Efficient Aggregates with Partial Fetch
|
|
610
|
+
|
|
611
|
+
Fetch only the property needed for aggregation:
|
|
612
|
+
|
|
613
|
+
```swift
|
|
614
|
+
var descriptor = FetchDescriptor<Trip>()
|
|
615
|
+
descriptor.propertiesToFetch = [\.budget]
|
|
616
|
+
let trips = try modelContext.fetch(descriptor)
|
|
617
|
+
let total = trips.reduce(0.0) { $0 + $1.budget }
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### Background Aggregate Computation
|
|
621
|
+
|
|
622
|
+
```swift
|
|
623
|
+
@ModelActor
|
|
624
|
+
actor StatsHandler {
|
|
625
|
+
struct TripStats: Sendable {
|
|
626
|
+
let totalCount: Int
|
|
627
|
+
let favoriteCount: Int
|
|
628
|
+
let averageDuration: TimeInterval
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
func computeStats() throws -> TripStats {
|
|
632
|
+
let allTrips = try modelContext.fetch(FetchDescriptor<Trip>())
|
|
633
|
+
let favoriteCount = try modelContext.fetchCount(
|
|
634
|
+
FetchDescriptor<Trip>(predicate: #Predicate { $0.isFavorite == true })
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
let totalDuration = allTrips.reduce(0.0) { sum, trip in
|
|
638
|
+
sum + trip.endDate.timeIntervalSince(trip.startDate)
|
|
639
|
+
}
|
|
640
|
+
let avgDuration = allTrips.isEmpty ? 0 : totalDuration / Double(allTrips.count)
|
|
641
|
+
|
|
642
|
+
return TripStats(
|
|
643
|
+
totalCount: allTrips.count,
|
|
644
|
+
favoriteCount: favoriteCount,
|
|
645
|
+
averageDuration: avgDuration
|
|
646
|
+
)
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Enumerate for Large Datasets
|
|
654
|
+
|
|
655
|
+
Use `enumerate` instead of `fetch` when processing many records to keep memory
|
|
656
|
+
usage constant:
|
|
657
|
+
|
|
658
|
+
```swift
|
|
659
|
+
// Process all trips without loading all into memory
|
|
660
|
+
try modelContext.enumerate(
|
|
661
|
+
FetchDescriptor<Trip>(sortBy: [SortDescriptor(\.startDate)]),
|
|
662
|
+
batchSize: 1000,
|
|
663
|
+
allowEscapingMutations: false
|
|
664
|
+
) { trip in
|
|
665
|
+
// Process each trip
|
|
666
|
+
trip.isProcessed = true
|
|
667
|
+
}
|
|
668
|
+
try modelContext.save()
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
Parameters:
|
|
672
|
+
- `batchSize`: Objects per batch (default 5000). Lower values use less memory.
|
|
673
|
+
- `allowEscapingMutations`: When `false`, objects are autoreleased after the
|
|
674
|
+
block. Set to `true` only if mutations must persist beyond the block.
|
|
675
|
+
|