diff --git a/CHANGELOG.md b/CHANGELOG.md
index 608ffc4feea..f612bd9e544 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,443 +1,4 @@
-# EmberData Changelog
-
-## v5.3.4 (2024-06-15)
-
-#### :evergreen_tree: New Deprecation
-
-* [#9479](https://github.com/emberjs/data/pull/9479) feat: support migration path for ember-inflector usage ([@runspired](https://github.com/runspired))
-* [#9403](https://github.com/emberjs/data/pull/9403) feat: deprecate store extending EmberObject ([@runspired](https://github.com/runspired))
-
-#### :memo: Documentation
-
-* [#9394](https://github.com/emberjs/data/pull/9394) Add cookbook page about model names convention ([@Baltazore](https://github.com/Baltazore))
-* [#9393](https://github.com/emberjs/data/pull/9393) Update types on typescript guide part 4 ([@Baltazore](https://github.com/Baltazore))
-* [#9390](https://github.com/emberjs/data/pull/9390) docs: fix readme links in @warp-drive/ember ([@runspired](https://github.com/runspired))
-* [#9379](https://github.com/emberjs/data/pull/9379) fix: Automate uninstall process ([@MichalBryxi](https://github.com/MichalBryxi))
-* [#9378](https://github.com/emberjs/data/pull/9378) Update some docs to string ids ([@wagenet](https://github.com/wagenet))
-* [#9300](https://github.com/emberjs/data/pull/9300) doc: remove reference to unexisting ESA auth handler ([@sly7-7](https://github.com/sly7-7))
-* [#9332](https://github.com/emberjs/data/pull/9332) docs: add typescript guide ([@runspired](https://github.com/runspired))
-* [#9328](https://github.com/emberjs/data/pull/9328) chore: update READMEs with status and dist tag info ([@runspired](https://github.com/runspired))
-* [#9329](https://github.com/emberjs/data/pull/9329) chore: update compat chart in README ([@runspired](https://github.com/runspired))
-* [#9299](https://github.com/emberjs/data/pull/9299) doc: use store for save-record docs ([@Yelinz](https://github.com/Yelinz))
-* [#9298](https://github.com/emberjs/data/pull/9298) docs(request): remove duplicate line in readme ([@Yelinz](https://github.com/Yelinz))
-* [#9063](https://github.com/emberjs/data/pull/9063) docs: add requests guide ([@runspired](https://github.com/runspired))
-* [#9215](https://github.com/emberjs/data/pull/9215) Docs: Add guide for incremental adoption ([@Baltazore](https://github.com/Baltazore))
-* [#9275](https://github.com/emberjs/data/pull/9275) doc: don't mention unexisting ESA auth handler ([@sly7-7](https://github.com/sly7-7))
-
-#### :rocket: Enhancement
-
-* [#9474](https://github.com/emberjs/data/pull/9474) Improve query types for legacy-compat/builders ([@gitKrystan](https://github.com/gitKrystan))
-* [#9473](https://github.com/emberjs/data/pull/9473) npx: warp-drive retrofit types@canary 🪄 ([@runspired](https://github.com/runspired))
-* [#9471](https://github.com/emberjs/data/pull/9471) feat: npx warp-drive ([@runspired](https://github.com/runspired))
-* [#9467](https://github.com/emberjs/data/pull/9467) feat: implement schema-object for schema-record ([@richgt](https://github.com/richgt))
-* [#9468](https://github.com/emberjs/data/pull/9468) feat: string utils 🌌 ([@runspired](https://github.com/runspired))
-* [#9466](https://github.com/emberjs/data/pull/9466) feat: make @id editable and reactive ([@runspired](https://github.com/runspired))
-* [#9465](https://github.com/emberjs/data/pull/9465) feat: implement edit & create cases for legacy relationships ([@runspired](https://github.com/runspired))
-* [#9464](https://github.com/emberjs/data/pull/9464) feat: implement support for legacy hasMany and belongsTo relationship reads ([@runspired](https://github.com/runspired))
-* [#9407](https://github.com/emberjs/data/pull/9407) feat: v2 addons ([@runspired](https://github.com/runspired))
-* [#9453](https://github.com/emberjs/data/pull/9453) feat: update SchemaService to reflect RFC updates ([@runspired](https://github.com/runspired))
-* [#9448](https://github.com/emberjs/data/pull/9448) feat: impl SchemaService RFC ([@runspired](https://github.com/runspired))
-* [#9450](https://github.com/emberjs/data/pull/9450) feat: improve typing around Model and createRecord ([@runspired](https://github.com/runspired))
-* [#9444](https://github.com/emberjs/data/pull/9444) feat: rename LifetimesService => CachePolicy for clarity ([@runspired](https://github.com/runspired))
-* [#9443](https://github.com/emberjs/data/pull/9443) feat: universal consts ([@runspired](https://github.com/runspired))
-* [#9396](https://github.com/emberjs/data/pull/9396) fix: Resolve promise types for props passed to `store.createRecord()` ([@seanCodes](https://github.com/seanCodes))
-* [#9401](https://github.com/emberjs/data/pull/9401) feat: preserve lids returned by the API in legacy normalization ([@runspired](https://github.com/runspired))
-* [#9400](https://github.com/emberjs/data/pull/9400) feat: add expectId util ([@runspired](https://github.com/runspired))
-* [#9343](https://github.com/emberjs/data/pull/9343) @ember-data/codemods package ([@gitKrystan](https://github.com/gitKrystan))
-* [#9387](https://github.com/emberjs/data/pull/9387) feat: better types for legacy store methods ([@runspired](https://github.com/runspired))
-* [#8957](https://github.com/emberjs/data/pull/8957) feat(private): schema CLI ([@runspired](https://github.com/runspired))
-* [#9366](https://github.com/emberjs/data/pull/9366) feat: typed Model ([@runspired](https://github.com/runspired))
-* [#9363](https://github.com/emberjs/data/pull/9363) feat: autoRefresh ([@runspired](https://github.com/runspired))
-* [#9359](https://github.com/emberjs/data/pull/9359) feat: type checked builders and inferred request types from builders ([@runspired](https://github.com/runspired))
-* [#9353](https://github.com/emberjs/data/pull/9353) feat: utilies for migrating to stricter type and id usage ([@runspired](https://github.com/runspired))
-* [#9352](https://github.com/emberjs/data/pull/9352) feat: make setKeyInfoForResource public ([@runspired](https://github.com/runspired))
-* [#9277](https://github.com/emberjs/data/pull/9277) feat: implement managed object for schemaRecord ([@richgt](https://github.com/richgt))
-* [#9319](https://github.com/emberjs/data/pull/9319) Add @ember-data/legacy-compat/builders ([@gitKrystan](https://github.com/gitKrystan))
-* [#9314](https://github.com/emberjs/data/pull/9314) feat: improve lifetime handling of ad-hoc createRecord requests ([@runspired](https://github.com/runspired))
-* [#9317](https://github.com/emberjs/data/pull/9317) feat: ensure data utils work well with legacy relationship proxies ([@runspired](https://github.com/runspired))
-* [#9260](https://github.com/emberjs/data/pull/9260) feat: ember specific data utils ([@runspired](https://github.com/runspired))
-* [#9240](https://github.com/emberjs/data/pull/9240) feat: implement managed array for schemaRecord ([@richgt](https://github.com/richgt))
-* [#9256](https://github.com/emberjs/data/pull/9256) feat: improve alpha types support ([@runspired](https://github.com/runspired))
-* [#9250](https://github.com/emberjs/data/pull/9250) feat: fix types for legacy decorator syntax ([@runspired](https://github.com/runspired))
-* [#9249](https://github.com/emberjs/data/pull/9249) chore: handle declare statements in module rewriting ([@runspired](https://github.com/runspired))
-* [#9248](https://github.com/emberjs/data/pull/9248) feat: publish types as module defs ([@runspired](https://github.com/runspired))
-* [#9245](https://github.com/emberjs/data/pull/9245) feat: add consumer types for Model APIs ([@runspired](https://github.com/runspired))
-* [#9246](https://github.com/emberjs/data/pull/9246) normalization in json-api serializer preserves lid #7956 ([@sly7-7](https://github.com/sly7-7))
-* [#9244](https://github.com/emberjs/data/pull/9244) feat: improves consumer-facing store types ([@runspired](https://github.com/runspired))
-
-#### :bug: Bug Fix
-
-* [#9475](https://github.com/emberjs/data/pull/9475) fix: dont install optional peers if not already present ([@runspired](https://github.com/runspired))
-* [#9469](https://github.com/emberjs/data/pull/9469) Fix exports for 'ember-data' ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
-* [#9459](https://github.com/emberjs/data/pull/9459) fix: ensure cachehandler responses are cast to documents ([@runspired](https://github.com/runspired))
-* [#9456](https://github.com/emberjs/data/pull/9456) fix: visibilitychange => hidden should update unavailableStart ([@runspired](https://github.com/runspired))
-* [#9454](https://github.com/emberjs/data/pull/9454) Allow RequestState.abort to be used with on modifier ([@gitKrystan](https://github.com/gitKrystan))
-* [#9455](https://github.com/emberjs/data/pull/9455) fix: config version lookup needs to be project location aware ([@runspired](https://github.com/runspired))
-* [#9355](https://github.com/emberjs/data/pull/9355) Fix: @attr defaultValue() results should persist after initialization ([@christophersansone](https://github.com/christophersansone))
-* [#9391](https://github.com/emberjs/data/pull/9391) fix: dont fall-through after shouldAttempt on refresh ([@runspired](https://github.com/runspired))
-* [#9383](https://github.com/emberjs/data/pull/9383) fix: ensure cache-handler clones full errors ([@runspired](https://github.com/runspired))
-* [#9369](https://github.com/emberjs/data/pull/9369) fix: @warp-drive-ember, dont leak empty slot ([@runspired](https://github.com/runspired))
-* [#9364](https://github.com/emberjs/data/pull/9364) fix: restore old behavior in deprecation ([@enspandi](https://github.com/enspandi))
-* [#9360](https://github.com/emberjs/data/pull/9360) fix: Make IS_MAYBE_MIRAGE work in Firefox ([@MichalBryxi](https://github.com/MichalBryxi))
-* [#9318](https://github.com/emberjs/data/pull/9318) fix: be more specific in files in case .npmignore is ignored ([@runspired](https://github.com/runspired))
-* [#9307](https://github.com/emberjs/data/pull/9307) fix: mirage does not support anything ([@runspired](https://github.com/runspired))
-* [#9265](https://github.com/emberjs/data/pull/9265) feat: Improve config handling for polyfillUUID ([@MehulKChaudhari](https://github.com/MehulKChaudhari))
-* [#9263](https://github.com/emberjs/data/pull/9263) fix: set localState to latest identifier in belongsTo when merging identifiers ([@runspired](https://github.com/runspired))
-* [#9254](https://github.com/emberjs/data/pull/9254) Update IS_MAYBE_MIRAGE function to check for Mirage in development mode ([@Baltazore](https://github.com/Baltazore))
-* [#9257](https://github.com/emberjs/data/pull/9257) fix: use npm pack instead of pnpm pack to respect .npmignore rules ([@runspired](https://github.com/runspired))
-* [#9252](https://github.com/emberjs/data/pull/9252) fix: update line when removing declare statements ([@runspired](https://github.com/runspired))
-* [#9251](https://github.com/emberjs/data/pull/9251) fix: notify during replace if existing localState never previously calculated ([@runspired](https://github.com/runspired))
-
-#### :house: Internal
-
-* [#9477](https://github.com/emberjs/data/pull/9477) fix: add deprecation and avoid breaking configs ([@runspired](https://github.com/runspired))
-* [#9476](https://github.com/emberjs/data/pull/9476) chore: cleanup symbol usage ([@runspired](https://github.com/runspired))
-* [#9463](https://github.com/emberjs/data/pull/9463) types: ManyArray => HasMany ([@runspired](https://github.com/runspired))
-* [#9457](https://github.com/emberjs/data/pull/9457) feat: the big list of versions ([@runspired](https://github.com/runspired))
-* [#9292](https://github.com/emberjs/data/pull/9292) feat: add new build-config package ([@runspired](https://github.com/runspired))
-* [#9399](https://github.com/emberjs/data/pull/9399) types: limit traversal depth on include path generation ([@runspired](https://github.com/runspired))
-* [#9398](https://github.com/emberjs/data/pull/9398) chore: dont --compile during prepack ([@runspired](https://github.com/runspired))
-* [#9397](https://github.com/emberjs/data/pull/9397) chore: fixup publish for @ember-data/codemods ([@runspired](https://github.com/runspired))
-* [#9395](https://github.com/emberjs/data/pull/9395) Update strategy.json to mirror publish @warp-drive/schema-record ([@runspired](https://github.com/runspired))
-* [#9385](https://github.com/emberjs/data/pull/9385) fix: Make IS_MAYBE_MIRAGE simplified ([@MichalBryxi](https://github.com/MichalBryxi))
-* [#9392](https://github.com/emberjs/data/pull/9392) Fix some typos after reading code ([@Baltazore](https://github.com/Baltazore))
-* [#9370](https://github.com/emberjs/data/pull/9370) chore: rename macros ([@runspired](https://github.com/runspired))
-* [#9368](https://github.com/emberjs/data/pull/9368) docs: Update ISSUE_TEMPLATE.md to follow latest pnpm ([@MichalBryxi](https://github.com/MichalBryxi))
-* [#9365](https://github.com/emberjs/data/pull/9365) chore: remove unneeded infra tests ([@runspired](https://github.com/runspired))
-* [#9349](https://github.com/emberjs/data/pull/9349) chore: fix CI installs ([@runspired](https://github.com/runspired))
-* [#9330](https://github.com/emberjs/data/pull/9330) chore: ensure latest tag is canary/beta tag for early stage packages ([@runspired](https://github.com/runspired))
-* [#9303](https://github.com/emberjs/data/pull/9303) infra: setup mirror and types publishing ([@runspired](https://github.com/runspired))
-* [#9291](https://github.com/emberjs/data/pull/9291) chore: remove unused scripts ([@runspired](https://github.com/runspired))
-* [#9289](https://github.com/emberjs/data/pull/9289) chore: bump timeout for floating dep check in CI ([@runspired](https://github.com/runspired))
-* [#9287](https://github.com/emberjs/data/pull/9287) chore: bump deps for example-api app ([@runspired](https://github.com/runspired))
-* [#9279](https://github.com/emberjs/data/pull/9279) types: branded transforms and improve types needed for serializers ([@runspired](https://github.com/runspired))
-* [#9280](https://github.com/emberjs/data/pull/9280) chore: handle dynamic imports with relative paths ([@runspired](https://github.com/runspired))
-* [#9259](https://github.com/emberjs/data/pull/9259) Update setting-up-the-project.md ([@MehulKChaudhari](https://github.com/MehulKChaudhari))
-* [#9258](https://github.com/emberjs/data/pull/9258) fix: remove unused turbo key ([@runspired](https://github.com/runspired))
-
-#### Committers: (13)
-
-Chris Thoburn ([@runspired](https://github.com/runspired))
-Kirill Shaplyko ([@Baltazore](https://github.com/Baltazore))
-Michal Bryxí ([@MichalBryxi](https://github.com/MichalBryxi))
-Peter Wagenet ([@wagenet](https://github.com/wagenet))
-Sylvain Mina ([@sly7-7](https://github.com/sly7-7))
-Yelin Zhang ([@Yelinz](https://github.com/Yelinz))
-Krystan HuffMenne ([@gitKrystan](https://github.com/gitKrystan))
-Rich Glazerman ([@richgt](https://github.com/richgt))
-Sean Juarez ([@seanCodes](https://github.com/seanCodes))
-[@NullVoxPopuli](https://github.com/NullVoxPopuli)
-Christopher Sansone ([@christophersansone](https://github.com/christophersansone))
-Andreas Minnich ([@enspandi](https://github.com/enspandi))
-Mehul Kiran Chaudhari ([@MehulKChaudhari](https://github.com/MehulKChaudhari))
-
-## v5.3.3 (2024-03-02)
-
-#### :bug: Bug Fix
-
-* [#9243](https://github.com/emberjs/data/pull/9243) fix: keep core-type peer-deps ([@runspired](https://github.com/runspired))
-
-#### Committers: (1)
-
-Chris Thoburn ([@runspired](https://github.com/runspired))
-
-## v5.3.2 (2024-02-29)
-
-#### :house: Internal
-
-* [#9241](https://github.com/emberjs/data/pull/9241) chore: manually run prepack ([@runspired](https://github.com/runspired))
-* [#9238](https://github.com/emberjs/data/pull/9238) chore: better "from" version default value population ([@runspired](https://github.com/runspired))
-* [#9237](https://github.com/emberjs/data/pull/9237) chore: fix publishing of core-types when strategy is private ([@runspired](https://github.com/runspired))
-
-#### Committers: (1)
-
-Chris Thoburn ([@runspired](https://github.com/runspired))
-
-## v5.3.1 (2024-02-24)
-
-#### :evergreen_tree: New Deprecation
-
-* [#9189](https://github.com/emberjs/data/pull/9189) fix: mutating ManyArray should handle duplicates gracefully (with deprecation) ([@gitKrystan](https://github.com/gitKrystan))
-
-#### :memo: Documentation
-
-* [#9132](https://github.com/emberjs/data/pull/9132) Add auth handler guides ([@Baltazore](https://github.com/Baltazore))
-* [#9071](https://github.com/emberjs/data/pull/9071) chore: refactor relationships guide ([@runspired](https://github.com/runspired))
-* [#9059](https://github.com/emberjs/data/pull/9059) docs: The comprehensive guide to relationships ([@runspired](https://github.com/runspired))
-* [#9018](https://github.com/emberjs/data/pull/9018) doc(README): remove typo ([@omimakhare](https://github.com/omimakhare))
-* [#8966](https://github.com/emberjs/data/pull/8966) feat: Add links to the CODE_OF_CONDUCT.md ([@Agnik7](https://github.com/Agnik7))
-* [#8963](https://github.com/emberjs/data/pull/8963) chore: scaffold additional contributing materials ([@runspired](https://github.com/runspired))
-* [#9162](https://github.com/emberjs/data/pull/9162) feat: improve store.request documentation ([@runspired](https://github.com/runspired))
-* [#9161](https://github.com/emberjs/data/pull/9161) docs: fix return signature of peekRequest ([@runspired](https://github.com/runspired))
-* [#9159](https://github.com/emberjs/data/pull/9159) fix: support full range of json:api for references, update docs ([@runspired](https://github.com/runspired))
-* [#9160](https://github.com/emberjs/data/pull/9160) docs: update links ([@runspired](https://github.com/runspired))
-* [#8954](https://github.com/emberjs/data/pull/8954) docs: typo in hasChangedRelationships description ([@BoussonKarel](https://github.com/BoussonKarel))
-* [#9072](https://github.com/emberjs/data/pull/9072) feat: advanced JSON:API queries & basic request example ([@runspired](https://github.com/runspired))
-* [#9070](https://github.com/emberjs/data/pull/9070) docs: fix note notation to make use of github formatting ([@runspired](https://github.com/runspired))
-* [#9068](https://github.com/emberjs/data/pull/9068) docs: unroll details sections ([@runspired](https://github.com/runspired))
-
-#### :rocket: Enhancement
-
-* [#9220](https://github.com/emberjs/data/pull/9220) feat: request infra improvements ([@runspired](https://github.com/runspired))
-* [#9163](https://github.com/emberjs/data/pull/9163) feat: improved lifetimes-service capabilities ([@runspired](https://github.com/runspired))
-* [#9159](https://github.com/emberjs/data/pull/9159) fix: support full range of json:api for references, update docs ([@runspired](https://github.com/runspired))
-* [#9094](https://github.com/emberjs/data/pull/9094) feat: support legacy attribute behaviors in SchemaRecord ([@gitKrystan](https://github.com/gitKrystan))
-* [#9095](https://github.com/emberjs/data/pull/9095) feat (internal): support legacy model behaviors in SchemaRecord legacy mode ([@runspired](https://github.com/runspired))
-* [#9072](https://github.com/emberjs/data/pull/9072) feat: advanced JSON:API queries & basic request example ([@runspired](https://github.com/runspired))
-* [#9069](https://github.com/emberjs/data/pull/9069) feat: Improve extensibility ([@runspired](https://github.com/runspired))
-* [#8955](https://github.com/emberjs/data/pull/8955) feat(private): scaffold packages for schema parser ([@runspired](https://github.com/runspired))
-* [#8949](https://github.com/emberjs/data/pull/8949) feat:prepare for universal reactivity ([@runspired](https://github.com/runspired))
-* [#8948](https://github.com/emberjs/data/pull/8948) feat(private): reactive simple fields ([@runspired](https://github.com/runspired))
-* [#8946](https://github.com/emberjs/data/pull/8946) feat (private): implement resource relationships for SchemaRecord ([@runspired](https://github.com/runspired))
-* [#8939](https://github.com/emberjs/data/pull/8939) feat (private): implement support for derivations in schema-record ([@runspired](https://github.com/runspired))
-* [#8935](https://github.com/emberjs/data/pull/8935) feat: (private) implement basic field support for schema-record ([@runspired](https://github.com/runspired))
-* [#8925](https://github.com/emberjs/data/pull/8925) feat: implement postQuery builder ([@runspired](https://github.com/runspired))
-* [#8921](https://github.com/emberjs/data/pull/8921) feat: Improved Fetch Errors ([@runspired](https://github.com/runspired))
-
-#### :bug: Bug Fix
-
-* [#9221](https://github.com/emberjs/data/pull/9221) fix: prevent rollbackRelationships from setting remoteState and localState to the same array reference ([@runspired](https://github.com/runspired))
-* [#9203](https://github.com/emberjs/data/pull/9203) fix: Fetch handler hacks for Mirage (canary) ([@gitKrystan](https://github.com/gitKrystan))
-* [#9189](https://github.com/emberjs/data/pull/9189) fix: mutating ManyArray should handle duplicates gracefully (with deprecation) ([@gitKrystan](https://github.com/gitKrystan))
-* [#9183](https://github.com/emberjs/data/pull/9183) fix: keep a backreference for previously merged identifiers ([@runspired](https://github.com/runspired))
-* [#8927](https://github.com/emberjs/data/pull/8927) fix: live-array delete sync should not clear the set on length match ([@runspired](https://github.com/runspired))
-* [#9164](https://github.com/emberjs/data/pull/9164) fix: url configuration should respect / for host and error more meaningfully when invalid ([@runspired](https://github.com/runspired))
-* [#9159](https://github.com/emberjs/data/pull/9159) fix: support full range of json:api for references, update docs ([@runspired](https://github.com/runspired))
-* [#9097](https://github.com/emberjs/data/pull/9097) fix: allow decorator syntax in code comments during yui doc processing ([@jaredgalanis](https://github.com/jaredgalanis))
-* [#9014](https://github.com/emberjs/data/pull/9014) fix: make willCommit slightly safer when race conditions occur ([@runspired](https://github.com/runspired))
-* [#8934](https://github.com/emberjs/data/pull/8934) fix: JSONAPISerializer should not reify empty records ([@runspired](https://github.com/runspired))
-* [#8892](https://github.com/emberjs/data/pull/8892) doc: Fix paths in transform deprecations ([@HeroicEric](https://github.com/HeroicEric))
-
-#### :house: Internal
-
-* [#9125](https://github.com/emberjs/data/pull/9125) Configure ESLint for test packages ([@gitKrystan](https://github.com/gitKrystan))
-* [#8994](https://github.com/emberjs/data/pull/8994) chore: fix recursive pnpm on node 18.18 ([@runspired](https://github.com/runspired))
-* [#9110](https://github.com/emberjs/data/pull/9110) Stricter typescript-eslint config ([@gitKrystan](https://github.com/gitKrystan))
-* [#9101](https://github.com/emberjs/data/pull/9101) chore: Type check test files ([@gitKrystan](https://github.com/gitKrystan))
-* [#9093](https://github.com/emberjs/data/pull/9093) feat(internal): implement legacy mode toggle ([@runspired](https://github.com/runspired))
-* [#9085](https://github.com/emberjs/data/pull/9085) Add type-checking to tests/warp-drive__schema-record ([@gitKrystan](https://github.com/gitKrystan))
-* [#9089](https://github.com/emberjs/data/pull/9089) Add type-checking for packages/unpublished-test-infra ([@gitKrystan](https://github.com/gitKrystan))
-* [#9009](https://github.com/emberjs/data/pull/9009) chore(internal) add @warp-drive/diagnostic/ember ([@runspired](https://github.com/runspired))
-* [#9007](https://github.com/emberjs/data/pull/9007) chore(internal): convert model and adapter tests to use diagnostic ([@runspired](https://github.com/runspired))
-* [#8967](https://github.com/emberjs/data/pull/8967) chore(private): implements a QUnit alternative ([@runspired](https://github.com/runspired))
-* [#9086](https://github.com/emberjs/data/pull/9086) Add ESLint config for tests/warp-drive__schema-record ([@gitKrystan](https://github.com/gitKrystan))
-* [#9078](https://github.com/emberjs/data/pull/9078) docs: add compatibility table to readme ([@runspired](https://github.com/runspired))
-* [#9054](https://github.com/emberjs/data/pull/9054) Initial lint config for tests/blueprints ([@gitKrystan](https://github.com/gitKrystan))
-* [#9061](https://github.com/emberjs/data/pull/9061) Git-ignore .prettier-cache ([@gitKrystan](https://github.com/gitKrystan))
-* [#8993](https://github.com/emberjs/data/pull/8993) chore: fix development test command ([@runspired](https://github.com/runspired))
-* [#8986](https://github.com/emberjs/data/pull/8986) chore: rename schema tests to warp-drive__* variants ([@runspired](https://github.com/runspired))
-* [#8984](https://github.com/emberjs/data/pull/8984) chore: remove unneeded debug-encapsulation tests ([@runspired](https://github.com/runspired))
-* [#8983](https://github.com/emberjs/data/pull/8983) chore: rename request-test-app to ember-data__request ([@runspired](https://github.com/runspired))
-* [#8982](https://github.com/emberjs/data/pull/8982) chore: rename json-api-test-app to ember-data__json-api ([@runspired](https://github.com/runspired))
-* [#8981](https://github.com/emberjs/data/pull/8981) chore: rename adapter-encapsulation-test-app to ember-data__adapter ([@runspired](https://github.com/runspired))
-* [#8980](https://github.com/emberjs/data/pull/8980) chore: rename graph-test-app to ember-data__graph ([@runspired](https://github.com/runspired))
-* [#8979](https://github.com/emberjs/data/pull/8979) chore: rename serializer-encapsulation tests, remove smoke-test ([@runspired](https://github.com/runspired))
-* [#8978](https://github.com/emberjs/data/pull/8978) chore: rename model-encapsulation tests, remove smoke-test ([@runspired](https://github.com/runspired))
-* [#8974](https://github.com/emberjs/data/pull/8974) chore: remove uneeded json-api-encapsulation test app ([@runspired](https://github.com/runspired))
-* [#8960](https://github.com/emberjs/data/pull/8960) internal: fix test settledness ([@runspired](https://github.com/runspired))
-* [#9084](https://github.com/emberjs/data/pull/9084) Add import types ([@gitKrystan](https://github.com/gitKrystan))
-* [#8989](https://github.com/emberjs/data/pull/8989) chore(private): concurrent mode ([@runspired](https://github.com/runspired))
-* [#9082](https://github.com/emberjs/data/pull/9082) Remove remaining @types/ember* packages ([@gitKrystan](https://github.com/gitKrystan))
-* [#8961](https://github.com/emberjs/data/pull/8961) chore: run tests nicely ([@runspired](https://github.com/runspired))
-* [#9062](https://github.com/emberjs/data/pull/9062) Extract qunit ESLint config ([@gitKrystan](https://github.com/gitKrystan))
-* [#9058](https://github.com/emberjs/data/pull/9058) Switch from eslint-plugin-prettier to running prettier directly ([@gitKrystan](https://github.com/gitKrystan))
-* [#9057](https://github.com/emberjs/data/pull/9057) Add eslint-plugin-n to eslint config for node files ([@gitKrystan](https://github.com/gitKrystan))
-* [#9055](https://github.com/emberjs/data/pull/9055) Fix ESLint for VSCode ([@gitKrystan](https://github.com/gitKrystan))
-* [#9051](https://github.com/emberjs/data/pull/9051) chore: use references for tsc, add checks to schema-record, bun to run scripts ([@runspired](https://github.com/runspired))
-* [#9032](https://github.com/emberjs/data/pull/9032) chore(types): split out lint and type commands to be per-package ([@runspired](https://github.com/runspired))
-* [#9050](https://github.com/emberjs/data/pull/9050) chore: use composite mode for tsc ([@runspired](https://github.com/runspired))
-* [#9049](https://github.com/emberjs/data/pull/9049) chore: incremental tsc builds ([@runspired](https://github.com/runspired))
-* [#9046](https://github.com/emberjs/data/pull/9046) chore: reduce number of things turbo builds for build ([@runspired](https://github.com/runspired))
-* [#9027](https://github.com/emberjs/data/pull/9027) chore: improve types for store package ([@runspired](https://github.com/runspired))
-* [#9029](https://github.com/emberjs/data/pull/9029) chore: add @warp-drive/core as home for shared code ([@runspired](https://github.com/runspired))
-* [#9028](https://github.com/emberjs/data/pull/9028) chore: more isolated types ([@runspired](https://github.com/runspired))
-* [#9025](https://github.com/emberjs/data/pull/9025) chore: reconfigure request package type location ([@runspired](https://github.com/runspired))
-* [#9024](https://github.com/emberjs/data/pull/9024) chore: cleanup more types ([@runspired](https://github.com/runspired))
-* [#9021](https://github.com/emberjs/data/pull/9021) chore: cleanup ember-data/-private types ([@runspired](https://github.com/runspired))
-* [#9019](https://github.com/emberjs/data/pull/9019) chore: make model types strict ([@runspired](https://github.com/runspired))
-* [#9017](https://github.com/emberjs/data/pull/9017) chore: make json-api cache strict ([@runspired](https://github.com/runspired))
-* [#9016](https://github.com/emberjs/data/pull/9016) chore: make type-only files strict ([@runspired](https://github.com/runspired))
-* [#9008](https://github.com/emberjs/data/pull/9008) chore: update eslint plugin name ([@runspired](https://github.com/runspired))
-* [#9006](https://github.com/emberjs/data/pull/9006) chore (internal): convert builder and request tests to use diagnostic+runner ([@runspired](https://github.com/runspired))
-* [#9000](https://github.com/emberjs/data/pull/9000) feat(private): native test runner ([@runspired](https://github.com/runspired))
-* [#8995](https://github.com/emberjs/data/pull/8995) chore: add @warp-drive/diagnostic docs ([@runspired](https://github.com/runspired))
-* [#8987](https://github.com/emberjs/data/pull/8987) chore: test-harness improvements ([@runspired](https://github.com/runspired))
-* [#8972](https://github.com/emberjs/data/pull/8972) chore: use new test runner for request tests ([@runspired](https://github.com/runspired))
-* [#8931](https://github.com/emberjs/data/pull/8931) chore: package infra for schema-record ([@runspired](https://github.com/runspired))
-* [#8930](https://github.com/emberjs/data/pull/8930) chore: get last request for any record on instantiation ([@runspired](https://github.com/runspired))
-* [#8923](https://github.com/emberjs/data/pull/8923) chore: prepare files for new eslint plugin ([@runspired](https://github.com/runspired))
-* [#8911](https://github.com/emberjs/data/pull/8911) chore: remove unneeded type cast ([@runspired](https://github.com/runspired))
-* [#8912](https://github.com/emberjs/data/pull/8912) chore: docs for holodeck ([@runspired](https://github.com/runspired))
-* [#8906](https://github.com/emberjs/data/pull/8906) feat: expand mock-server capabilities, add to main tests ([@runspired](https://github.com/runspired))
-
-#### Committers: (8)
-
-Krystan HuffMenne ([@gitKrystan](https://github.com/gitKrystan))
-Kirill Shaplyko ([@Baltazore](https://github.com/Baltazore))
-Chris Thoburn ([@runspired](https://github.com/runspired))
-OMKAR MAKHARE ([@omimakhare](https://github.com/omimakhare))
-Agnik Bakshi ([@Agnik7](https://github.com/Agnik7))
-[@BoussonKarel](https://github.com/BoussonKarel)
-Jared Galanis ([@jaredgalanis](https://github.com/jaredgalanis))
-Eric Kelly ([@HeroicEric](https://github.com/HeroicEric))
-
-## v5.3.0 (2023-09-18)
-
-#### :rocket: Enhancement
- * [#8849](https://github.com/emberjs/data/pull/8849) feat: docs, tests and fixes for create/update/deleteRecord builders ([@Baltazore](https://github.com/Baltazore))
- * [#8824](https://github.com/emberjs/data/pull/8824) feat: relationshipRollback, serializePatch ([@runspired](https://github.com/runspired))
- * [#8798](https://github.com/emberjs/data/pull/8798) feat: implement a simple LifetimeService utility, improve document reconstruction ([@runspired](https://github.com/runspired))
- * [#8741](https://github.com/emberjs/data/pull/8741) feat: JSON:API serialization utils ([@runspired](https://github.com/runspired))
- * [#8740](https://github.com/emberjs/data/pull/8740) feat: saveRecord builders ([@runspired](https://github.com/runspired))
- * [#8744](https://github.com/emberjs/data/pull/8744) add sortQueryParams, update roadmap with link to checklist ([@runspired](https://github.com/runspired))
- * [#8716](https://github.com/emberjs/data/pull/8716) feat: filterEmpty for query params ([@runspired](https://github.com/runspired))
- * [#8687](https://github.com/emberjs/data/pull/8687) feat: findRecord and query request builders ([@runspired](https://github.com/runspired))
- * [#8673](https://github.com/emberjs/data/pull/8673) DX: Nicer backtracking errors ([@runspired](https://github.com/runspired))
- * [#8736](https://github.com/emberjs/data/pull/8736) chore: refactor IdentityCache to make resource more opaque ([@runspired](https://github.com/runspired))
-
-#### :bug: Bug Fix
- * [#8876](https://github.com/emberjs/data/pull/8876) fix: Fetch handler should account for empty body ([@runspired](https://github.com/runspired))
- * [#8842](https://github.com/emberjs/data/pull/8842) fix: handle Immutable Response objects ([@runspired](https://github.com/runspired))
- * [#8828](https://github.com/emberjs/data/pull/8828) fix: set headers after setResponse in Fetch handler ([@runspired](https://github.com/runspired))
- * [#8850](https://github.com/emberjs/data/pull/8850) Overwrite addMixin ([@patricklx](https://github.com/patricklx))
- * [#8831](https://github.com/emberjs/data/pull/8831) fix: cleanup build deps and add @ember/string to REST/ActiveRecord builder peer-deps ([@runspired](https://github.com/runspired))
- * [#8826](https://github.com/emberjs/data/pull/8826) fix createRecord error when no adapter is present ([@runspired](https://github.com/runspired))
- * [#8791](https://github.com/emberjs/data/pull/8791) fix: clear relationships properly when unloading new records ([@Windvis](https://github.com/Windvis))
- * [#8794](https://github.com/emberjs/data/pull/8794) Fix check for new records in JSONAPISerializer.serializeHasMany ([@dagroe](https://github.com/dagroe))
- * [#8751](https://github.com/emberjs/data/pull/8751) Forward fixes from 3.12.x into main ([@jrjohnson](https://github.com/jrjohnson))
- * [#8684](https://github.com/emberjs/data/pull/8684) fix: unloadAll(void) should not destroy the notification manager ([@runspired](https://github.com/runspired))
-
-#### :evergreen_tree: New Deprecation
- * [#8747](https://github.com/emberjs/data/pull/8747) feat: implement legacy imports deprecation ([@runspired](https://github.com/runspired))
- * [#8734](https://github.com/emberjs/data/pull/8734) feat: Implement Strict Types and Id Deprecations ([@runspired](https://github.com/runspired))
-
-#### :shower: Deprecation Removal
-* `adapter`, `model`, `private-build-infra`, `serializer`
- * [#8797](https://github.com/emberjs/data/pull/8797) Drop support for `ember-cli-mocha` and `ember-mocha` when generating test blueprints ([@bertdeblock](https://github.com/bertdeblock))
-
-#### :memo: Documentation
- * [#8848](https://github.com/emberjs/data/pull/8848) feat: add request options documentation parts to find-record builder ([@Baltazore](https://github.com/Baltazore))
- * [#8825](https://github.com/emberjs/data/pull/8825) feat: more docs for builders ([@runspired](https://github.com/runspired))
- * [#8819](https://github.com/emberjs/data/pull/8819) fix: `JSONAPISerializer.shouldSerializeHasMany` relation param type ([@samridhivig](https://github.com/samridhivig))
- * [#8746](https://github.com/emberjs/data/pull/8746) docs: more documentation for builders ([@runspired](https://github.com/runspired))
- * [#8745](https://github.com/emberjs/data/pull/8745) chore: readme overviews for builders ([@runspired](https://github.com/runspired))
- * [#8724](https://github.com/emberjs/data/pull/8724) chore: rename CacheStoreWrapper => CacheCapabilitiesManager to reflect its role ([@runspired](https://github.com/runspired))
- * [#8671](https://github.com/emberjs/data/pull/8671) Typo correction in ROADMAP.md ([@wagenet](https://github.com/wagenet))
-
-#### :goal_net: Test
- * [#8878](https://github.com/emberjs/data/pull/8878) test: add basic test for Fetch handler ([@runspired](https://github.com/runspired))
- * [#8849](https://github.com/emberjs/data/pull/8849) feat: docs, tests and fixes for create/update/deleteRecord builders ([@Baltazore](https://github.com/Baltazore))
- * [#8868](https://github.com/emberjs/data/pull/8868) Add tests for filter-empty request util ([@Baltazore](https://github.com/Baltazore))
- * [#8866](https://github.com/emberjs/data/pull/8866) Add tests for parse-cache-control ([@Baltazore](https://github.com/Baltazore))
- * [#8864](https://github.com/emberjs/data/pull/8864) test: confirm records unload properly for #8863 ([@runspired](https://github.com/runspired))
- * [#8780](https://github.com/emberjs/data/pull/8780) chore: add test to demonstrate create props work as expected ([@runspired](https://github.com/runspired))
-
-#### :house: Internal
- * [#8758](https://github.com/emberjs/data/pull/8758) chore: refactor implicit edge to match resource and collection pattern ([@runspired](https://github.com/runspired))
- * [#8755](https://github.com/emberjs/data/pull/8755) chore: simplify file structure in graph package ([@runspired](https://github.com/runspired))
- * [#8749](https://github.com/emberjs/data/pull/8749) fix: ensure we are not allowing embroider to do anything ([@runspired](https://github.com/runspired))
- * [#8672](https://github.com/emberjs/data/pull/8672) chore: update roadmap for 5.3 ([@runspired](https://github.com/runspired))
- * [#8670](https://github.com/emberjs/data/pull/8670) chore: add ROADMAP and update CONTRIBUTING ([@runspired](https://github.com/runspired))
- * [#8739](https://github.com/emberjs/data/pull/8739) chore: migrate store/graph to strict types config ([@runspired](https://github.com/runspired))
- * [#8733](https://github.com/emberjs/data/pull/8733) chore: improve types and lint ([@runspired](https://github.com/runspired))
- * [#8727](https://github.com/emberjs/data/pull/8727) chore: fix peers and get perf-test-app running again ([@runspired](https://github.com/runspired))
- * [#8717](https://github.com/emberjs/data/pull/8717) Switch from local and @types/ember types to ember-source types ([@BradBarnich](https://github.com/BradBarnich))
- * [#8499](https://github.com/emberjs/data/pull/8499) chore: refactor model hook support to live in the model package ([@runspired](https://github.com/runspired))
- * [#8862](https://github.com/emberjs/data/pull/8862) chore: remove more runloop usage | completely remove rsvp ([@runspired](https://github.com/runspired))
- * [#8861](https://github.com/emberjs/data/pull/8861) chore: remove runloop usage ([@runspired](https://github.com/runspired))
- * [#8859](https://github.com/emberjs/data/pull/8859) chore: update target labels ([@runspired](https://github.com/runspired))
- * [#8858](https://github.com/emberjs/data/pull/8858) chore: update required labels ([@runspired](https://github.com/runspired))
- * [#8830](https://github.com/emberjs/data/pull/8830) chore: cleanup actions/setup usage ([@runspired](https://github.com/runspired))
- * [#8812](https://github.com/emberjs/data/pull/8812) fix typo ([@samridhivig](https://github.com/samridhivig))
- * [#8802](https://github.com/emberjs/data/pull/8802) chore: fix fastboot-testing deprecation ([@runspired](https://github.com/runspired))
- * [#8801](https://github.com/emberjs/data/pull/8801) chore: resolve deprecation in fastboot app ([@runspired](https://github.com/runspired))
- * [#8860](https://github.com/emberjs/data/pull/8860) chore: burn down runloop and RSVP usage ([@runspired](https://github.com/runspired))
- * [#8832](https://github.com/emberjs/data/pull/8832) chore: add recommended JSON:API setup test app ([@runspired](https://github.com/runspired))
- * [#8829](https://github.com/emberjs/data/pull/8829) chore: eliminate dead build code ([@runspired](https://github.com/runspired))
- * [#8823](https://github.com/emberjs/data/pull/8823) fix: graph instantiation should not be required ([@runspired](https://github.com/runspired))
-
-#### Committers: 11
-- Bert De Block ([@bertdeblock](https://github.com/bertdeblock))
-- Chris Thoburn ([@runspired](https://github.com/runspired))
-- Daniel Gröger ([@dagroe](https://github.com/dagroe))
-- Kirill Shaplyko ([@Baltazore](https://github.com/Baltazore))
-- Patrick Pircher ([@patricklx](https://github.com/patricklx))
-- Sam Van Campenhout ([@Windvis](https://github.com/Windvis))
-- Samridhi Vig ([@samridhivig](https://github.com/samridhivig))
-- Brad Barnich ([@BradBarnich](https://github.com/BradBarnich))
-- Jon Johnson ([@jrjohnson](https://github.com/jrjohnson))
-- Michal Bryxí ([@MichalBryxi](https://github.com/MichalBryxi))
-- Peter Wagenet ([@wagenet](https://github.com/wagenet))
-
-## 5.2.0 (2023-08-17)
-
-* Re-release of 5.1.2 to keep lockstep pace. This release contains no new work.
-## 5.1.2 (2023-08-17)
-#### :bug: Bug Fix
-
-* [#8750](https://github.com/emberjs/data/pull/8750) Backport into release ([@jrjohnson](https://github.com/jrjohnson))
- * fix: @ember-data/debug should declare its peer-dependency on @ember-data/store #8703
- * fix: de-dupe coalescing when includes or adapterOptions is present but still use findRecord #8704
- * fix: make implicit relationship teardown following delete of related record safe #8705
- * fix: catch errors during didCommit in DEBUG #8708
-
-## 5.1.1 (2023-07-07)
-
-#### :bug: Bug Fix
- * [#8685](https://github.com/emberjs/data/pull/8685) fix: unloadAll(void) should not destroy the notification manager (backports #8684) ([@runspired](https://github.com/runspired))
-
-#### Committers: 1
-- Chris Thoburn ([@runspired](https://github.com/runspired))
-
-## 5.1.0 (2023-06-29)
-
-#### :bug: Bug Fix
- * [#8657](https://github.com/emberjs/data/pull/8657) fix: ensure deprecation configs are threaded to each package ([@runspired](https://github.com/runspired))
- * [#8649](https://github.com/emberjs/data/pull/8649) fix: NotificationManager should only invoke resource/document callbacks owned by the originating store ([@runspired](https://github.com/runspired))
-
-#### Committers: 1
-- Chris Thoburn ([@runspired](https://github.com/runspired))
-
-## 5.0.1 (2023-06-29)
-
-#### :bug: Bug Fix
- * [#8649](https://github.com/emberjs/data/pull/8649) fix: NotificationManager should only invoke resource/document callbacks owned by the originating store ([@runspired](https://github.com/runspired))
-
-#### Committers: 1
-- Chris Thoburn ([@runspired](https://github.com/runspired))
-
-## 5.0.0 (2023-06-10)
-
-#### :bug: Bug Fix
-* `adapter`
- * [#8621](https://github.com/emberjs/data/pull/8621) fix: normalizeErrorResponse should be resilient to non-string details ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
-* Other
- * [#8598](https://github.com/emberjs/data/pull/8598) fix: docs generation should maintain a stable relative path ([@runspired](https://github.com/runspired))
-* `json-api`, `legacy-compat`, `store`
- * [#8566](https://github.com/emberjs/data/pull/8566) Avoid unnecessary identity notification when record is saved ([@robbytx](https://github.com/robbytx))
-* `model`
- * [#8597](https://github.com/emberjs/data/pull/8597) fix: dont share promise cache for all fields ([@runspired](https://github.com/runspired))
-* `store`
- * [#8594](https://github.com/emberjs/data/pull/8594) fix: restore Store extends EmberObject :( ([@runspired](https://github.com/runspired))
- * [#8570](https://github.com/emberjs/data/pull/8570) Fix: don't clear RecordArray if remaining record does not match the removed record ([@esbanarango](https://github.com/esbanarango))
-* `graph`, `model`, `private-build-infra`
- * [#8555](https://github.com/emberjs/data/pull/8555) fix: fix polymorphic assertions when deprecated code is removed, improve polymorphic dx ([@runspired](https://github.com/runspired))
-
-#### :shower: Deprecation Removal
-* `-ember-data`, `adapter`, `debug`, `graph`, `json-api`, `legacy-compat`, `model`, `private-build-infra`, `store`, `unpublished-test-infra`
- * [#8550](https://github.com/emberjs/data/pull/8550) chore: remove 4.x deprecations ([@runspired](https://github.com/runspired))
-
-#### :memo: Documentation
-* `store`
- * [#8601](https://github.com/emberjs/data/pull/8601) docs: fix forgotten references to FetchManager ([@runspired](https://github.com/runspired))
-* Other
- * [#8598](https://github.com/emberjs/data/pull/8598) fix: docs generation should maintain a stable relative path ([@runspired](https://github.com/runspired))
-
-#### Committers: 4
-- Chris Thoburn ([@runspired](https://github.com/runspired))
-- Esteban ([@esbanarango](https://github.com/esbanarango))
-- Robby Morgan ([@robbytx](https://github.com/robbytx))
-- [@NullVoxPopuli](https://github.com/NullVoxPopuli)
+# Ember Data Changelog
## v4.12.8 (2024-05-08)
@@ -510,7 +71,7 @@ Eric Kelly ([@HeroicEric](https://github.com/HeroicEric))
#### Committers: 1
- Chris Thoburn ([@runspired](https://github.com/runspired))
-## LTS 4.12.2 (2023-07-07)
+## 4.12.2 (2023-07-07)
#### :rocket: Enhancement
* [#8660](https://github.com/emberjs/data/pull/8660) DX: Nicer backtracking errors ([@runspired](https://github.com/runspired))
@@ -521,7 +82,7 @@ Eric Kelly ([@HeroicEric](https://github.com/HeroicEric))
#### Committers: 1
- Chris Thoburn ([@runspired](https://github.com/runspired))
-## LTS 4.12.1 (2023-06-29)
+## 4.12.1 (2023-06-29)
#### :bug: Bug Fix
* [#8656](https://github.com/emberjs/data/pull/8656) fix: NotificationManager should only invoke resource/document callbacks owned by the originating store (#8649) ([@runspired](https://github.com/runspired))
@@ -533,6 +94,7 @@ Eric Kelly ([@HeroicEric](https://github.com/HeroicEric))
- Chris Thoburn ([@runspired](https://github.com/runspired))
- Esteban ([@esbanarango](https://github.com/esbanarango))
+
## 4.12.0 (2023-04-06)
#### :rocket: Enhancement
@@ -884,46 +446,6 @@ This is a re-release of 4.10.0
- [@law-rence](https://github.com/law-rence)
- Eugen Ciur ([@ciur](https://github.com/ciur))
-## v4.6.5 (2024-05-08)
-
-#### :bug: Bug Fix
-* [#9316](https://github.com/emberjs/data/pull/9316) Notify on length when notifying that many-array has changed
-
-#### Committers: 1
--
-Ross Grayton ([@grayt0r](https://github.com/grayt0r))
-
-
-## v4.6.4 (2022-10-02)
-
-#### :bug: Bug Fix
-* `private-build-infra`
- * [#8199](https://github.com/emberjs/data/pull/8199) [backport release-prev] fix: thread polyfillUUID config through nested deps ([@runspired](https://github.com/runspired))
-
-#### Committers: 1
-- Chris Thoburn ([@runspired](https://github.com/runspired))
-
-## v4.6.3 (2022-09-15)
-
-#### :bug: Bug Fix
-* `store`
- * fix: allow ManyArray being passed to createRecord
-
-## v4.6.2 (2022-09-15)
-
-#### :bug: Bug Fix
-* `store`
- * [#8169](https://github.com/emberjs/data/pull/8169) fix: uuid polyfill logic ([@jrjohnson](https://github.com/jrjohnson))
-* `-ember-data`, `model`
- * [#8148](https://github.com/emberjs/data/pull/8148) Clear subscriptions once unsubscribed, don't unnecessarily churn on subscriptions ([@jrjohnson](https://github.com/jrjohnson))
-* `private-build-infra`
- * [#8145](https://github.com/emberjs/data/pull/8145) fix earlier versions of node-14 (#8108) ([@jrjohnson](https://github.com/jrjohnson))
-* `private-build-infra`, `store`
- * [#8144](https://github.com/emberjs/data/pull/8144) Backport add optional polyfill (#8109) ([@jrjohnson](https://github.com/jrjohnson))
-
-#### Committers: 1
-- Jon Johnson ([@jrjohnson](https://github.com/jrjohnson))
-
## v4.6.1 (2022-07-28)
#### :bug: Bug Fix
@@ -1034,15 +556,6 @@ Ross Grayton ([@grayt0r](https://github.com/grayt0r))
- Cameron Dubas ([@camerondubas](https://github.com/camerondubas))
- Jen Weber ([@jenweber](https://github.com/jenweber))
-## v4.4.2 (2023-08-01)
-
-#### :bug: Bug Fix
-* `model`
- * [#8713](https://github.com/emberjs/data/pull/8713) Notify on length when notifying that many-array has changed ([@richgt](https://github.com/richgt))
-
-#### Committers: 1
-- Rich Glazerman ([@richgt](https://github.com/richgt))
-
## v4.1.0 (2021-12-30)
#### :house: Internal
@@ -3418,7 +2931,7 @@ The full API reference of `DS.Snapshot` can be found [here](https://api.emberjs.
- fetch() -> fetchById() in docs
- Run findHasMany inside an ED runloop
- Cleanup debug adapter test: Watching Records
-- Fixed didDelete event/callback not fired in uncommitted state
+- Fixed didDelete event/callback not fired in uncommited state
- Add main entry point for package.json.
- register the store as a service
- Warn when expected coalesced records are not found in the response
diff --git a/config/package.json b/config/package.json
index 1f04ca8e2bf..38efe8f7314 100644
--- a/config/package.json
+++ b/config/package.json
@@ -1,7 +1,7 @@
{
"name": "@warp-drive/internal-config",
"private": true,
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"type": "module",
"dependencies": {
"@babel/cli": "^7.24.5",
diff --git a/package.json b/package.json
index 6b001446895..e438083270f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "root",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"private": true,
"license": "MIT",
"repository": {
diff --git a/packages/-ember-data/app/adapters/-json-api.js b/packages/-ember-data/app/adapters/-json-api.js
new file mode 100644
index 00000000000..2cbb7cd7057
--- /dev/null
+++ b/packages/-ember-data/app/adapters/-json-api.js
@@ -0,0 +1 @@
+export { default } from '@ember-data/adapter/json-api';
diff --git a/packages/-ember-data/app/initializers/ember-data.js b/packages/-ember-data/app/initializers/ember-data.js
index 4c8e1d14e7b..a3dd9a3a6f5 100644
--- a/packages/-ember-data/app/initializers/ember-data.js
+++ b/packages/-ember-data/app/initializers/ember-data.js
@@ -1,12 +1,11 @@
-import '@ember-data/request-utils/deprecation-support';
+import 'ember-data';
+
+import setupContainer from 'ember-data/setup-container';
/*
This code initializes EmberData in an Ember application.
*/
export default {
name: 'ember-data',
- initialize(application) {
- application.registerOptionsForType('serializer', { singleton: false });
- application.registerOptionsForType('adapter', { singleton: false });
- },
+ initialize: setupContainer,
};
diff --git a/packages/-ember-data/app/instance-initializers/ember-data.js b/packages/-ember-data/app/instance-initializers/ember-data.js
new file mode 100644
index 00000000000..b48556a316c
--- /dev/null
+++ b/packages/-ember-data/app/instance-initializers/ember-data.js
@@ -0,0 +1,5 @@
+/* exists only for things that historically used "after" or "before" */
+export default {
+ name: 'ember-data',
+ initialize() {},
+};
diff --git a/packages/-ember-data/app/serializers/-default.js b/packages/-ember-data/app/serializers/-default.js
new file mode 100644
index 00000000000..d617bfb1824
--- /dev/null
+++ b/packages/-ember-data/app/serializers/-default.js
@@ -0,0 +1 @@
+export { default } from '@ember-data/serializer/json';
diff --git a/packages/-ember-data/app/serializers/-json-api.js b/packages/-ember-data/app/serializers/-json-api.js
new file mode 100644
index 00000000000..59723c5ab2a
--- /dev/null
+++ b/packages/-ember-data/app/serializers/-json-api.js
@@ -0,0 +1 @@
+export { default } from '@ember-data/serializer/json-api';
diff --git a/packages/-ember-data/app/serializers/-rest.js b/packages/-ember-data/app/serializers/-rest.js
new file mode 100644
index 00000000000..d6878ba3c3e
--- /dev/null
+++ b/packages/-ember-data/app/serializers/-rest.js
@@ -0,0 +1 @@
+export { default } from '@ember-data/serializer/rest';
diff --git a/packages/-ember-data/app/services/store.js b/packages/-ember-data/app/services/store.js
index 94f7019f584..043aebdc25a 100644
--- a/packages/-ember-data/app/services/store.js
+++ b/packages/-ember-data/app/services/store.js
@@ -1,10 +1,11 @@
import { deprecate } from '@ember/debug';
export { default } from 'ember-data/store';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
deprecate(
"You are relying on ember-data auto-magically installing the store service. Use `export { default } from 'ember-data/store';` in app/services/store.js instead",
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/app/transforms/boolean.js b/packages/-ember-data/app/transforms/boolean.js
index be707e054f2..764286175bc 100644
--- a/packages/-ember-data/app/transforms/boolean.js
+++ b/packages/-ember-data/app/transforms/boolean.js
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { BooleanTransform as default } from '@ember-data/serializer/transform';
deprecate(
"You are relying on ember-data auto-magically installing the BooleanTransform. Use `export { BooleanTransform as default } from '@ember-data/serializer/transform';` in app/transforms/boolean.js instead",
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/app/transforms/date.js b/packages/-ember-data/app/transforms/date.js
index 1ba53723825..187c01d2e40 100644
--- a/packages/-ember-data/app/transforms/date.js
+++ b/packages/-ember-data/app/transforms/date.js
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { DateTransform as default } from '@ember-data/serializer/transform';
deprecate(
"You are relying on ember-data auto-magically installing the DateTransform. Use `export { DateTransform as default } from '@ember-data/serializer/transform';` in app/transforms/date.js instead",
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/app/transforms/number.js b/packages/-ember-data/app/transforms/number.js
index e33eac7b1a4..c79ef0d21dd 100644
--- a/packages/-ember-data/app/transforms/number.js
+++ b/packages/-ember-data/app/transforms/number.js
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { NumberTransform as default } from '@ember-data/serializer/transform';
deprecate(
"You are relying on ember-data auto-magically installing the NumberTransform. Use `export { NumberTransform as default } from '@ember-data/serializer/transform';` in app/transforms/number.js instead",
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/app/transforms/string.js b/packages/-ember-data/app/transforms/string.js
index 95d95453178..929095af070 100644
--- a/packages/-ember-data/app/transforms/string.js
+++ b/packages/-ember-data/app/transforms/string.js
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { StringTransform as default } from '@ember-data/serializer/transform';
deprecate(
"You are relying on ember-data auto-magically installing the StringTransform. Use `export { StringTransform as default } from '@ember-data/serializer/transform';` in app/transforms/string.js instead",
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/package.json b/packages/-ember-data/package.json
index b31164fded4..77a99520768 100644
--- a/packages/-ember-data/package.json
+++ b/packages/-ember-data/package.json
@@ -1,6 +1,6 @@
{
"name": "ember-data",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"description": "The lightweight reactive data library for JavaScript applications",
"keywords": [
"ember-addon"
diff --git a/packages/-ember-data/src/-private/index.ts b/packages/-ember-data/src/-private/index.ts
index d677821855a..ef3ed492d25 100644
--- a/packages/-ember-data/src/-private/index.ts
+++ b/packages/-ember-data/src/-private/index.ts
@@ -4,15 +4,21 @@ import { deprecate } from '@ember/debug';
import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
import ObjectProxy from '@ember/object/proxy';
-deprecate('Importing from `ember-data/-private` is deprecated without replacement.', false, {
- id: 'ember-data:deprecate-legacy-imports',
- for: 'ember-data',
- until: '6.0',
- since: {
- enabled: '5.2',
- available: '4.13',
- },
-});
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
+deprecate(
+ 'Importing from `ember-data/-private` is deprecated without replacement.',
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
+ {
+ id: 'ember-data:deprecate-legacy-imports',
+ for: 'ember-data',
+ until: '6.0',
+ since: {
+ enabled: '5.2',
+ available: '4.13',
+ },
+ }
+);
export { default as Store } from '../store';
diff --git a/packages/-ember-data/src/adapter.ts b/packages/-ember-data/src/adapter.ts
index 86e9e39f16c..7f870c613c2 100644
--- a/packages/-ember-data/src/adapter.ts
+++ b/packages/-ember-data/src/adapter.ts
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { default } from '@ember-data/adapter';
deprecate(
'Importing from `ember-data/adapter` is deprecated. Please import from `@ember-data/adapter` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/adapters/errors.ts b/packages/-ember-data/src/adapters/errors.ts
index ef0abcbe475..ffa8d144a6a 100644
--- a/packages/-ember-data/src/adapters/errors.ts
+++ b/packages/-ember-data/src/adapters/errors.ts
@@ -1,5 +1,7 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export {
AbortError,
default as AdapterError,
@@ -10,11 +12,13 @@ export {
ServerError,
TimeoutError,
UnauthorizedError,
+ errorsArrayToHash,
+ errorsHashToArray,
} from '@ember-data/adapter/error';
deprecate(
'Importing from `ember-data/adapters/errors` is deprecated. Please import from `@ember-data/adapter` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/adapters/json-api.ts b/packages/-ember-data/src/adapters/json-api.ts
index 5b02150cc2b..d056eea91f9 100644
--- a/packages/-ember-data/src/adapters/json-api.ts
+++ b/packages/-ember-data/src/adapters/json-api.ts
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { default } from '@ember-data/adapter/json-api';
deprecate(
'Importing from `ember-data/adapters/json-api` is deprecated. Please import from `@ember-data/adapter/json-api` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/adapters/rest.ts b/packages/-ember-data/src/adapters/rest.ts
index 3e8d5887c90..7bea4ec2261 100644
--- a/packages/-ember-data/src/adapters/rest.ts
+++ b/packages/-ember-data/src/adapters/rest.ts
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { default } from '@ember-data/adapter/rest';
deprecate(
'Importing from `ember-data/adapters/rest` is deprecated. Please import from `@ember-data/adapter/rest` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/attr.ts b/packages/-ember-data/src/attr.ts
index d4d29c0318a..93b5cd32c1e 100644
--- a/packages/-ember-data/src/attr.ts
+++ b/packages/-ember-data/src/attr.ts
@@ -1,13 +1,19 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { attr as default } from '@ember-data/model';
-deprecate('Importing from `ember-data/attr` is deprecated. Please import from `@ember-data/model` instead.', false, {
- id: 'ember-data:deprecate-legacy-imports',
- for: 'ember-data',
- until: '6.0',
- since: {
- enabled: '5.2',
- available: '4.13',
- },
-});
+deprecate(
+ 'Importing from `ember-data/attr` is deprecated. Please import from `@ember-data/model` instead.',
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
+ {
+ id: 'ember-data:deprecate-legacy-imports',
+ for: 'ember-data',
+ until: '6.0',
+ since: {
+ enabled: '5.2',
+ available: '4.13',
+ },
+ }
+);
diff --git a/packages/-ember-data/src/index.ts b/packages/-ember-data/src/index.ts
index 6db2ee494c9..87d64f7b851 100644
--- a/packages/-ember-data/src/index.ts
+++ b/packages/-ember-data/src/index.ts
@@ -185,6 +185,7 @@ import Transform, {
NumberTransform,
StringTransform,
} from '@ember-data/serializer/transform';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
import {
DS,
@@ -201,7 +202,7 @@ import setupContainer from './setup-container';
deprecate(
'Importing from `ember-data` is deprecated. Please import from the appropriate `@ember-data/*` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/model.ts b/packages/-ember-data/src/model.ts
index f27c9832bca..4164b3a5dd1 100644
--- a/packages/-ember-data/src/model.ts
+++ b/packages/-ember-data/src/model.ts
@@ -1,13 +1,19 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { default } from '@ember-data/model';
-deprecate('Importing from `ember-data/model` is deprecated. Please import from `@ember-data/model` instead.', false, {
- id: 'ember-data:deprecate-legacy-imports',
- for: 'ember-data',
- until: '6.0',
- since: {
- enabled: '5.2',
- available: '4.13',
- },
-});
+deprecate(
+ 'Importing from `ember-data/model` is deprecated. Please import from `@ember-data/model` instead.',
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
+ {
+ id: 'ember-data:deprecate-legacy-imports',
+ for: 'ember-data',
+ until: '6.0',
+ since: {
+ enabled: '5.2',
+ available: '4.13',
+ },
+ }
+);
diff --git a/packages/-ember-data/src/relationships.ts b/packages/-ember-data/src/relationships.ts
index 24578d4944c..5c5cabfbf14 100644
--- a/packages/-ember-data/src/relationships.ts
+++ b/packages/-ember-data/src/relationships.ts
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { belongsTo, hasMany } from '@ember-data/model';
deprecate(
'Importing from `ember-data/relationships` is deprecated. Please import from `@ember-data/model` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/serializer.ts b/packages/-ember-data/src/serializer.ts
index 33c1b590691..6c878eaeccb 100644
--- a/packages/-ember-data/src/serializer.ts
+++ b/packages/-ember-data/src/serializer.ts
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { default } from '@ember-data/serializer';
deprecate(
'Importing from `ember-data/serializer` is deprecated. Please import from `@ember-data/serializer` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/serializers/embedded-records-mixin.ts b/packages/-ember-data/src/serializers/embedded-records-mixin.ts
index 8cc22d64b6f..6e5ad9a040f 100644
--- a/packages/-ember-data/src/serializers/embedded-records-mixin.ts
+++ b/packages/-ember-data/src/serializers/embedded-records-mixin.ts
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { EmbeddedRecordsMixin as default } from '@ember-data/serializer/rest';
deprecate(
'Importing from `ember-data/serializers/embedded-records-mixin` is deprecated. Please import from `@ember-data/serializer/rest` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/serializers/json-api.ts b/packages/-ember-data/src/serializers/json-api.ts
index 272e7f8deb5..cd8bb715d8f 100644
--- a/packages/-ember-data/src/serializers/json-api.ts
+++ b/packages/-ember-data/src/serializers/json-api.ts
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { default } from '@ember-data/serializer/json-api';
deprecate(
'Importing from `ember-data/serializers/json-api` is deprecated. Please import from `@ember-data/serializer/json-api` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/serializers/json.ts b/packages/-ember-data/src/serializers/json.ts
index 3148ab0ff37..46fccf1e318 100644
--- a/packages/-ember-data/src/serializers/json.ts
+++ b/packages/-ember-data/src/serializers/json.ts
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { default } from '@ember-data/serializer/json';
deprecate(
'Importing from `ember-data/serializers/json` is deprecated. Please import from `@ember-data/serializer/json` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/serializers/rest.ts b/packages/-ember-data/src/serializers/rest.ts
index 41743413946..4c65661a043 100644
--- a/packages/-ember-data/src/serializers/rest.ts
+++ b/packages/-ember-data/src/serializers/rest.ts
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { default } from '@ember-data/serializer/rest';
deprecate(
'Importing from `ember-data/serializers/rest` is deprecated. Please import from `@ember-data/serializer/rest` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/-ember-data/src/setup-container.ts b/packages/-ember-data/src/setup-container.ts
index f6c010d3548..00a519ce955 100644
--- a/packages/-ember-data/src/setup-container.ts
+++ b/packages/-ember-data/src/setup-container.ts
@@ -1,6 +1,8 @@
import type Application from '@ember/application';
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
function initializeStore(application: Application) {
application.registerOptionsForType('serializer', { singleton: false });
application.registerOptionsForType('adapter', { singleton: false });
@@ -10,12 +12,16 @@ export default function setupContainer(application: Application) {
initializeStore(application);
}
-deprecate('Importing from `ember-data/setup-container` is deprecated without replacement', false, {
- id: 'ember-data:deprecate-legacy-imports',
- for: 'ember-data',
- until: '6.0',
- since: {
- enabled: '5.2',
- available: '4.13',
- },
-});
+deprecate(
+ 'Importing from `ember-data/setup-container` is deprecated without replacement',
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
+ {
+ id: 'ember-data:deprecate-legacy-imports',
+ for: 'ember-data',
+ until: '6.0',
+ since: {
+ enabled: '5.2',
+ available: '4.13',
+ },
+ }
+);
diff --git a/packages/-ember-data/src/store.ts b/packages/-ember-data/src/store.ts
index 7482209de23..d750281c67e 100644
--- a/packages/-ember-data/src/store.ts
+++ b/packages/-ember-data/src/store.ts
@@ -24,6 +24,12 @@ function hasRequestManager(store: BaseStore): boolean {
return 'requestManager' in store;
}
+// FIXME @ember-data/store
+// may also need to do all of this configuration
+// because in 4.12 we had not yet caused it to be
+// required to use `ember-data/store` to get the configured
+// store except in the case of RequestManager.
+// so for instance in tests new Store would mostly just work (tm)
export default class Store extends BaseStore {
declare _fetchManager: FetchManager;
diff --git a/packages/-ember-data/src/transform.ts b/packages/-ember-data/src/transform.ts
index ca0fb52b174..c9124e01d93 100644
--- a/packages/-ember-data/src/transform.ts
+++ b/packages/-ember-data/src/transform.ts
@@ -1,10 +1,12 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
+
export { default } from '@ember-data/serializer/transform';
deprecate(
'Importing from `ember-data/transform` is deprecated. Please import from `@ember-data/serializer/transform` instead.',
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-legacy-imports',
for: 'ember-data',
diff --git a/packages/active-record/package.json b/packages/active-record/package.json
index 606449b4670..c851420fdae 100644
--- a/packages/active-record/package.json
+++ b/packages/active-record/package.json
@@ -1,7 +1,7 @@
{
"name": "@ember-data/active-record",
"description": "ActiveRecord Format Support for EmberData",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"private": false,
"license": "MIT",
"author": "Chris Thoburn ",
diff --git a/packages/adapter/package.json b/packages/adapter/package.json
index 677bc93ed5a..90f0527529c 100644
--- a/packages/adapter/package.json
+++ b/packages/adapter/package.json
@@ -1,6 +1,6 @@
{
"name": "@ember-data/adapter",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"description": "Provides Legacy JSON:API and REST Implementations of the Adapter Interface for use with @ember-data/store",
"keywords": [
"ember-addon"
diff --git a/packages/adapter/src/error.js b/packages/adapter/src/error.js
index f19e7149b9d..d21456c1334 100644
--- a/packages/adapter/src/error.js
+++ b/packages/adapter/src/error.js
@@ -1,6 +1,9 @@
/**
@module @ember-data/adapter/error
*/
+import { deprecate } from '@ember/debug';
+
+import { DEPRECATE_HELPERS } from '@warp-drive/build-config/deprecations';
import { assert } from '@warp-drive/build-config/macros';
import { getOrSetGlobal } from '@warp-drive/core-types/-private';
@@ -353,3 +356,161 @@ export const ServerError = getOrSetGlobal(
extend(AdapterError, 'The adapter operation failed due to a server error')
);
ServerError.prototype.code = 'ServerError';
+
+function makeArray(value) {
+ return Array.isArray(value) ? value : [value];
+}
+
+const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/;
+const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/;
+const PRIMARY_ATTRIBUTE_KEY = 'base';
+/**
+ Convert an hash of errors into an array with errors in JSON-API format.
+ ```javascript
+ import { errorsHashToArray } from '@ember-data/adapter/error';
+
+ let errors = {
+ base: 'Invalid attributes on saving this record',
+ name: 'Must be present',
+ age: ['Must be present', 'Must be a number']
+ };
+ let errorsArray = errorsHashToArray(errors);
+ // [
+ // {
+ // title: "Invalid Document",
+ // detail: "Invalid attributes on saving this record",
+ // source: { pointer: "/data" }
+ // },
+ // {
+ // title: "Invalid Attribute",
+ // detail: "Must be present",
+ // source: { pointer: "/data/attributes/name" }
+ // },
+ // {
+ // title: "Invalid Attribute",
+ // detail: "Must be present",
+ // source: { pointer: "/data/attributes/age" }
+ // },
+ // {
+ // title: "Invalid Attribute",
+ // detail: "Must be a number",
+ // source: { pointer: "/data/attributes/age" }
+ // }
+ // ]
+ ```
+ @method errorsHashToArray
+ @for @ember-data/adapter/error
+ @static
+ @deprecated
+ @public
+ @param {Object} errors hash with errors as properties
+ @return {Array} array of errors in JSON-API format
+*/
+export function errorsHashToArray(errors) {
+ if (DEPRECATE_HELPERS) {
+ deprecate(`errorsHashToArray helper has been deprecated.`, false, {
+ id: 'ember-data:deprecate-errors-hash-to-array-helper',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ });
+ const out = [];
+
+ if (errors) {
+ Object.keys(errors).forEach((key) => {
+ const messages = makeArray(errors[key]);
+ for (let i = 0; i < messages.length; i++) {
+ let title = 'Invalid Attribute';
+ let pointer = `/data/attributes/${key}`;
+ if (key === PRIMARY_ATTRIBUTE_KEY) {
+ title = 'Invalid Document';
+ pointer = `/data`;
+ }
+ out.push({
+ title: title,
+ detail: messages[i],
+ source: {
+ pointer: pointer,
+ },
+ });
+ }
+ });
+ }
+
+ return out;
+ }
+ assert(`errorsHashToArray helper has been removed`);
+}
+
+/**
+ Convert an array of errors in JSON-API format into an object.
+
+ ```javascript
+ import { errorsArrayToHash } from '@ember-data/adapter/error';
+
+ let errorsArray = [
+ {
+ title: 'Invalid Attribute',
+ detail: 'Must be present',
+ source: { pointer: '/data/attributes/name' }
+ },
+ {
+ title: 'Invalid Attribute',
+ detail: 'Must be present',
+ source: { pointer: '/data/attributes/age' }
+ },
+ {
+ title: 'Invalid Attribute',
+ detail: 'Must be a number',
+ source: { pointer: '/data/attributes/age' }
+ }
+ ];
+
+ let errors = errorsArrayToHash(errorsArray);
+ // {
+ // "name": ["Must be present"],
+ // "age": ["Must be present", "must be a number"]
+ // }
+ ```
+
+ @method errorsArrayToHash
+ @static
+ @for @ember-data/adapter/error
+ @deprecated
+ @public
+ @param {Array} errors array of errors in JSON-API format
+ @return {Object}
+*/
+export function errorsArrayToHash(errors) {
+ if (DEPRECATE_HELPERS) {
+ deprecate(`errorsArrayToHash helper has been deprecated.`, false, {
+ id: 'ember-data:deprecate-errors-array-to-hash-helper',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ });
+ const out = {};
+
+ if (errors) {
+ errors.forEach((error) => {
+ if (error.source && error.source.pointer) {
+ let key = error.source.pointer.match(SOURCE_POINTER_REGEXP);
+
+ if (key) {
+ key = key[2];
+ } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) {
+ key = PRIMARY_ATTRIBUTE_KEY;
+ }
+
+ if (key) {
+ out[key] = out[key] || [];
+ out[key].push(error.detail || error.title);
+ }
+ }
+ });
+ }
+
+ return out;
+ }
+ assert(`errorsArrayToHash helper has been removed`);
+}
diff --git a/packages/build-config/package.json b/packages/build-config/package.json
index da8c7cc9d27..297950862a9 100644
--- a/packages/build-config/package.json
+++ b/packages/build-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@warp-drive/build-config",
- "version": "0.0.0-alpha.58",
+ "version": "4.12.8",
"description": "Provides Build Configuration for projects using WarpDrive or EmberData",
"keywords": [
"ember-data",
diff --git a/packages/build-config/src/deprecation-versions.ts b/packages/build-config/src/deprecation-versions.ts
index 78d21a10057..80d5148b4d3 100644
--- a/packages/build-config/src/deprecation-versions.ts
+++ b/packages/build-config/src/deprecation-versions.ts
@@ -88,6 +88,621 @@
* @public
*/
export const DEPRECATE_CATCH_ALL = '99.0';
+
+/**
+ * **id: ember-data:rsvp-unresolved-async**
+ *
+ * Deprecates when a request promise did not resolve prior to the store tearing down.
+ *
+ * Note: in most cases even with the promise guard that is now being deprecated
+ * a test crash would still be encountered.
+ *
+ * To resolve: Tests or Fastboot instances which crash need to find triggers requests
+ * and properly await them before tearing down.
+ *
+ * @property DEPRECATE_RSVP_PROMISE
+ * @since 4.4
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_RSVP_PROMISE = '4.4';
+
+/**
+ * **id: ember-data:model-save-promise**
+ *
+ * Affects
+ * - model.save / store.saveRecord
+ * - model.reload
+ *
+ * Deprecates the promise-proxy returned by these methods in favor of
+ * a Promise return value.
+ *
+ * To resolve this deprecation, `await` or `.then` the return value
+ * before doing work with the result instead of accessing values via
+ * the proxy.
+ *
+ * To continue utilizing flags such as `isPending` in your templates
+ * consider using [ember-promise-helpers](https://github.com/fivetanley/ember-promise-helpers)
+ *
+ * @property DEPRECATE_SAVE_PROMISE_ACCESS
+ * @since 4.4
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_SAVE_PROMISE_ACCESS = '4.4';
+
+/**
+ * **id: ember-data:deprecate-snapshot-model-class-access**
+ *
+ * Deprecates accessing the factory class for a given resource type
+ * via properties on various classes.
+ *
+ * Guards
+ *
+ * - SnapshotRecordArray.type
+ * - Snapshot.type
+ * - RecordArray.type
+ *
+ * Use `store.modelFor()` instead.
+ *
+ * @property DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS
+ * @since 4.5
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS = '4.5';
+
+/**
+ * **id: ember-data:deprecate-store-find**
+ *
+ * Deprecates using `store.find` instead of `store.findRecord`. Typically
+ * `store.find` is a mistaken call that occurs when using implicit route behaviors
+ * in Ember which attempt to derive how to load data via parsing the route params
+ * for a route which does not implement a `model` hook.
+ *
+ * To resolve, use `store.findRecord`. This may require implementing an associated
+ * route's `model() {}` hook.
+ *
+ * @property DEPRECATE_STORE_FIND
+ * @since 4.5
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_STORE_FIND = '4.5';
+
+/**
+ * **id: ember-data:deprecate-has-record-for-id**
+ *
+ * Deprecates `store.hasRecordForId(type, id)` in favor of `store.peekRecord({ type, id }) !== null`.
+ *
+ * Broadly speaking, while the ability to query for presence is important, a key distinction exists
+ * between these methods that make relying on `hasRecordForId` unsafe, as it may report `true` for a
+ * record which is not-yet loaded and un-peekable. `peekRecord` offers a safe mechanism by which to check
+ * for whether a record is present in a usable manner.
+ *
+ * @property DEPRECATE_HAS_RECORD
+ * @since 4.5
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_HAS_RECORD = '4.5';
+
+/**
+ * **id: ember-data:deprecate-string-arg-schemas**
+ *
+ * Deprecates `schema.attributesDefinitionFor(type)` and
+ * `schema.relationshipsDefinitionFor(type)` in favor of
+ * a consistent object signature (`identifier | { type }`).
+ *
+ * To resolve change
+ *
+ * ```diff
+ * - store.getSchemaDefinitionService().attributesDefinitionFor('user')
+ * + store.getSchemaDefinitionService().attributesDefinitionFor({ type: 'user' })
+ * ```
+ *
+ * @property DEPRECATE_STRING_ARG_SCHEMAS
+ * @since 4.5
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_STRING_ARG_SCHEMAS = '4.5';
+
+/**
+ * **id: ember-data:deprecate-secret-adapter-fallback**
+ *
+ * Deprecates the secret `-json-api` fallback adapter in favor
+ * or an explicit "catch all" application adapter. In addition
+ * to this deprecation ensuring the user has explicitly chosen an
+ * adapter, this ensures that the user may choose to use no adapter
+ * at all.
+ *
+ * Simplest fix:
+ *
+ * */app/adapters/application.js*
+ * ```js
+ * export { default } from '@ember-data/adapter/json-api';
+ * ```
+ *
+ * @property DEPRECATE_JSON_API_FALLBACK
+ * @since 4.5
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_JSON_API_FALLBACK = '4.5';
+
+/**
+ * **id: ember-data:deprecate-model-reopen**
+ *
+ * ----
+ *
+ * For properties known ahead of time, instead of
+ *
+ * ```ts
+ * class User extends Model { @attr firstName; }
+ *
+ * User.reopen({ lastName: attr() });
+ * ```
+ *
+ * Extend `User` again or include it in the initial definition.
+ *
+ * ```ts
+ * class User extends Model { @attr firstName; @attr lastName }
+ * ```
+ *
+ * For properties generated dynamically, consider registering
+ * a `SchemaDefinitionService` with the store , as such services
+ * are capable of dynamically adjusting their schemas, and utilize
+ * the `instantiateRecord` hook to create a Proxy based class that
+ * can react to the changes in the schema.
+ *
+ *
+ * Use Foo extends Model to extend your class instead
+ *
+ *
+ *
+ *
+ * **id: ember-data:deprecate-model-reopenclass**
+ *
+ * ----
+ *
+ * Instead of reopenClass, define `static` properties with native class syntax
+ * or add them to the final object.
+ *
+ * ```ts
+ * // instead of
+ * User.reopenClass({ aStaticMethod() {} });
+ *
+ * // do this
+ * class User {
+ * static aStaticMethod() {}
+ * }
+ *
+ * // or do this
+ * User.aStaticMethod = function() {}
+ * ```
+ *
+ *
+ * @property DEPRECATE_MODEL_REOPEN
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_MODEL_REOPEN = '4.7';
+
+/**
+ * **id: ember-data:deprecate-early-static**
+ *
+ * This deprecation triggers if static computed properties
+ * or methods are triggered without looking up the record
+ * via the store service's `modelFor` hook. Accessing this
+ * static information without looking up the model via the
+ * store most commonly occurs when
+ *
+ * - using ember-cli-mirage (to fix, refactor to not use its auto-discovery of ember-data models)
+ * - importing a model class and accessing its static information via the import
+ *
+ * Instead of
+ *
+ * ```js
+ * import User from 'my-app/models/user';
+ *
+ * const relationships = User.relationshipsByName;
+ * ```
+ *
+ * Do *at least* this
+ *
+ * ```js
+ * const relationships = store.modelFor('user').relationshipsByName;
+ * ```
+ *
+ * However, the much more future proof refactor is to not use `modelFor` at all but instead
+ * to utilize the schema service for this static information.
+ *
+ * ```js
+ * const relationships = store.getSchemaDefinitionService().relationshipsDefinitionFor({ type: 'user' });
+ * ```
+ *
+ *
+ * @property DEPRECATE_EARLY_STATIC
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_EARLY_STATIC = '4.7';
+
+/**
+ * **id: ember-data:deprecate-errors-hash-to-array-helper**
+ * **id: ember-data:deprecate-errors-array-to-hash-helper**
+ * **id: ember-data:deprecate-normalize-modelname-helper**
+ *
+ * Deprecates `errorsHashToArray` `errorsArrayToHash` and `normalizeModelName`
+ *
+ * Users making use of these (already private) utilities can trivially copy them
+ * into their own codebase to continue using them, though we recommend refactoring
+ * to a more direct conversion into the expected errors format for the errors helpers.
+ *
+ * For refactoring normalizeModelName we also recommend following the guidance in
+ * [RFC#740 Deprecate Non-Strict Types](https://github.com/emberjs/rfcs/pull/740).
+ *
+ *
+ * @property DEPRECATE_HELPERS
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_HELPERS = '4.7';
+
+/**
+ * **id: ember-data:deprecate-promise-many-array-behavior**
+ *
+ * [RFC Documentation](https://rfcs.emberjs.com/id/0745-ember-data-deprecate-methods-on-promise-many-array)
+ *
+ * This deprecation deprecates accessing values on the asynchronous proxy
+ * in favor of first "resolving" or "awaiting" the promise to retrieve a
+ * synchronous value.
+ *
+ * Template iteration of the asynchronous value will still work and not trigger
+ * the deprecation, but all JS access should be avoided and HBS access for anything
+ * but `{{#each}}` should also be refactored.
+ *
+ * Recommended approaches include using the addon `ember-promise-helpers`, using
+ * Ember's `resource` pattern (including potentially the addon `ember-data-resources`),
+ * resolving the value in routes/provider components, or using the references API.
+ *
+ * An example of using the [hasMany](https://api.emberjs.com/ember-data/4.11/classes/Model/methods/hasMany?anchor=hasMany) [reference API](https://api.emberjs.com/ember-data/release/classes/HasManyReference):
+ *
+ * ```ts
+ * // get the synchronous "ManyArray" value for the asynchronous "friends" relationship.
+ * // note, this will return `null` if the relationship has not been loaded yet
+ * const value = person.hasMany('friends').value();
+ *
+ * // to get just the list of related IDs
+ * const ids = person.hasMany('friends').ids();
+ * ```
+ *
+ * References participate in autotracking and getters/cached getters etc. which consume them
+ * will recompute if the value changes.
+ *
+ * @property DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS = '4.7';
+
+/**
+ * **id: ember-data:deprecate-non-strict-relationships**
+ *
+ * Deprecates when belongsTo and hasMany relationships are defined
+ * without specifying the inverse record's type.
+ *
+ * Instead of
+ *
+ * ```ts
+ * class Company extends Model {
+ * @hasMany() employees;
+ * }
+ * class Employee extends Model {
+ * @belongsTo() company;
+ * }
+ * ```
+ *
+ * Use
+ *
+ * ```ts
+ * class Company extends Model {
+ * @hasMany('employee', { async: true, inverse: 'company' }) employees;
+ * }
+ *
+ * class Employee extends Model {
+ * @belongsTo('company', { async: true, inverse: 'employees' }) company;
+ * }
+ * ```
+ *
+ * @property DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE = '4.7';
+
+/**
+ * **id: ember-data:deprecate-non-strict-relationships**
+ *
+ * Deprecates when belongsTo and hasMany relationships are defined
+ * without specifying whether the relationship is asynchronous.
+ *
+ * The current behavior is that relationships which do not define
+ * this setting are aschronous (`{ async: true }`).
+ *
+ * Instead of
+ *
+ * ```ts
+ * class Company extends Model {
+ * @hasMany('employee') employees;
+ * }
+ * class Employee extends Model {
+ * @belongsTo('company') company;
+ * }
+ * ```
+ *
+ * Use
+ *
+ * ```ts
+ * class Company extends Model {
+ * @hasMany('employee', { async: true, inverse: 'company' }) employees;
+ * }
+ *
+ * class Employee extends Model {
+ * @belongsTo('company', { async: true, inverse: 'employees' }) company;
+ * }
+ * ```
+ *
+ * @property DEPRECATE_RELATIONSHIPS_WITHOUT_ASYNC
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_RELATIONSHIPS_WITHOUT_ASYNC = '4.7';
+
+/**
+ * **id: ember-data:deprecate-non-strict-relationships**
+ *
+ * Deprecates when belongsTo and hasMany relationships are defined
+ * without specifying the inverse field on the related type.
+ *
+ * The current behavior is that relationships which do not define
+ * this setting have their inverse determined at runtime, which is
+ * potentially non-deterministic when mixins and polymorphism are involved.
+ *
+ * If an inverse relationship exists and you wish changes on one side to
+ * reflect onto the other side, use the inverse key. If you wish to not have
+ * changes reflected or no inverse relationship exists, specify `inverse: null`.
+ *
+ * Instead of
+ *
+ * ```ts
+ * class Company extends Model {
+ * @hasMany('employee') employees;
+ * }
+ * class Employee extends Model {
+ * @belongsTo('company') company;
+ * }
+ * ```
+ *
+ * Use
+ *
+ * ```ts
+ * class Company extends Model {
+ * @hasMany('employee', { async: true, inverse: 'company' }) employees;
+ * }
+ *
+ * class Employee extends Model {
+ * @belongsTo('company', { async: true, inverse: 'employees' }) company;
+ * }
+ * ```
+ *
+ * Instead of
+ *
+ * ```ts
+ * class Company extends Model {
+ * @hasMany('employee') employees;
+ * }
+ * class Employee extends Model {
+ * @attr name;
+ * }
+ * ```
+ *
+ * Use
+ *
+ * ```ts
+ * class Company extends Model {
+ * @hasMany('employee', { async: true, inverse: null }) employees;
+ * }
+ *
+ * class Employee extends Model {
+ * @attr name;
+ * }
+ * ```
+ *
+ * @property DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE = '4.7';
+
+/**
+ * **id: ember-data:no-a-with-array-like**
+ *
+ * Deprecates when calling `A()` on an EmberData ArrayLike class
+ * is detected. This deprecation may not always trigger due to complexities
+ * in ember-source versions and the use (or disabling) of prototype extensions.
+ *
+ * To fix, just use the native array methods instead of the EmberArray methods
+ * and refrain from wrapping the array in `A()`.
+ *
+ * Note that some computed property macros may themselves utilize `A()`, in which
+ * scenario the computed properties need to be upgraded to octane syntax.
+ *
+ * For instance, instead of:
+ *
+ * ```ts
+ * class extends Component {
+ * @filterBy('items', 'isComplete') completedItems;
+ * }
+ * ```
+ *
+ * Use the following:
+ *
+ * ```ts
+ * class extends Component {
+ * get completedItems() {
+ * return this.items.filter(item => item.isComplete);
+ * }
+ * }
+ * ```
+ *
+ * @property DEPRECATE_A_USAGE
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_A_USAGE = '4.7';
+
+/**
+ * **id: ember-data:deprecate-promise-proxies**
+ *
+ * Additional Reading: [RFC#846 Deprecate Proxies](https://rfcs.emberjs.com/id/0846-ember-data-deprecate-proxies)
+ *
+ * Deprecates using the proxy object/proxy array capabilities of values returned from
+ *
+ * - `store.findRecord`
+ * - `store.findAll`
+ * - `store.query`
+ * - `store.queryRecord`
+ * - `record.save`
+ * - `recordArray.save`
+ * - `recordArray.update`
+ *
+ * These methods will now return a native Promise that resolves with the value.
+ *
+ * Note that this does not deprecate the proxy behaviors of `PromiseBelongsTo`. See RFC for reasoning.
+ * The opportunity should still be taken if available to stop using these proxy behaviors; however, this class
+ * will remain until `import Model from '@ember-data/model';` is deprecated more broadly.
+ *
+ * @property DEPRECATE_PROMISE_PROXIES
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_PROMISE_PROXIES = '4.7';
+
+/**
+ * **id: ember-data:deprecate-array-like**
+ *
+ * Deprecates Ember "Array-like" methods on RecordArray and ManyArray.
+ *
+ * These are the arrays returned respectively by `store.peekAll()`, `store.findAll()`and
+ * hasMany relationships on instance of Model or `record.hasMany('relationshipName').value()`.
+ *
+ * The appropriate refactor is to treat these arrays as native arrays and to use native array methods.
+ *
+ * For instance, instead of:
+ *
+ * ```ts
+ * users.firstObject;
+ * ```
+ *
+ * Use:
+ *
+ * ```ts
+ * users[0];
+ * // or
+ * users.at(0);
+ * ```
+ *
+ * @property DEPRECATE_ARRAY_LIKE
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_ARRAY_LIKE = '4.7';
+
+/**
+ * **id: **
+ *
+ * This is a planned deprecation which will trigger when observer or computed
+ * chains are used to watch for changes on any EmberData RecordArray, ManyArray
+ * or PromiseManyArray.
+ *
+ * Support for these chains is currently guarded by the inactive deprecation flag
+ * listed here.
+ *
+ * @property DEPRECATE_COMPUTED_CHAINS
+ * @since 5.0
+ * @until 6.0
+ * @public
+ */
+export const DEPRECATE_COMPUTED_CHAINS = '5.0';
+
+/**
+ * **id: ember-data:non-explicit-relationships**
+ *
+ * Deprecates when polymorphic relationships are detected via inheritance or mixins
+ * and no polymorphic relationship configuration has been setup.
+ *
+ * For further reading please review [RFC#793](https://rfcs.emberjs.com/id/0793-polymporphic-relations-without-inheritance)
+ * which introduced support for explicit relationship polymorphism without
+ * mixins or inheritance.
+ *
+ * You may still use mixins and inheritance to setup your polymorphism; however, the class
+ * structure is no longer what drives the design. Instead polymorphism is "traits" based or "structural":
+ * so long as each model which can satisfy the polymorphic relationship defines the inverse in the same
+ * way they work.
+ *
+ * Notably: `inverse: null` relationships can receive any type as a record with no additional configuration
+ * at all.
+ *
+ * Example Polymorphic Relationship Configuration
+ *
+ * ```ts
+ * // polymorphic relationship
+ * class Tag extends Model {
+ * @hasMany("taggable", { async: false, polymorphic: true, inverse: "tags" }) tagged;
+ * }
+ *
+ * // an inverse concrete relationship (e.g. satisfies "taggable")
+ * class Post extends Model {
+ * @hasMany("tag", { async: false, inverse: "tagged", as: "taggable" }) tags;
+ * }
+ * ```
+ *
+ * @property DEPRECATE_NON_EXPLICIT_POLYMORPHISM
+ * @since 4.7
+ * @until 5.0
+ * @public
+ */
+export const DEPRECATE_NON_EXPLICIT_POLYMORPHISM = '4.7';
+
+/**
+ * **id: ember-data:deprecate-many-array-duplicates**
+ *
+ * When the flag is `true` (default), adding duplicate records to a `ManyArray`
+ * is deprecated in non-production environments. In production environments,
+ * duplicate records added to a `ManyArray` will be deduped and no error will
+ * be thrown.
+ *
+ * When the flag is `false`, an error will be thrown when duplicates are added.
+ *
+ * @property DEPRECATE_MANY_ARRAY_DUPLICATES
+ * @since 5.3
+ * @until 6.0
+ * @public
+ */
+export const DEPRECATE_MANY_ARRAY_DUPLICATES = '4.12'; // '5.3';
+
/**
* **id: ember-data:deprecate-non-strict-types**
*
@@ -146,42 +761,6 @@ export const DEPRECATE_NON_STRICT_TYPES = '5.3';
*/
export const DEPRECATE_NON_STRICT_ID = '5.3';
-/**
- * **id: **
- *
- * This is a planned deprecation which will trigger when observer or computed
- * chains are used to watch for changes on any EmberData LiveArray, CollectionRecordArray,
- * ManyArray or PromiseManyArray.
- *
- * Support for these chains is currently guarded by the deprecation flag
- * listed here, enabling removal of the behavior if desired.
- *
- * @property DEPRECATE_COMPUTED_CHAINS
- * @since 5.0
- * @until 6.0
- * @public
- */
-export const DEPRECATE_COMPUTED_CHAINS = '5.0';
-
-/**
- * **id: ember-data:deprecate-legacy-imports**
- *
- * Deprecates when importing from `ember-data/*` instead of `@ember-data/*`
- * in order to prepare for the eventual removal of the legacy `ember-data/*`
- *
- * All imports from `ember-data/*` should be updated to `@ember-data/*`
- * except for `ember-data/store`. When you are using `ember-data` (as opposed to
- * installing the indivudal packages) you should import from `ember-data/store`
- * instead of `@ember-data/store` in order to receive the appropriate configuration
- * of defaults.
- *
- * @property DEPRECATE_LEGACY_IMPORTS
- * @since 5.3
- * @until 6.0
- * @public
- */
-export const DEPRECATE_LEGACY_IMPORTS = '5.3';
-
/**
* **id: ember-data:deprecate-non-unique-collection-payloads**
*
@@ -372,23 +951,6 @@ export const DEPRECATE_NON_UNIQUE_PAYLOADS = '5.3';
*/
export const DEPRECATE_RELATIONSHIP_REMOTE_UPDATE_CLEARING_LOCAL_STATE = '5.3';
-/**
- * **id: ember-data:deprecate-many-array-duplicates**
- *
- * When the flag is `true` (default), adding duplicate records to a `ManyArray`
- * is deprecated in non-production environments. In production environments,
- * duplicate records added to a `ManyArray` will be deduped and no error will
- * be thrown.
- *
- * When the flag is `false`, an error will be thrown when duplicates are added.
- *
- * @property DEPRECATE_MANY_ARRAY_DUPLICATES
- * @since 5.3
- * @until 6.0
- * @public
- */
-export const DEPRECATE_MANY_ARRAY_DUPLICATES = '5.3';
-
/**
* **id: ember-data:deprecate-store-extends-ember-object**
*
@@ -459,3 +1021,20 @@ export const ENABLE_LEGACY_SCHEMA_SERVICE = '5.4';
* @public
*/
export const DEPRECATE_EMBER_INFLECTOR = '5.3';
+
+/**
+ * This is a special flag that can be used to opt-in early to receiving deprecations introduced in 5.x
+ * which have had their infra backported to 4.x versions of EmberData.
+ *
+ * When this flag is not present or set to `true`, the deprecations from the 5.x branch
+ * will not print their messages and the deprecation cannot be resolved.
+ *
+ * When this flag is present and set to `false`, the deprecations from the 5.x branch will
+ * print and can be resolved.
+ *
+ * @property DISABLE_6X_DEPRECATIONS
+ * @since 4.13
+ * @until 5.0
+ * @public
+ */
+export const DISABLE_6X_DEPRECATIONS = '6.0';
diff --git a/packages/build-config/src/deprecations.ts b/packages/build-config/src/deprecations.ts
index e6c80aa73ea..344315da32f 100644
--- a/packages/build-config/src/deprecations.ts
+++ b/packages/build-config/src/deprecations.ts
@@ -1,12 +1,31 @@
// deprecations
export const DEPRECATE_CATCH_ALL: boolean = true;
+export const DEPRECATE_SAVE_PROMISE_ACCESS: boolean = true;
+export const DEPRECATE_RSVP_PROMISE: boolean = true;
+export const DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS: boolean = true;
+export const DEPRECATE_STORE_FIND: boolean = true;
+export const DEPRECATE_HAS_RECORD: boolean = true;
+// FIXME we can potentially drop this since the cache implementations we care about turn out to all be stuck 4.6 or earlier
+export const DEPRECATE_STRING_ARG_SCHEMAS: boolean = true;
+export const DEPRECATE_JSON_API_FALLBACK: boolean = true;
+export const DEPRECATE_MODEL_REOPEN: boolean = true;
+export const DEPRECATE_EARLY_STATIC: boolean = true;
+export const DEPRECATE_HELPERS: boolean = true;
+export const DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS: boolean = true;
+export const DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE: boolean = true;
+export const DEPRECATE_RELATIONSHIPS_WITHOUT_ASYNC: boolean = true;
+export const DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE: boolean = true;
+export const DEPRECATE_A_USAGE: boolean = true;
+export const DEPRECATE_PROMISE_PROXIES: boolean = true;
+export const DEPRECATE_ARRAY_LIKE: boolean = true;
export const DEPRECATE_COMPUTED_CHAINS: boolean = true;
+export const DEPRECATE_NON_EXPLICIT_POLYMORPHISM: boolean = true;
+export const DEPRECATE_MANY_ARRAY_DUPLICATES: boolean = true;
export const DEPRECATE_NON_STRICT_TYPES: boolean = true;
export const DEPRECATE_NON_STRICT_ID: boolean = true;
-export const DEPRECATE_LEGACY_IMPORTS: boolean = true;
export const DEPRECATE_NON_UNIQUE_PAYLOADS: boolean = true;
export const DEPRECATE_RELATIONSHIP_REMOTE_UPDATE_CLEARING_LOCAL_STATE: boolean = true;
-export const DEPRECATE_MANY_ARRAY_DUPLICATES: boolean = true;
export const DEPRECATE_STORE_EXTENDS_EMBER_OBJECT: boolean = true;
export const ENABLE_LEGACY_SCHEMA_SERVICE: boolean = true;
export const DEPRECATE_EMBER_INFLECTOR: boolean = true;
+export const DISABLE_6X_DEPRECATIONS: boolean = true;
diff --git a/packages/core-types/package.json b/packages/core-types/package.json
index a9be5a044b2..2d8a57b25c1 100644
--- a/packages/core-types/package.json
+++ b/packages/core-types/package.json
@@ -1,6 +1,6 @@
{
"name": "@warp-drive/core-types",
- "version": "0.0.0-alpha.107",
+ "version": "4.12.8",
"description": "Provides core logic, utils and types for WarpDrive and EmberData",
"keywords": [
"ember-addon"
diff --git a/packages/debug/package.json b/packages/debug/package.json
index e137e65bbea..3a17493dd4b 100644
--- a/packages/debug/package.json
+++ b/packages/debug/package.json
@@ -1,6 +1,6 @@
{
"name": "@ember-data/debug",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"description": "Provides support for the ember-inspector for apps built with Ember and EmberData",
"keywords": [
"ember-addon"
diff --git a/packages/diagnostic/package.json b/packages/diagnostic/package.json
index 2fcbccc8dfa..02964f7cea4 100644
--- a/packages/diagnostic/package.json
+++ b/packages/diagnostic/package.json
@@ -1,6 +1,7 @@
{
"name": "@warp-drive/diagnostic",
- "version": "0.0.0-alpha.107",
+ "version": "4.12.8",
+ "private": true,
"description": "⚡️ A Lightweight Modern Test Runner",
"keywords": [
"test",
diff --git a/packages/graph/eslint.config.mjs b/packages/graph/eslint.config.mjs
index 63296bac802..c42683457ca 100644
--- a/packages/graph/eslint.config.mjs
+++ b/packages/graph/eslint.config.mjs
@@ -2,6 +2,7 @@
import { globalIgnores } from '@warp-drive/internal-config/eslint/ignore.js';
import * as node from '@warp-drive/internal-config/eslint/node.js';
import * as typescript from '@warp-drive/internal-config/eslint/typescript.js';
+import { externals } from './vite.config.mjs';
/** @type {import('eslint').Linter.FlatConfig[]} */
export default [
@@ -11,7 +12,7 @@ export default [
// browser (js/ts) ================
typescript.browser({
srcDirs: ['src'],
- allowedImports: ['@ember/debug'],
+ allowedImports: externals,
}),
// node (module) ================
diff --git a/packages/graph/package.json b/packages/graph/package.json
index ad8526a85e8..90e8d04c9d0 100644
--- a/packages/graph/package.json
+++ b/packages/graph/package.json
@@ -1,6 +1,6 @@
{
"name": "@ember-data/graph",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"description": "Provides a normalized graph for managing relationships between resources",
"keywords": [
"ember-addon"
diff --git a/packages/graph/src/-private/-diff.ts b/packages/graph/src/-private/-diff.ts
index 868c4c80510..0041ab66a66 100644
--- a/packages/graph/src/-private/-diff.ts
+++ b/packages/graph/src/-private/-diff.ts
@@ -1,6 +1,6 @@
import { deprecate } from '@ember/debug';
-import { DEPRECATE_NON_UNIQUE_PAYLOADS } from '@warp-drive/build-config/deprecations';
+import { DEPRECATE_NON_UNIQUE_PAYLOADS, DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
@@ -178,7 +178,7 @@ export function diffCollection(
if (DEBUG) {
deprecate(
`Expected all entries in the relationship ${relationship.definition.type}:${relationship.definition.key} to be unique, see log for a list of duplicate entry indeces`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-non-unique-relationship-entries',
for: 'ember-data',
diff --git a/packages/graph/src/-private/-edge-definition.ts b/packages/graph/src/-private/-edge-definition.ts
index 6412cbb0400..a6868f487db 100644
--- a/packages/graph/src/-private/-edge-definition.ts
+++ b/packages/graph/src/-private/-edge-definition.ts
@@ -1,4 +1,5 @@
import type Store from '@ember-data/store';
+import { DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE } from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
@@ -581,12 +582,27 @@ export function upgradeDefinition(
return info;
}
+type RelationshipDefinition = RelationshipField & {
+ _inverseKey: (store: Store, modelClass: unknown) => string | null;
+};
+
+function metaIsRelationshipDefinition(meta: FieldSchema): meta is RelationshipDefinition {
+ return typeof (meta as RelationshipDefinition)._inverseKey === 'function';
+}
+
function inverseForRelationship(store: Store, identifier: StableRecordIdentifier | { type: string }, key: string) {
const definition = store.schema.fields(identifier).get(key);
if (!definition) {
return null;
}
+ if (DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE) {
+ if (metaIsRelationshipDefinition(definition)) {
+ const modelClass = store.modelFor(identifier.type);
+ return definition._inverseKey(store, modelClass);
+ }
+ }
+
assert(`Expected ${key} to be a relationship`, isRelationshipField(definition));
assert(
`Expected the relationship defintion to specify the inverse type or null.`,
diff --git a/packages/graph/src/-private/coerce-id.ts b/packages/graph/src/-private/coerce-id.ts
index 7ad7db9c748..4c44a8b22e0 100644
--- a/packages/graph/src/-private/coerce-id.ts
+++ b/packages/graph/src/-private/coerce-id.ts
@@ -1,6 +1,6 @@
import { deprecate } from '@ember/debug';
-import { DEPRECATE_NON_STRICT_ID } from '@warp-drive/build-config/deprecations';
+import { DEPRECATE_NON_STRICT_ID, DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
import { assert } from '@warp-drive/build-config/macros';
// Used by the store to normalize IDs entering the store. Despite the fact
@@ -24,7 +24,7 @@ export function coerceId(id: Coercable): string | null {
`The resource id '<${typeof id}> ${String(
id
)} ' is not normalized. Update your application code to use '${JSON.stringify(normalized)}' instead.`,
- normalized === id,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS ? true : normalized === id,
{
id: 'ember-data:deprecate-non-strict-id',
until: '6.0',
diff --git a/packages/graph/src/-private/debug/assert-polymorphic-type.ts b/packages/graph/src/-private/debug/assert-polymorphic-type.ts
index db9cb188bc6..ee164ad6bb8 100644
--- a/packages/graph/src/-private/debug/assert-polymorphic-type.ts
+++ b/packages/graph/src/-private/debug/assert-polymorphic-type.ts
@@ -1,11 +1,34 @@
/* eslint-disable @typescript-eslint/no-shadow */
-import type { CacheCapabilitiesManager } from '@ember-data/store/types';
+import type Mixin from '@ember/object/mixin';
+
+import type Store from '@ember-data/store';
+import type { CacheCapabilitiesManager, ModelSchema } from '@ember-data/store/types';
+import { DEPRECATE_NON_EXPLICIT_POLYMORPHISM } from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
import { isLegacyField, isRelationshipField, temporaryConvertToLegacy, type UpgradedMeta } from '../-edge-definition';
+type Model = ModelSchema;
+
+// A pile of soft-lies to deal with mixin APIs
+type ModelWithMixinApis = Model & {
+ isModel?: boolean;
+ __isMixin?: boolean;
+ __mixin: Mixin;
+ PrototypeMixin: Mixin;
+ detect: (mixin: Model | Mixin | ModelWithMixinApis) => boolean;
+ prototype: Model;
+ [Symbol.hasInstance](model: Model): true;
+};
+
+function assertModelSchemaIsModel(
+ schema: ModelSchema | Model | ModelWithMixinApis
+): asserts schema is ModelWithMixinApis {
+ assert(`Expected Schema to be an instance of Model`, 'isModel' in schema && schema.isModel === true);
+}
+
/*
Assert that `addedRecord` has a valid type so it can be added to the
relationship of the `record`.
@@ -27,6 +50,21 @@ let assertPolymorphicType: (
let assertInheritedSchema: (definition: UpgradedMeta, type: string) => void;
if (DEBUG) {
+ const checkPolymorphic = function checkPolymorphic(modelClass: ModelSchema, addedModelClass: ModelSchema) {
+ assertModelSchemaIsModel(modelClass);
+ assertModelSchemaIsModel(addedModelClass);
+
+ if (modelClass.__isMixin) {
+ return (
+ modelClass.__mixin.detect(addedModelClass.PrototypeMixin) ||
+ // handle native class extension e.g. `class Post extends Model.extend(Commentable) {}`
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ modelClass.__mixin.detect(Object.getPrototypeOf(addedModelClass).PrototypeMixin)
+ );
+ }
+ return addedModelClass.prototype instanceof modelClass || modelClass.detect(addedModelClass);
+ };
+
function validateSchema(definition: UpgradedMeta, meta: PrintConfig) {
const errors = new Map();
@@ -61,9 +99,9 @@ if (DEBUG) {
kind: string;
options: {
as?: string;
- async: boolean;
+ async?: boolean;
polymorphic?: boolean;
- inverse: string | null;
+ inverse?: string | null;
};
};
type RelationshipSchemaError = 'name' | 'type' | 'kind' | 'as' | 'async' | 'polymorphic' | 'inverse';
@@ -211,69 +249,143 @@ if (DEBUG) {
if (parentDefinition.inverseIsImplicit) {
return;
}
+ let asserted = false;
+
if (parentDefinition.isPolymorphic) {
- let meta = store.schema.fields(addedIdentifier).get(parentDefinition.inverseKey);
- assert(
- `No '${parentDefinition.inverseKey}' field exists on '${
- addedIdentifier.type
- }'. To use this type in the polymorphic relationship '${parentDefinition.inverseType}.${
- parentDefinition.key
- }' the relationships schema definition for ${addedIdentifier.type} should include:${expectedSchema(
- parentDefinition
- )}`,
- meta
- );
- assert(
- `Expected the field ${parentDefinition.inverseKey} to be a relationship`,
- meta && isRelationshipField(meta)
- );
- meta = isLegacyField(meta) ? meta : temporaryConvertToLegacy(meta);
+ const rawMeta = store.schema.fields(addedIdentifier).get(parentDefinition.inverseKey);
assert(
- `You should not specify both options.as and options.inverse as null on ${addedIdentifier.type}.${parentDefinition.inverseKey}, as if there is no inverse field there is no abstract type to conform to. You may have intended for this relationship to be polymorphic, or you may have mistakenly set inverse to null.`,
- !(meta.options.inverse === null && meta?.options.as?.length)
- );
- const errors = validateSchema(parentDefinition, meta);
- assert(
- `The schema for the relationship '${parentDefinition.inverseKey}' on '${
- addedIdentifier.type
- }' type does not correctly implement '${parentDefinition.type}' and thus cannot be assigned to the '${
- parentDefinition.key
- }' relationship in '${
- parentIdentifier.type
- }'. If using this record in this polymorphic relationship is desired, correct the errors in the schema shown below:${printSchema(
- meta,
- errors
- )}`,
- errors.size === 0
+ `Expected to find a relationship field schema for ${parentDefinition.inverseKey} on ${addedIdentifier.type} but none was found`,
+ !rawMeta || isRelationshipField(rawMeta)
);
+ const meta = rawMeta && (isLegacyField(rawMeta) ? rawMeta : temporaryConvertToLegacy(rawMeta));
+
+ if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
+ if (meta?.options?.as) {
+ asserted = true;
+ assert(
+ `No '${parentDefinition.inverseKey}' field exists on '${addedIdentifier.type}'. To use this type in the polymorphic relationship '${parentDefinition.inverseType}.${parentDefinition.key}' the relationships schema definition for ${addedIdentifier.type} should include:${expectedSchema(parentDefinition)}`,
+ meta
+ );
+ assert(
+ `You should not specify both options.as and options.inverse as null on ${addedIdentifier.type}.${parentDefinition.inverseKey}, as if there is no inverse field there is no abstract type to conform to. You may have intended for this relationship to be polymorphic, or you may have mistakenly set inverse to null.`,
+ !(meta.options.inverse === null && meta?.options.as?.length > 0)
+ );
+ const errors = validateSchema(parentDefinition, meta);
+ assert(
+ `The schema for the relationship '${parentDefinition.inverseKey}' on '${addedIdentifier.type}' type does not correctly implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. If using this record in this polymorphic relationship is desired, correct the errors in the schema shown below:${printSchema(meta, errors)}`,
+ errors.size === 0
+ );
+ }
+ } else {
+ assert(
+ `No '${parentDefinition.inverseKey}' field exists on '${
+ addedIdentifier.type
+ }'. To use this type in the polymorphic relationship '${parentDefinition.inverseType}.${
+ parentDefinition.key
+ }' the relationships schema definition for ${addedIdentifier.type} should include:${expectedSchema(
+ parentDefinition
+ )}`,
+ meta
+ );
+ assert(
+ `Expected the field ${parentDefinition.inverseKey} to be a relationship`,
+ meta && isRelationshipField(meta)
+ );
+ assert(
+ `You should not specify both options.as and options.inverse as null on ${addedIdentifier.type}.${parentDefinition.inverseKey}, as if there is no inverse field there is no abstract type to conform to. You may have intended for this relationship to be polymorphic, or you may have mistakenly set inverse to null.`,
+ !(meta.options.inverse === null && meta?.options.as?.length)
+ );
+ const errors = validateSchema(parentDefinition, meta);
+ assert(
+ `The schema for the relationship '${parentDefinition.inverseKey}' on '${
+ addedIdentifier.type
+ }' type does not correctly implement '${parentDefinition.type}' and thus cannot be assigned to the '${
+ parentDefinition.key
+ }' relationship in '${
+ parentIdentifier.type
+ }'. If using this record in this polymorphic relationship is desired, correct the errors in the schema shown below:${printSchema(
+ meta,
+ errors
+ )}`,
+ errors.size === 0
+ );
+ }
} else if (addedIdentifier.type !== parentDefinition.type) {
// if we are not polymorphic
// then the addedIdentifier.type must be the same as the parentDefinition.type
- let meta = store.schema.fields(addedIdentifier).get(parentDefinition.inverseKey);
+ const rawMeta = store.schema.fields(addedIdentifier).get(parentDefinition.inverseKey);
assert(
- `Expected the field ${parentDefinition.inverseKey} to be a relationship`,
- !meta || isRelationshipField(meta)
+ `Expected to find a relationship field schema for ${parentDefinition.inverseKey} on ${addedIdentifier.type} but none was found`,
+ !rawMeta || isRelationshipField(rawMeta)
);
- meta = meta && (isLegacyField(meta) ? meta : temporaryConvertToLegacy(meta));
- if (meta?.options.as === parentDefinition.type) {
- // inverse is likely polymorphic but missing the polymorphic flag
- let meta = store.schema.fields({ type: parentDefinition.inverseType }).get(parentDefinition.key);
- assert(`Expected the field ${parentDefinition.key} to be a relationship`, meta && isRelationshipField(meta));
- meta = isLegacyField(meta) ? meta : temporaryConvertToLegacy(meta);
- const errors = validateSchema(definitionWithPolymorphic(inverseDefinition(parentDefinition)), meta);
- assert(
- `The '<${addedIdentifier.type}>.${
- parentDefinition.inverseKey
- }' relationship cannot be used polymorphically because '<${parentDefinition.inverseType}>.${
- parentDefinition.key
- } is not a polymorphic relationship. To use this relationship in a polymorphic manner, fix the following schema issues on the relationships schema for '${
- parentDefinition.inverseType
- }':${printSchema(meta, errors)}`
- );
- } else {
+ const meta = rawMeta && (isLegacyField(rawMeta) ? rawMeta : temporaryConvertToLegacy(rawMeta));
+
+ if (!DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
+ if (meta?.options.as === parentDefinition.type) {
+ // inverse is likely polymorphic but missing the polymorphic flag
+ const inverseMeta = store.schema.fields({ type: parentDefinition.inverseType }).get(parentDefinition.key);
+ assert(
+ `Expected to find a relationship field schema for ${parentDefinition.inverseKey} on ${addedIdentifier.type} but none was found`,
+ inverseMeta && isRelationshipField(inverseMeta)
+ );
+ const legacyInverseMeta =
+ inverseMeta && (isLegacyField(inverseMeta) ? inverseMeta : temporaryConvertToLegacy(inverseMeta));
+ const errors = validateSchema(
+ definitionWithPolymorphic(inverseDefinition(parentDefinition)),
+ legacyInverseMeta
+ );
+ assert(
+ `The '<${addedIdentifier.type}>.${parentDefinition.inverseKey}' relationship cannot be used polymorphically because '<${parentDefinition.inverseType}>.${parentDefinition.key} is not a polymorphic relationship. To use this relationship in a polymorphic manner, fix the following schema issues on the relationships schema for '${parentDefinition.inverseType}':${printSchema(legacyInverseMeta, errors)}`
+ );
+ } else {
+ assert(
+ `The '${addedIdentifier.type}' type does not implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. If this relationship should be polymorphic, mark ${parentDefinition.inverseType}.${parentDefinition.key} as \`polymorphic: true\` and ${addedIdentifier.type}.${parentDefinition.inverseKey} as implementing it via \`as: '${parentDefinition.type}'\`.`
+ );
+ }
+ } else if ((meta?.options?.as?.length ?? 0) > 0) {
+ asserted = true;
assert(
- `The '${addedIdentifier.type}' type does not implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. If this relationship should be polymorphic, mark ${parentDefinition.inverseType}.${parentDefinition.key} as \`polymorphic: true\` and ${addedIdentifier.type}.${parentDefinition.inverseKey} as implementing it via \`as: '${parentDefinition.type}'\`.`
+ `Expected the field ${parentDefinition.inverseKey} to be a relationship`,
+ !meta || isRelationshipField(meta)
);
+ const legacyMeta = meta && (isLegacyField(meta) ? meta : temporaryConvertToLegacy(meta));
+ if (legacyMeta?.options.as === parentDefinition.type) {
+ // inverse is likely polymorphic but missing the polymorphic flag
+ let meta = store.schema.fields({ type: parentDefinition.inverseType }).get(parentDefinition.key);
+ assert(`Expected the field ${parentDefinition.key} to be a relationship`, meta && isRelationshipField(meta));
+ meta = isLegacyField(meta) ? meta : temporaryConvertToLegacy(meta);
+ const errors = validateSchema(definitionWithPolymorphic(inverseDefinition(parentDefinition)), meta);
+ assert(
+ `The '<${addedIdentifier.type}>.${
+ parentDefinition.inverseKey
+ }' relationship cannot be used polymorphically because '<${parentDefinition.inverseType}>.${
+ parentDefinition.key
+ } is not a polymorphic relationship. To use this relationship in a polymorphic manner, fix the following schema issues on the relationships schema for '${
+ parentDefinition.inverseType
+ }':${printSchema(meta, errors)}`
+ );
+ } else {
+ assert(
+ `The '${addedIdentifier.type}' type does not implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. If this relationship should be polymorphic, mark ${parentDefinition.inverseType}.${parentDefinition.key} as \`polymorphic: true\` and ${addedIdentifier.type}.${parentDefinition.inverseKey} as implementing it via \`as: '${parentDefinition.type}'\`.`
+ );
+ }
+ }
+ }
+
+ if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
+ if (!asserted) {
+ const storeService = (store as unknown as { _store: Store })._store;
+ const addedModelName = addedIdentifier.type;
+ const parentModelName = parentIdentifier.type;
+ const key = parentDefinition.key;
+ const relationshipModelName = parentDefinition.type;
+ const relationshipClass = storeService.modelFor(relationshipModelName);
+ const addedClass = storeService.modelFor(addedModelName);
+
+ const assertionMessage = `The '${addedModelName}' type does not implement '${relationshipModelName}' and thus cannot be assigned to the '${key}' relationship in '${parentModelName}'. Make it a descendant of '${relationshipModelName}' or use a mixin of the same name.`;
+ const isPolymorphic = checkPolymorphic(relationshipClass, addedClass);
+
+ assert(assertionMessage, isPolymorphic);
}
}
};
diff --git a/packages/graph/src/-private/operations/replace-related-record.ts b/packages/graph/src/-private/operations/replace-related-record.ts
index 0eae682d6d6..ee8833f2cbb 100644
--- a/packages/graph/src/-private/operations/replace-related-record.ts
+++ b/packages/graph/src/-private/operations/replace-related-record.ts
@@ -1,6 +1,9 @@
import { deprecate } from '@ember/debug';
-import { DEPRECATE_RELATIONSHIP_REMOTE_UPDATE_CLEARING_LOCAL_STATE } from '@warp-drive/build-config/deprecations';
+import {
+ DEPRECATE_RELATIONSHIP_REMOTE_UPDATE_CLEARING_LOCAL_STATE,
+ DISABLE_6X_DEPRECATIONS,
+} from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
@@ -97,7 +100,7 @@ export default function replaceRelatedRecord(graph: Graph, op: ReplaceRelatedRec
} belongsTo relationship but will not be once this deprecation is resolved:\n\n\t${
localState ? 'Added: ' + localState.lid + '\n\t' : ''
}${existingState ? 'Removed: ' + existingState.lid : ''}`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-relationship-remote-update-clearing-local-state',
for: 'ember-data',
@@ -176,7 +179,7 @@ export default function replaceRelatedRecord(graph: Graph, op: ReplaceRelatedRec
} belongsTo relationship but will not be once this deprecation is resolved:\n\n\t${
localState ? 'Added: ' + localState.lid + '\n\t' : ''
}${existingState ? 'Removed: ' + existingState.lid : ''}`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-relationship-remote-update-clearing-local-state',
for: 'ember-data',
diff --git a/packages/graph/src/-private/operations/replace-related-records.ts b/packages/graph/src/-private/operations/replace-related-records.ts
index 5e04a712411..6cc3c58c6a7 100644
--- a/packages/graph/src/-private/operations/replace-related-records.ts
+++ b/packages/graph/src/-private/operations/replace-related-records.ts
@@ -1,6 +1,9 @@
import { deprecate } from '@ember/debug';
-import { DEPRECATE_RELATIONSHIP_REMOTE_UPDATE_CLEARING_LOCAL_STATE } from '@warp-drive/build-config/deprecations';
+import {
+ DEPRECATE_RELATIONSHIP_REMOTE_UPDATE_CLEARING_LOCAL_STATE,
+ DISABLE_6X_DEPRECATIONS,
+} from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
@@ -287,7 +290,7 @@ function replaceRelatedRecordsRemote(graph: Graph, op: ReplaceRelatedRecordsOper
} hasMany relationship but will not be once this deprecation is resolved by opting into the new behavior:\n\n\tAdded: [${deprecationInfo.additions
.map((i) => i.lid)
.join(', ')}]\n\tRemoved: [${deprecationInfo.removals.map((i) => i.lid).join(', ')}]`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-relationship-remote-update-clearing-local-state',
for: 'ember-data',
diff --git a/packages/graph/vite.config.mjs b/packages/graph/vite.config.mjs
index 7936563a474..a548ae349de 100644
--- a/packages/graph/vite.config.mjs
+++ b/packages/graph/vite.config.mjs
@@ -1,6 +1,7 @@
import { createConfig } from '@warp-drive/internal-config/vite/config.js';
export const externals = [
+ '@ember/object/mixin', // type only
'@ember/debug', // assert, deprecate
];
diff --git a/packages/holodeck/package.json b/packages/holodeck/package.json
index 6d5316cd17b..5bfcdf81598 100644
--- a/packages/holodeck/package.json
+++ b/packages/holodeck/package.json
@@ -1,7 +1,8 @@
{
"name": "@warp-drive/holodeck",
"description": "⚡️ Simple, Fast HTTP Mocking for Tests",
- "version": "0.0.0-alpha.107",
+ "version": "4.12.8",
+ "private": true,
"license": "MIT",
"author": "Chris Thoburn ",
"repository": {
diff --git a/packages/json-api/package.json b/packages/json-api/package.json
index 8409b8167a0..eff6132c4c1 100644
--- a/packages/json-api/package.json
+++ b/packages/json-api/package.json
@@ -1,6 +1,6 @@
{
"name": "@ember-data/json-api",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"description": "Provides a JSON:API document and resource cache implementation for EmberData",
"keywords": [
"ember-addon"
diff --git a/packages/legacy-compat/package.json b/packages/legacy-compat/package.json
index 039c26bf803..14c550af8f3 100644
--- a/packages/legacy-compat/package.json
+++ b/packages/legacy-compat/package.json
@@ -1,7 +1,7 @@
{
"name": "@ember-data/legacy-compat",
"description": "Compatibility Shims for Older EmberData",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"license": "MIT",
"author": "Chris Thoburn ",
"repository": {
diff --git a/packages/legacy-compat/src/builders/utils.ts b/packages/legacy-compat/src/builders/utils.ts
index 2cc2c71689f..dc29dd7bb26 100644
--- a/packages/legacy-compat/src/builders/utils.ts
+++ b/packages/legacy-compat/src/builders/utils.ts
@@ -1,7 +1,7 @@
import { deprecate } from '@ember/debug';
import { dasherize } from '@ember-data/request-utils/string';
-import { DEPRECATE_NON_STRICT_TYPES } from '@warp-drive/build-config/deprecations';
+import { DEPRECATE_NON_STRICT_TYPES, DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
import type { ResourceIdentifierObject } from '@warp-drive/core-types/spec/json-api-raw';
export function isMaybeIdentifier(
@@ -21,7 +21,7 @@ export function normalizeModelName(type: string): string {
deprecate(
`The resource type '${type}' is not normalized. Update your application code to use '${result}' instead of '${type}'.`,
- result === type,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS ? true : result === type,
{
id: 'ember-data:deprecate-non-strict-types',
until: '6.0',
diff --git a/packages/legacy-compat/src/index.ts b/packages/legacy-compat/src/index.ts
index 62a23740ef7..c9077b86e46 100644
--- a/packages/legacy-compat/src/index.ts
+++ b/packages/legacy-compat/src/index.ts
@@ -1,12 +1,14 @@
import { getOwner } from '@ember/application';
+import { deprecate } from '@ember/debug';
import type Store from '@ember-data/store';
import { recordIdentifierFor } from '@ember-data/store';
-import { _deprecatingNormalize } from '@ember-data/store/-private';
+import { DEPRECATE_JSON_API_FALLBACK } from '@warp-drive/build-config/deprecations';
import { assert } from '@warp-drive/build-config/macros';
import type { ObjectValue } from '@warp-drive/core-types/json/raw';
import { FetchManager, upgradeStore } from './-private';
+import { normalizeModelName } from './builders/utils';
import type { AdapterPayload, MinimumAdapterInterface } from './legacy-network-handler/minimum-adapter-interface';
import type {
MinimumSerializerInterface,
@@ -68,7 +70,7 @@ export function adapterFor(this: Store, modelName: string, _allowMissing?: true)
this._adapterCache =
this._adapterCache || (Object.create(null) as Record);
- const normalizedModelName = _deprecatingNormalize(modelName);
+ const normalizedModelName = normalizeModelName(modelName);
const { _adapterCache } = this;
let adapter: (MinimumAdapterInterface & { store: Store }) | undefined = _adapterCache[normalizedModelName];
@@ -93,6 +95,28 @@ export function adapterFor(this: Store, modelName: string, _allowMissing?: true)
return adapter;
}
+ if (DEPRECATE_JSON_API_FALLBACK) {
+ // final fallback, no model specific adapter, no application adapter, no
+ // `adapter` property on store: use json-api adapter
+ adapter = _adapterCache['-json-api'] || owner.lookup('adapter:-json-api');
+ if (adapter !== undefined) {
+ deprecate(
+ `Your application is utilizing a deprecated hidden fallback adapter (-json-api). Please implement an application adapter to function as your fallback.`,
+ false,
+ {
+ id: 'ember-data:deprecate-secret-adapter-fallback',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.5', enabled: '4.5' },
+ }
+ );
+ _adapterCache[normalizedModelName] = adapter;
+ _adapterCache['-json-api'] = adapter;
+
+ return adapter;
+ }
+ }
+
assert(
`No adapter was found for '${modelName}' and no 'application' adapter was found as a fallback.`,
_allowMissing
@@ -129,7 +153,7 @@ export function serializerFor(this: Store, modelName: string): MinimumSerializer
upgradeStore(this);
this._serializerCache =
this._serializerCache || (Object.create(null) as Record);
- const normalizedModelName = _deprecatingNormalize(modelName);
+ const normalizedModelName = normalizeModelName(modelName);
const { _serializerCache } = this;
let serializer: (MinimumSerializerInterface & { store: Store }) | undefined = _serializerCache[normalizedModelName];
@@ -190,7 +214,7 @@ export function normalize(this: Store, modelName: string, payload: ObjectValue)
`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${typeof modelName}`,
typeof modelName === 'string'
);
- const normalizedModelName = _deprecatingNormalize(modelName);
+ const normalizedModelName = normalizeModelName(modelName);
const serializer = this.serializerFor(normalizedModelName);
const schema = this.modelFor(normalizedModelName);
assert(
@@ -265,7 +289,7 @@ export function pushPayload(this: Store, modelName: string, inputPayload: Object
);
const payload: ObjectValue = inputPayload || (modelName as unknown as ObjectValue);
- const normalizedModelName = inputPayload ? _deprecatingNormalize(modelName) : 'application';
+ const normalizedModelName = inputPayload ? normalizeModelName(modelName) : 'application';
const serializer = this.serializerFor(normalizedModelName);
assert(
diff --git a/packages/legacy-compat/src/legacy-network-handler/fetch-manager.ts b/packages/legacy-compat/src/legacy-network-handler/fetch-manager.ts
index 1e30751209e..68ae09dd30c 100644
--- a/packages/legacy-compat/src/legacy-network-handler/fetch-manager.ts
+++ b/packages/legacy-compat/src/legacy-network-handler/fetch-manager.ts
@@ -1,4 +1,4 @@
-import { warn } from '@ember/debug';
+import { deprecate, warn } from '@ember/debug';
import { dependencySatisfies, importSync, macroCondition } from '@embroider/macros';
@@ -13,6 +13,7 @@ import type {
} from '@ember-data/store/-private';
import { coerceId } from '@ember-data/store/-private';
import type { FindRecordOptions, ModelSchema } from '@ember-data/store/types';
+import { DEPRECATE_RSVP_PROMISE } from '@warp-drive/build-config/deprecations';
import { DEBUG, TESTING } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import { getOrSetGlobal } from '@warp-drive/core-types/-private';
@@ -28,6 +29,7 @@ import type { AdapterPayload, MinimumAdapterInterface } from './minimum-adapter-
import type { MinimumSerializerInterface } from './minimum-serializer-interface';
import { normalizeResponseHelper } from './serializer-response';
import { Snapshot } from './snapshot';
+import { _objectIsAlive } from './utils';
type Deferred = ReturnType>;
type AdapterErrors = Error & { errors?: string[]; isAdapterError?: true };
@@ -611,6 +613,7 @@ function _flushPendingSave(store: Store, pending: PendingSaveItem) {
const modelName = snapshot.modelName;
const modelClass = store.modelFor(modelName);
+ const record = store._instanceCache.getRecord(identifier);
assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter);
assert(
@@ -627,6 +630,24 @@ function _flushPendingSave(store: Store, pending: PendingSaveItem) {
);
promise = promise.then((adapterPayload) => {
+ if (!_objectIsAlive(record)) {
+ if (DEPRECATE_RSVP_PROMISE) {
+ deprecate(
+ `A Promise while saving ${modelName} did not resolve by the time your model was destroyed. This will error in a future release.`,
+ false,
+ {
+ id: 'ember-data:rsvp-unresolved-async',
+ until: '5.0',
+ for: '@ember-data/store',
+ since: {
+ available: '4.5',
+ enabled: '4.5',
+ },
+ }
+ );
+ }
+ }
+
if (adapterPayload) {
return normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation);
}
diff --git a/packages/legacy-compat/src/legacy-network-handler/legacy-data-fetch.ts b/packages/legacy-compat/src/legacy-network-handler/legacy-data-fetch.ts
index d1618279415..6864f61fa05 100644
--- a/packages/legacy-compat/src/legacy-network-handler/legacy-data-fetch.ts
+++ b/packages/legacy-compat/src/legacy-network-handler/legacy-data-fetch.ts
@@ -1,8 +1,12 @@
+import { deprecate } from '@ember/debug';
+
import type Store from '@ember-data/store';
-import type { BaseFinderOptions } from '@ember-data/store/types';
+import type { BaseFinderOptions, ModelSchema } from '@ember-data/store/types';
+import { DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE, DEPRECATE_RSVP_PROMISE } from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { StableExistingRecordIdentifier } from '@warp-drive/core-types/identifier';
import type { LegacyRelationshipSchema as RelationshipSchema } from '@warp-drive/core-types/schema/fields';
import type { ExistingResourceObject, JsonApiDocument } from '@warp-drive/core-types/spec/json-api-raw';
@@ -10,6 +14,7 @@ import { upgradeStore } from '../-private';
import { iterateData, payloadIsNotBlank } from './legacy-data-utils';
import type { MinimumAdapterInterface } from './minimum-adapter-interface';
import { normalizeResponseHelper } from './serializer-response';
+import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './utils';
export function _findHasMany(
adapter: MinimumAdapterInterface,
@@ -18,9 +23,9 @@ export function _findHasMany(
link: string | null | { href: string },
relationship: RelationshipSchema,
options: BaseFinderOptions
-) {
+): Promise {
upgradeStore(store);
- const promise = Promise.resolve().then(() => {
+ let promise: Promise = Promise.resolve().then(() => {
const snapshot = store._fetchManager.createSnapshot(identifier, options);
const useLink = !link || typeof link === 'string';
const relatedLink = useLink ? link : link.href;
@@ -35,7 +40,28 @@ export function _findHasMany(
return adapter.findHasMany(store, snapshot, relatedLink, relationship);
});
- return promise.then((adapterPayload) => {
+ promise = guardDestroyedStore(promise, store);
+ promise = promise.then((adapterPayload) => {
+ const record = store._instanceCache.getRecord(identifier);
+
+ if (!_objectIsAlive(record)) {
+ if (DEPRECATE_RSVP_PROMISE) {
+ deprecate(
+ `A Promise for fetching ${relationship.type} did not resolve by the time your model was destroyed. This will error in a future release.`,
+ false,
+ {
+ id: 'ember-data:rsvp-unresolved-async',
+ until: '5.0',
+ for: '@ember-data/store',
+ since: {
+ available: '4.5',
+ enabled: '4.5',
+ },
+ }
+ );
+ }
+ }
+
assert(
`You made a 'findHasMany' request for a ${identifier.type}'s '${
relationship.name
@@ -59,6 +85,14 @@ export function _findHasMany(
payload = syncRelationshipDataFromLink(store, payload, identifier as ResourceIdentity, relationship);
return store._push(payload, true);
}, null);
+
+ if (DEPRECATE_RSVP_PROMISE) {
+ const record = store._instanceCache.getRecord(identifier);
+
+ promise = _guard(promise, _bind(_objectIsAlive, record));
+ }
+
+ return promise as Promise;
}
export function _findBelongsTo(
@@ -69,7 +103,7 @@ export function _findBelongsTo(
options: BaseFinderOptions
) {
upgradeStore(store);
- const promise = Promise.resolve().then(() => {
+ let promise = Promise.resolve().then(() => {
const adapter = store.adapterFor(identifier.type);
assert(`You tried to load a belongsTo relationship but you have no adapter (for ${identifier.type})`, adapter);
assert(
@@ -86,7 +120,33 @@ export function _findBelongsTo(
return adapter.findBelongsTo(store, snapshot, relatedLink, relationship);
});
+ if (DEPRECATE_RSVP_PROMISE) {
+ const record = store._instanceCache.getRecord(identifier);
+ promise = guardDestroyedStore(promise, store);
+ promise = _guard(promise, _bind(_objectIsAlive, record));
+ }
+
return promise.then((adapterPayload) => {
+ if (DEPRECATE_RSVP_PROMISE) {
+ const record = store._instanceCache.getRecord(identifier);
+
+ if (!_objectIsAlive(record)) {
+ deprecate(
+ `A Promise for fetching ${relationship.type} did not resolve by the time your model was destroyed. This will error in a future release.`,
+ false,
+ {
+ id: 'ember-data:rsvp-unresolved-async',
+ until: '5.0',
+ for: '@ember-data/store',
+ since: {
+ available: '4.5',
+ enabled: '4.5',
+ },
+ }
+ );
+ }
+ }
+
const modelClass = store.modelFor(relationship.type);
const serializer = store.serializerFor(relationship.type);
let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo');
@@ -226,11 +286,24 @@ function ensureRelationshipIsSetToParent(
}
}
+type LegacyRelationshipDefinition = { _inverseKey: (store: Store, modelClass: ModelSchema) => string | null };
+
+function metaIsRelationshipDefinition(meta: unknown): meta is LegacyRelationshipDefinition {
+ return typeof meta === 'object' && !!meta && '_inverseKey' in meta && typeof meta._inverseKey === 'function';
+}
+
function inverseForRelationship(store: Store, identifier: { type: string; id?: string }, key: string) {
const definition = store.schema.fields(identifier).get(key);
if (!definition) {
return null;
}
+
+ if (DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE) {
+ if (metaIsRelationshipDefinition(definition)) {
+ const modelClass = store.modelFor(identifier.type);
+ return definition._inverseKey(store, modelClass);
+ }
+ }
assert(
`Expected the field definition to be a relationship`,
definition.kind === 'hasMany' || definition.kind === 'belongsTo'
diff --git a/packages/legacy-compat/src/legacy-network-handler/snapshot-record-array.ts b/packages/legacy-compat/src/legacy-network-handler/snapshot-record-array.ts
index 1121ec58fc8..a6e996c9bd9 100644
--- a/packages/legacy-compat/src/legacy-network-handler/snapshot-record-array.ts
+++ b/packages/legacy-compat/src/legacy-network-handler/snapshot-record-array.ts
@@ -1,14 +1,19 @@
/**
@module @ember-data/legacy-compat
*/
+
+import { deprecate } from '@ember/debug';
+
import type Store from '@ember-data/store';
import type { LiveArray } from '@ember-data/store/-private';
import { SOURCE } from '@ember-data/store/-private';
import type { FindAllOptions, ModelSchema } from '@ember-data/store/types';
+import { DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS } from '@warp-drive/build-config/deprecations';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
import { upgradeStore } from '../-private';
import type { Snapshot } from './snapshot';
+
/**
SnapshotRecordArray is not directly instantiable.
Instances are provided to consuming application's
@@ -180,3 +185,29 @@ export class SnapshotRecordArray {
return this._snapshots;
}
}
+
+if (DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS) {
+ /**
+ The type of the underlying records for the snapshots in the array, as a Model
+
+ @deprecated
+ @property type
+ @public
+ @type {Model}
+ */
+ Object.defineProperty(SnapshotRecordArray.prototype, 'type', {
+ get() {
+ deprecate(
+ `Using SnapshotRecordArray.type to access the ModelClass for a record is deprecated. Use store.modelFor() instead.`,
+ false,
+ {
+ id: 'ember-data:deprecate-snapshot-model-class-access',
+ until: '5.0',
+ for: 'ember-data',
+ since: { available: '4.5.0', enabled: '4.5.0' },
+ }
+ );
+ return (this as SnapshotRecordArray)._recordArray.type as ModelSchema;
+ },
+ });
+}
diff --git a/packages/legacy-compat/src/legacy-network-handler/snapshot.ts b/packages/legacy-compat/src/legacy-network-handler/snapshot.ts
index 1198930fc9a..becb2a7524d 100644
--- a/packages/legacy-compat/src/legacy-network-handler/snapshot.ts
+++ b/packages/legacy-compat/src/legacy-network-handler/snapshot.ts
@@ -1,11 +1,14 @@
/**
@module @ember-data/store
*/
+import { deprecate } from '@ember/debug';
+
import { dependencySatisfies, importSync } from '@embroider/macros';
import type { CollectionEdge, ResourceEdge } from '@ember-data/graph/-private';
import type Store from '@ember-data/store';
-import type { FindRecordOptions } from '@ember-data/store/types';
+import type { FindRecordOptions, ModelSchema } from '@ember-data/store/types';
+import { DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS } from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
@@ -46,6 +49,16 @@ export class Snapshot {
declare adapterOptions?: Record;
declare _store: Store;
+ /**
+ The type of the underlying record for this snapshot, as a Model.
+
+ @property type
+ @public
+ @deprecated
+ @type {Model}
+ */
+ declare type: ModelSchema;
+
/**
* @method constructor
* @constructor
@@ -561,3 +574,21 @@ export class Snapshot {
return serializer.serialize(this, options);
}
}
+
+if (DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS) {
+ Object.defineProperty(Snapshot.prototype, 'type', {
+ get(this: Snapshot) {
+ deprecate(
+ `Using Snapshot.type to access the ModelClass for a record is deprecated. Use store.modelFor() instead.`,
+ false,
+ {
+ id: 'ember-data:deprecate-snapshot-model-class-access',
+ until: '5.0',
+ for: 'ember-data',
+ since: { available: '4.5.0', enabled: '4.5.0' },
+ }
+ );
+ return this._store.modelFor(this.identifier.type);
+ },
+ });
+}
diff --git a/packages/legacy-compat/src/legacy-network-handler/utils.ts b/packages/legacy-compat/src/legacy-network-handler/utils.ts
new file mode 100644
index 00000000000..69c64fd7e71
--- /dev/null
+++ b/packages/legacy-compat/src/legacy-network-handler/utils.ts
@@ -0,0 +1,57 @@
+import { deprecate } from '@ember/debug';
+
+import type Store from '@ember-data/store';
+import { DEPRECATE_RSVP_PROMISE } from '@warp-drive/build-config/deprecations';
+
+function isObject(value: unknown): value is T {
+ return value !== null && typeof value === 'object';
+}
+
+export function _objectIsAlive(object: unknown): boolean {
+ return isObject<{ isDestroyed: boolean; isDestroying: boolean }>(object)
+ ? !(object.isDestroyed || object.isDestroying)
+ : false;
+}
+
+export function guardDestroyedStore(promise: Promise, store: Store): Promise {
+ return promise.then((_v) => {
+ if (!_objectIsAlive(store)) {
+ if (DEPRECATE_RSVP_PROMISE) {
+ deprecate(
+ `A Promise did not resolve by the time the store was destroyed. This will error in a future release.`,
+ false,
+ {
+ id: 'ember-data:rsvp-unresolved-async',
+ until: '5.0',
+ for: '@ember-data/store',
+ since: {
+ available: '4.5',
+ enabled: '4.5',
+ },
+ }
+ );
+ }
+ }
+
+ return _v;
+ });
+}
+
+export function _bind boolean>(fn: T, ...args: unknown[]) {
+ return function () {
+ // eslint-disable-next-line prefer-spread
+ return fn.apply(undefined, args);
+ };
+}
+
+export function _guard(promise: Promise, test: () => boolean): Promise {
+ const guarded = promise.finally(() => {
+ if (!test()) {
+ // @ts-expect-error this is a private RSVPPromise API that won't always be there
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions, @typescript-eslint/no-unsafe-member-access
+ guarded._subscribers ? (guarded._subscribers.length = 0) : null;
+ }
+ });
+
+ return guarded;
+}
diff --git a/packages/model/eslint.config.mjs b/packages/model/eslint.config.mjs
index 9ca51cdf5b4..c42683457ca 100644
--- a/packages/model/eslint.config.mjs
+++ b/packages/model/eslint.config.mjs
@@ -2,6 +2,7 @@
import { globalIgnores } from '@warp-drive/internal-config/eslint/ignore.js';
import * as node from '@warp-drive/internal-config/eslint/node.js';
import * as typescript from '@warp-drive/internal-config/eslint/typescript.js';
+import { externals } from './vite.config.mjs';
/** @type {import('eslint').Linter.FlatConfig[]} */
export default [
@@ -11,17 +12,7 @@ export default [
// browser (js/ts) ================
typescript.browser({
srcDirs: ['src'],
- allowedImports: [
- '@ember/array',
- '@ember/array/proxy',
- '@ember/debug',
- '@ember/object/internals',
- '@ember/object/proxy',
- '@ember/object/computed',
- '@ember/object',
- '@ember/application',
- '@ember/object/promise-proxy-mixin',
- ],
+ allowedImports: externals,
}),
// node (module) ================
diff --git a/packages/model/package.json b/packages/model/package.json
index d1a9b50b9a3..273d3d3159d 100644
--- a/packages/model/package.json
+++ b/packages/model/package.json
@@ -1,6 +1,6 @@
{
"name": "@ember-data/model",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"description": "A basic Ember implementation of a resource presentation layer for use with @ember-data/store",
"keywords": [
"ember-addon"
diff --git a/packages/model/src/-private/belongs-to.ts b/packages/model/src/-private/belongs-to.ts
index 8f3f387cd21..95bbacb4889 100644
--- a/packages/model/src/-private/belongs-to.ts
+++ b/packages/model/src/-private/belongs-to.ts
@@ -1,6 +1,14 @@
-import { warn } from '@ember/debug';
+import { deprecate, warn } from '@ember/debug';
import { computed } from '@ember/object';
+import { dasherize, singularize } from '@ember-data/request-utils/string';
+import {
+ DEPRECATE_NON_STRICT_TYPES,
+ DEPRECATE_RELATIONSHIPS_WITHOUT_ASYNC,
+ DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE,
+ DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE,
+ DISABLE_6X_DEPRECATIONS,
+} from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { TypeFromInstance } from '@warp-drive/core-types/record';
@@ -8,7 +16,7 @@ import { RecordStore } from '@warp-drive/core-types/symbols';
import { lookupLegacySupport } from './legacy-relationships-support';
import type { MinimalLegacyRecord } from './model-methods';
-import { isElementDescriptor, normalizeModelName } from './util';
+import { isElementDescriptor } from './util';
/**
@module @ember-data/model
*/
@@ -33,22 +41,116 @@ export type NoNull = Exclude;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export type RelationshipDecorator = (target: This, key: string, desc?: PropertyDescriptor) => void; // BelongsToDecoratorObject;
+function normalizeType(type: string) {
+ if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE) {
+ if (!type) {
+ return;
+ }
+ }
+
+ if (DEPRECATE_NON_STRICT_TYPES) {
+ const result = singularize(dasherize(type));
+
+ deprecate(
+ `The resource type '${type}' is not normalized. Update your application code to use '${result}' instead of '${type}'.`,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS ? true : result === type,
+ {
+ id: 'ember-data:deprecate-non-strict-types',
+ until: '6.0',
+ for: 'ember-data',
+ since: {
+ available: '4.13',
+ enabled: '5.3',
+ },
+ }
+ );
+
+ return result;
+ }
+
+ return type;
+}
+
function _belongsTo(
type: string,
options: RelationshipOptions
): RelationshipDecorator {
- assert(
- `Expected options.async from @belongsTo('${type}', options) to be a boolean`,
- options && typeof options.async === 'boolean'
- );
- assert(
- `Expected options.inverse from @belongsTo('${type}', options) to be either null or the string type of the related resource.`,
- options.inverse === null || (typeof options.inverse === 'string' && options.inverse.length > 0)
- );
+ let opts = options;
+ let rawType: string | undefined = type;
+ if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE) {
+ if (typeof type !== 'string' || !type.length) {
+ deprecate('belongsTo() must specify the string type of the related resource as the first parameter', false, {
+ id: 'ember-data:deprecate-non-strict-relationships',
+ for: 'ember-data',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ });
+
+ if (typeof type === 'object') {
+ opts = type;
+ rawType = undefined;
+ } else {
+ opts = options;
+ rawType = type;
+ }
+
+ assert(
+ 'The first argument to belongsTo must be a string representing a model type key, not an instance of ' +
+ typeof rawType +
+ ". E.g., to define a relation to the Person model, use belongsTo('person')",
+ typeof rawType === 'string' || typeof rawType === 'undefined'
+ );
+ }
+ }
+
+ if (DEPRECATE_RELATIONSHIPS_WITHOUT_ASYNC) {
+ if (!opts || typeof opts.async !== 'boolean') {
+ opts = opts || {};
+ if (!('async' in opts)) {
+ // @ts-expect-error the inbound signature is strict to convince the user to use the non-deprecated signature
+ opts.async = true as Async;
+ }
+ deprecate('belongsTo(, ) must specify options.async as either `true` or `false`.', false, {
+ id: 'ember-data:deprecate-non-strict-relationships',
+ for: 'ember-data',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ });
+ } else {
+ assert(`Expected belongsTo options.async to be a boolean`, opts && typeof opts.async === 'boolean');
+ }
+ } else {
+ assert(`Expected belongsTo options.async to be a boolean`, opts && typeof opts.async === 'boolean');
+ }
+
+ if (DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE) {
+ if (opts.inverse !== null && (typeof opts.inverse !== 'string' || opts.inverse.length === 0)) {
+ deprecate(
+ 'belongsTo(, ) must specify options.inverse as either `null` or the name of the field on the related resource type.',
+ false,
+ {
+ id: 'ember-data:deprecate-non-strict-relationships',
+ for: 'ember-data',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Expected belongsTo options.inverse to be either null or the string type of the related resource.`,
+ opts.inverse === null || (typeof opts.inverse === 'string' && opts.inverse.length > 0)
+ );
+ }
+ } else {
+ assert(
+ `Expected belongsTo options.inverse to be either null or the string type of the related resource.`,
+ opts.inverse === null || (typeof opts.inverse === 'string' && opts.inverse.length > 0)
+ );
+ }
const meta = {
- type: normalizeModelName(type),
- options: options,
+ type: normalizeType(type),
+ options: opts,
kind: 'belongsTo',
name: '',
};
@@ -285,11 +387,17 @@ export function belongsTo(
type?: TypeFromInstance>,
options?: RelationshipOptions
): RelationshipDecorator {
- if (DEBUG) {
+ if (!DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE) {
assert(
- `belongsTo must be invoked with a type and options. Did you mean \`@belongsTo(${type}, { async: false, inverse: null })\`?`,
+ `belongsTo must be invoked with a type and options. Did you mean \`@belongsTo(, { async: false, inverse: null })\`?`,
!isElementDescriptor(arguments as unknown as unknown[])
);
+ return _belongsTo(type!, options!);
+ } else {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return isElementDescriptor(arguments as unknown as any[])
+ ? // @ts-expect-error the inbound signature is strict to convince the user to use the non-deprecated signature
+ (_belongsTo()(...arguments) as RelationshipDecorator)
+ : _belongsTo(type!, options!);
}
- return _belongsTo(type!, options!);
}
diff --git a/packages/model/src/-private/debug/assert-polymorphic-type.ts b/packages/model/src/-private/debug/assert-polymorphic-type.ts
index 49c451e0f99..bf9f57b79ee 100644
--- a/packages/model/src/-private/debug/assert-polymorphic-type.ts
+++ b/packages/model/src/-private/debug/assert-polymorphic-type.ts
@@ -1,8 +1,31 @@
+import type Mixin from '@ember/object/mixin';
+
import type { UpgradedMeta } from '@ember-data/graph/-private';
import type Store from '@ember-data/store';
+import type { ModelSchema } from '@ember-data/store/types';
+import { DEPRECATE_NON_EXPLICIT_POLYMORPHISM } from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { FieldSchema, LegacyRelationshipSchema } from '@warp-drive/core-types/schema/fields';
+
+import { Model } from '../model';
+
+// A pile of soft-lies to deal with mixin APIs
+type ModelWithMixinApis = Model & {
+ __isMixin?: boolean;
+ __mixin: Mixin;
+ PrototypeMixin: Mixin;
+ detect: (mixin: Model | Mixin | ModelWithMixinApis) => boolean;
+ prototype: Model;
+ [Symbol.hasInstance](model: Model): true;
+};
+
+function assertModelSchemaIsModel(
+ schema: ModelSchema | Model | ModelWithMixinApis
+): asserts schema is ModelWithMixinApis {
+ assert(`Expected Schema to be an instance of Model`, schema instanceof Model);
+}
/*
Assert that `addedRecord` has a valid type so it can be added to the
@@ -24,6 +47,26 @@ let assertPolymorphicType: (
) => void;
if (DEBUG) {
+ const checkPolymorphic = function checkPolymorphic(modelClass: ModelSchema, addedModelClass: ModelSchema) {
+ assertModelSchemaIsModel(modelClass);
+ assertModelSchemaIsModel(addedModelClass);
+
+ if (modelClass.__isMixin) {
+ return (
+ modelClass.__mixin.detect(addedModelClass.PrototypeMixin) ||
+ // handle native class extension e.g. `class Post extends Model.extend(Commentable) {}`
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ modelClass.__mixin.detect(Object.getPrototypeOf(addedModelClass).PrototypeMixin)
+ );
+ }
+
+ return addedModelClass.prototype instanceof modelClass || modelClass.detect(addedModelClass);
+ };
+
+ const isRelationshipField = function isRelationshipField(meta: FieldSchema): meta is LegacyRelationshipSchema {
+ return meta.kind === 'hasMany' || meta.kind === 'belongsTo';
+ };
+
// eslint-disable-next-line @typescript-eslint/no-shadow
assertPolymorphicType = function assertPolymorphicType(
parentIdentifier: StableRecordIdentifier,
@@ -34,16 +77,45 @@ if (DEBUG) {
if (parentDefinition.inverseIsImplicit) {
return;
}
+ let asserted = false;
if (parentDefinition.isPolymorphic) {
const meta = store.schema.fields(addedIdentifier)?.get(parentDefinition.inverseKey);
assert(
- `Expected the schema for the field ${parentDefinition.inverseKey} on ${addedIdentifier.type} to be for a legacy relationship`,
- !meta || meta.kind === 'belongsTo' || meta.kind === 'hasMany'
- );
- assert(
- `The schema for the relationship '${parentDefinition.inverseKey}' on '${addedIdentifier.type}' type does not implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. The definition should specify 'as: "${parentDefinition.type}"' in options.`,
- meta?.options.as === parentDefinition.type
+ `Expected to find a relationship field schema for ${parentDefinition.inverseKey} on ${addedIdentifier.type} but none was found`,
+ meta && isRelationshipField(meta)
);
+
+ if (!DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
+ assert(
+ `The schema for the relationship '${parentDefinition.inverseKey}' on '${addedIdentifier.type}' type does not implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. The definition should specify 'as: "${parentDefinition.type}"' in options.`,
+ meta.options.as === parentDefinition.type
+ );
+ } else if ((meta.options.as?.length ?? 0) > 0) {
+ asserted = true;
+ assert(
+ `The schema for the relationship '${parentDefinition.inverseKey}' on '${addedIdentifier.type}' type does not implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. The definition should specify 'as: "${parentDefinition.type}"' in options.`,
+ meta.options.as === parentDefinition.type
+ );
+ }
+
+ if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
+ if (!asserted) {
+ store = (store as unknown as { _store: Store })._store
+ ? (store as unknown as { _store: Store })._store
+ : store; // allow usage with storeWrapper
+ const addedModelName = addedIdentifier.type;
+ const parentModelName = parentIdentifier.type;
+ const key = parentDefinition.key;
+ const relationshipModelName = parentDefinition.type;
+ const relationshipClass = store.modelFor(relationshipModelName);
+ const addedClass = store.modelFor(addedModelName);
+
+ const assertionMessage = `The '${addedModelName}' type does not implement '${relationshipModelName}' and thus cannot be assigned to the '${key}' relationship in '${parentModelName}'. Make it a descendant of '${relationshipModelName}' or use a mixin of the same name.`;
+ const isPolymorphic = checkPolymorphic(relationshipClass, addedClass);
+
+ assert(assertionMessage, isPolymorphic);
+ }
+ }
}
};
}
diff --git a/packages/model/src/-private/deprecated-promise-proxy.ts b/packages/model/src/-private/deprecated-promise-proxy.ts
new file mode 100644
index 00000000000..0adb72058ae
--- /dev/null
+++ b/packages/model/src/-private/deprecated-promise-proxy.ts
@@ -0,0 +1,73 @@
+import { deprecate } from '@ember/debug';
+import { get } from '@ember/object';
+
+import { DEBUG } from '@warp-drive/build-config/env';
+
+import { PromiseObject } from './promise-proxy-base';
+
+function promiseObject(promise: Promise): PromiseObject {
+ return PromiseObject.create({ promise }) as PromiseObject;
+}
+
+// constructor is accessed in some internals but not including it in the copyright for the deprecation
+const ALLOWABLE_METHODS = ['constructor', 'then', 'catch', 'finally'];
+const ALLOWABLE_PROPS = ['__ec_yieldable__', '__ec_cancel__'];
+const PROXIED_OBJECT_PROPS = ['content', 'isPending', 'isSettled', 'isRejected', 'isFulfilled', 'promise', 'reason'];
+
+const ProxySymbolString = String(Symbol.for('PROXY_CONTENT'));
+
+export function deprecatedPromiseObject(promise: Promise): PromiseObject {
+ const promiseObjectProxy: PromiseObject = promiseObject(promise);
+ if (!DEBUG) {
+ return promiseObjectProxy;
+ }
+ const handler = {
+ get(target: object, prop: string, receiver: object): unknown {
+ if (typeof prop === 'symbol') {
+ if (String(prop) === ProxySymbolString) {
+ return;
+ }
+ return Reflect.get(target, prop, receiver);
+ }
+
+ if (prop === 'constructor') {
+ return target.constructor;
+ }
+
+ if (ALLOWABLE_PROPS.includes(prop)) {
+ return target[prop];
+ }
+
+ if (!ALLOWABLE_METHODS.includes(prop)) {
+ deprecate(
+ `Accessing ${prop} is deprecated. The return type is being changed from PromiseObjectProxy to a Promise. The only available methods to access on this promise are .then, .catch and .finally`,
+ false,
+ {
+ id: 'ember-data:model-save-promise',
+ until: '5.0',
+ for: '@ember-data/store',
+ since: {
+ available: '4.4',
+ enabled: '4.4',
+ },
+ }
+ );
+ } else {
+ return (target[prop] as () => unknown).bind(target);
+ }
+
+ if (PROXIED_OBJECT_PROPS.includes(prop)) {
+ return target[prop];
+ }
+
+ const value: unknown = get(target, prop);
+ if (value && typeof value === 'function' && typeof value.bind === 'function') {
+ return value.bind(receiver);
+ }
+
+ return undefined;
+ },
+ };
+
+ return new Proxy(promiseObjectProxy, handler) as PromiseObject;
+}
diff --git a/packages/model/src/-private/has-many.ts b/packages/model/src/-private/has-many.ts
index 9a6fcb286c3..305ae73431c 100644
--- a/packages/model/src/-private/has-many.ts
+++ b/packages/model/src/-private/has-many.ts
@@ -1,11 +1,17 @@
/**
@module @ember-data/model
*/
-import { deprecate } from '@ember/debug';
+import { deprecate, inspect } from '@ember/debug';
import { computed } from '@ember/object';
import { dasherize, singularize } from '@ember-data/request-utils/string';
-import { DEPRECATE_NON_STRICT_TYPES } from '@warp-drive/build-config/deprecations';
+import {
+ DEPRECATE_NON_STRICT_TYPES,
+ DEPRECATE_RELATIONSHIPS_WITHOUT_ASYNC,
+ DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE,
+ DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE,
+ DISABLE_6X_DEPRECATIONS,
+} from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { TypeFromInstance } from '@warp-drive/core-types/record';
@@ -17,12 +23,18 @@ import type { MinimalLegacyRecord } from './model-methods';
import { isElementDescriptor } from './util';
function normalizeType(type: string) {
+ if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE) {
+ if (!type) {
+ return;
+ }
+ }
+
if (DEPRECATE_NON_STRICT_TYPES) {
const result = singularize(dasherize(type));
deprecate(
`The resource type '${type}' is not normalized. Update your application code to use '${result}' instead of '${type}'.`,
- result === type,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS ? true : result === type,
{
id: 'ember-data:deprecate-non-strict-types',
until: '6.0',
@@ -44,7 +56,66 @@ function _hasMany(
type: string,
options: RelationshipOptions
): RelationshipDecorator {
- assert(`Expected hasMany options.async to be a boolean`, options && typeof options.async === 'boolean');
+ if (DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE) {
+ if (typeof type !== 'string' || !type.length) {
+ deprecate(
+ 'hasMany(, ) must specify the string type of the related resource as the first parameter',
+ false,
+ {
+ id: 'ember-data:deprecate-non-strict-relationships',
+ for: 'ember-data',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ }
+ );
+ if (typeof type === 'object') {
+ options = type;
+ type = undefined as unknown as string;
+ }
+
+ assert(
+ `The first argument to hasMany must be a string representing a model type key, not an instance of ${inspect(
+ type
+ )}. E.g., to define a relation to the Comment model, use hasMany('comment')`,
+ typeof type === 'string' || typeof type === 'undefined'
+ );
+ }
+ }
+
+ if (DEPRECATE_RELATIONSHIPS_WITHOUT_ASYNC) {
+ if (!options || typeof options.async !== 'boolean') {
+ options = options || {};
+ if (!('async' in options)) {
+ // @ts-expect-error the inbound signature is strict to convince the user to use the non-deprecated signature
+ options.async = true;
+ }
+ deprecate('hasMany(, ) must specify options.async as either `true` or `false`.', false, {
+ id: 'ember-data:deprecate-non-strict-relationships',
+ for: 'ember-data',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ });
+ } else {
+ assert(`Expected hasMany options.async to be a boolean`, options && typeof options.async === 'boolean');
+ }
+ } else {
+ assert(`Expected hasMany options.async to be a boolean`, options && typeof options.async === 'boolean');
+ }
+
+ if (DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE) {
+ if (options.inverse !== null && (typeof options.inverse !== 'string' || options.inverse.length === 0)) {
+ deprecate(
+ 'hasMany(, ) must specify options.inverse as either `null` or the name of the field on the related resource type.',
+ false,
+ {
+ id: 'ember-data:deprecate-non-strict-relationships',
+ for: 'ember-data',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ }
+ );
+ }
+ }
// Metadata about relationships is stored on the meta of
// the relationship. This is used for introspection and
@@ -266,11 +337,17 @@ export function hasMany(
type?: TypeFromInstance>,
options?: RelationshipOptions
): RelationshipDecorator {
- if (DEBUG) {
+ if (!DEPRECATE_RELATIONSHIPS_WITHOUT_TYPE) {
assert(
- `hasMany must be invoked with a type and options. Did you mean \`@hasMany(${type}, { async: false, inverse: null })\`?`,
+ `hasMany must be invoked with a type and options. Did you mean \`@hasMany(, { async: false, inverse: null })\`?`,
!isElementDescriptor(arguments as unknown as unknown[])
);
+ return _hasMany(type!, options!);
+ } else {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return isElementDescriptor(arguments as unknown as any[])
+ ? // @ts-expect-error the inbound signature is strict to convince the user to use the non-deprecated signature
+ (_hasMany()(...arguments) as RelationshipDecorator)
+ : _hasMany(type!, options!);
}
- return _hasMany(type!, options!);
}
diff --git a/packages/model/src/-private/legacy-relationships-support.ts b/packages/model/src/-private/legacy-relationships-support.ts
index 242529d92e6..ef6fe4831f4 100644
--- a/packages/model/src/-private/legacy-relationships-support.ts
+++ b/packages/model/src/-private/legacy-relationships-support.ts
@@ -1,3 +1,5 @@
+import { deprecate } from '@ember/debug';
+
import { dependencySatisfies, importSync, macroCondition } from '@embroider/macros';
import type { CollectionEdge, Graph, GraphEdge, ResourceEdge, UpgradedMeta } from '@ember-data/graph/-private';
@@ -13,6 +15,7 @@ import {
storeFor,
} from '@ember-data/store/-private';
import type { BaseFinderOptions } from '@ember-data/store/types';
+import { DEPRECATE_PROMISE_PROXIES } from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
@@ -717,6 +720,30 @@ function extractIdentifierFromRecord(record: PromiseProxyRecord | OpaqueRecordIn
return null;
}
+ if (DEPRECATE_PROMISE_PROXIES) {
+ if (isPromiseRecord(record)) {
+ const content = record.content;
+ assert(
+ 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.',
+ content !== undefined
+ );
+ deprecate(
+ `You passed in a PromiseProxy to a Relationship API that now expects a resolved value. await the value before setting it.`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-proxies',
+ until: '5.0',
+ since: {
+ enabled: '4.7',
+ available: '4.7',
+ },
+ for: 'ember-data',
+ }
+ );
+ return content ? recordIdentifierFor(content) : null;
+ }
+ }
+
return recordIdentifierFor(record);
}
@@ -758,3 +785,7 @@ export function areAllInverseRecordsLoaded(store: Store, resource: InnerRelation
function isBelongsTo(relationship: GraphEdge): relationship is ResourceEdge {
return relationship.definition.kind === 'belongsTo';
}
+
+function isPromiseRecord(record: PromiseProxyRecord | OpaqueRecordInstance): record is PromiseProxyRecord {
+ return typeof record === 'object' && !!record && 'then' in record;
+}
diff --git a/packages/model/src/-private/many-array.ts b/packages/model/src/-private/many-array.ts
index c514e4860ce..01c73832264 100644
--- a/packages/model/src/-private/many-array.ts
+++ b/packages/model/src/-private/many-array.ts
@@ -17,7 +17,11 @@ import {
import type { BaseFinderOptions, ModelSchema } from '@ember-data/store/types';
import type { Signal } from '@ember-data/tracking/-private';
import { addToTransaction } from '@ember-data/tracking/-private';
-import { DEPRECATE_MANY_ARRAY_DUPLICATES } from '@warp-drive/build-config/deprecations';
+import {
+ DEPRECATE_MANY_ARRAY_DUPLICATES,
+ DEPRECATE_PROMISE_PROXIES,
+ DISABLE_6X_DEPRECATIONS,
+} from '@warp-drive/build-config/deprecations';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
import type { Cache } from '@warp-drive/core-types/cache';
@@ -317,11 +321,12 @@ export class RelatedCollection extends LiveArray {
// dedupe
const current = new Set(adds);
const unique = Array.from(current);
+ const uniqueIdentifiers = Array.from(new Set(newValues));
const newArgs = ([start, deleteCount] as unknown[]).concat(unique);
const result = Reflect.apply(target[prop], receiver, newArgs) as OpaqueRecordInstance[];
- mutateReplaceRelatedRecords(this, extractIdentifiersFromRecords(unique), _SIGNAL);
+ mutateReplaceRelatedRecords(this, uniqueIdentifiers, _SIGNAL);
return result;
}
@@ -485,10 +490,39 @@ function extractIdentifiersFromRecords(records: OpaqueRecordInstance[]): StableR
}
function extractIdentifierFromRecord(recordOrPromiseRecord: PromiseProxyRecord | OpaqueRecordInstance) {
+ if (DEPRECATE_PROMISE_PROXIES) {
+ if (isPromiseRecord(recordOrPromiseRecord)) {
+ const content = recordOrPromiseRecord.content;
+ assert(
+ 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo relationship.',
+ content !== undefined && content !== null
+ );
+ deprecate(
+ `You passed in a PromiseProxy to a Relationship API that now expects a resolved value. await the value before setting it.`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-proxies',
+ until: '5.0',
+ since: {
+ enabled: '4.7',
+ available: '4.7',
+ },
+ for: 'ember-data',
+ }
+ );
+ assertRecordPassedToHasMany(content);
+ return recordIdentifierFor(content);
+ }
+ }
+
assertRecordPassedToHasMany(recordOrPromiseRecord);
return recordIdentifierFor(recordOrPromiseRecord);
}
+function isPromiseRecord(record: PromiseProxyRecord | OpaqueRecordInstance): record is PromiseProxyRecord {
+ return Boolean(typeof record === 'object' && record && 'then' in record);
+}
+
function assertNoDuplicates(
collection: RelatedCollection,
target: StableRecordIdentifier[],
@@ -511,7 +545,7 @@ function assertNoDuplicates(
.map((r) => (isStableIdentifier(r) ? r.lid : recordIdentifierFor(r).lid))
.sort((a, b) => a.localeCompare(b))
.join('\n\t- ')}`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-many-array-duplicates',
for: 'ember-data',
diff --git a/packages/model/src/-private/model-methods.ts b/packages/model/src/-private/model-methods.ts
index 8af6b3cba97..ed8b690f087 100644
--- a/packages/model/src/-private/model-methods.ts
+++ b/packages/model/src/-private/model-methods.ts
@@ -5,10 +5,12 @@ import { upgradeStore } from '@ember-data/legacy-compat/-private';
import type Store from '@ember-data/store';
import { recordIdentifierFor } from '@ember-data/store';
import { peekCache } from '@ember-data/store/-private';
+import { DEPRECATE_SAVE_PROMISE_ACCESS } from '@warp-drive/build-config/deprecations';
import { assert } from '@warp-drive/build-config/macros';
import type { ChangedAttributesHash } from '@warp-drive/core-types/cache';
import { RecordStore } from '@warp-drive/core-types/symbols';
+import { deprecatedPromiseObject } from './deprecated-promise-proxy';
import type { Errors } from './errors';
import { lookupLegacySupport } from './legacy-relationships-support';
import type RecordState from './record-state';
@@ -88,6 +90,10 @@ export function reload(this: T, options: Record(this: T, options?: Record(this: T, options?:
return Promise.resolve(this);
}
return this.save(options).then((_) => {
+ // run(() => {
this.unloadRecord();
+ // });
return this;
});
}
diff --git a/packages/model/src/-private/model.ts b/packages/model/src/-private/model.ts
index c003b428c6a..ea2eff41537 100644
--- a/packages/model/src/-private/model.ts
+++ b/packages/model/src/-private/model.ts
@@ -2,6 +2,7 @@
@module @ember-data/model
*/
+import { deprecate, warn } from '@ember/debug';
import EmberObject from '@ember/object';
import type { Snapshot } from '@ember-data/legacy-compat/-private';
@@ -11,6 +12,12 @@ import { recordIdentifierFor, storeFor } from '@ember-data/store';
import { coerceId } from '@ember-data/store/-private';
import { compat } from '@ember-data/tracking';
import { defineSignal } from '@ember-data/tracking/-private';
+import {
+ DEPRECATE_EARLY_STATIC,
+ DEPRECATE_MODEL_REOPEN,
+ DEPRECATE_NON_EXPLICIT_POLYMORPHISM,
+ DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE,
+} from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
@@ -38,6 +45,7 @@ import notifyChanges from './notify-changes';
import RecordState, { notifySignal, tagged } from './record-state';
import type BelongsToReference from './references/belongs-to';
import type HasManyReference from './references/has-many';
+import { relationshipFromMeta } from './relationship-meta';
import type {
_MaybeBelongsToFields,
isSubClass,
@@ -1168,22 +1176,49 @@ class Model extends EmberObject implements MinimalLegacyRecord {
@param {store} store an instance of Store
@return {Model} the type of the relationship, or undefined
*/
- static typeForRelationship(name: string, store: Store) {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ static typeForRelationship(name: string, store: Store): typeof Model | undefined {
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const relationship = this.relationshipsByName.get(name);
+ // @ts-expect-error
return relationship && store.modelFor(relationship.type);
}
@computeOnce
static get inverseMap(): Record {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
return Object.create(null) as Record;
}
@@ -1221,10 +1256,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
@return {Object} the inverse relationship, or null
*/
static inverseFor(name: string, store: Store): LegacyRelationshipSchema | null {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const inverseMap = this.inverseMap;
if (inverseMap[name]) {
return inverseMap[name];
@@ -1237,10 +1285,27 @@ class Model extends EmberObject implements MinimalLegacyRecord {
//Calculate the inverse, ignoring the cache
static _findInverseFor(name: string, store: Store): LegacyRelationshipSchema | null {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
+
+ if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
+ return legacyFindInverseFor(this, name, store);
+ }
const relationship = this.relationshipsByName.get(name)!;
assert(`No relationship named '${name}' on '${this.modelName}' exists.`, relationship);
@@ -1322,10 +1387,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
@computeOnce
static get relationships(): Map {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const map = new Map();
const relationshipsByName = this.relationshipsByName;
@@ -1380,10 +1458,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
*/
@computeOnce
static get relationshipNames() {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const names: { hasMany: string[]; belongsTo: string[] } = {
hasMany: [],
belongsTo: [],
@@ -1433,10 +1524,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
*/
@computeOnce
static get relatedTypes(): string[] {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const types: string[] = [];
@@ -1496,10 +1600,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
*/
@computeOnce
static get relationshipsByName(): Map {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const map = new Map();
const rels = this.relationshipsObject;
const relationships = Object.keys(rels);
@@ -1516,10 +1633,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
@computeOnce
static get relationshipsObject(): Record {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const relationships = Object.create(null) as Record;
const modelName = this.modelName;
@@ -1530,7 +1660,10 @@ class Model extends EmberObject implements MinimalLegacyRecord {
// TODO deprecate key being here
(meta as unknown as { key: string }).key = name;
meta.name = name;
- relationships[name] = meta;
+ const parentModelName = meta.options?.as ?? modelName;
+ relationships[name] = DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE
+ ? relationshipFromMeta(meta, parentModelName)
+ : meta;
assert(`Expected options in meta`, meta.options && typeof meta.options === 'object');
assert(
@@ -1584,10 +1717,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
*/
@computeOnce
static get fields(): Map {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const map = new Map();
this.eachComputedProperty((name, meta) => {
@@ -1620,10 +1766,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
) => void,
binding?: T
): void {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
this.relationshipsByName.forEach((relationship, name) => {
callback.call(binding, name as MaybeRelationshipFields, relationship);
@@ -1643,10 +1802,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
@param {any} binding the value to which the callback's `this` should be bound
*/
static eachRelatedType(callback: (this: T | undefined, type: string) => void, binding?: T) {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const relationshipTypes = this.relatedTypes;
@@ -1666,10 +1838,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
knownSide: LegacyRelationshipSchema,
store: Store
): 'oneToOne' | 'oneToMany' | 'manyToOne' | 'manyToMany' | 'oneToNone' | 'manyToNone' {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const knownKey = knownSide.name;
const knownKind = knownSide.kind;
@@ -1730,10 +1915,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
*/
@computeOnce
static get attributes(): Map {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const map = new Map();
@@ -1795,10 +1993,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
*/
@computeOnce
static get transformedAttributes() {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
const map = new Map();
@@ -1859,10 +2070,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
callback: (this: T | undefined, key: MaybeAttrFields, attribute: LegacyAttributeField) => void,
binding?: T
): void {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
this.attributes.forEach((meta, name) => {
callback.call(binding, name as MaybeAttrFields, meta);
@@ -1918,10 +2142,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
callback: (this: T | undefined, key: Exclude, type: string) => void,
binding?: T
): void {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
this.transformedAttributes.forEach((type: string, name) => {
callback.call(binding, name as Exclude, type);
@@ -1936,10 +2173,23 @@ class Model extends EmberObject implements MinimalLegacyRecord {
@static
*/
static toString() {
- assert(
- `Accessing schema information on Models without looking up the model via the store is disallowed.`,
- this.modelName
- );
+ if (DEPRECATE_EARLY_STATIC) {
+ deprecate(
+ `Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
+ Boolean(this.modelName),
+ {
+ id: 'ember-data:deprecate-early-static',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ } else {
+ assert(
+ `Accessing schema information on Models without looking up the model via the store is disallowed.`,
+ this.modelName
+ );
+ }
return `model:${this.modelName}`;
}
@@ -2016,8 +2266,40 @@ if (DEBUG) {
}
};
- delete (Model as unknown as { reopen: unknown }).reopen;
- delete (Model as unknown as { reopenClass: unknown }).reopenClass;
+ if (DEPRECATE_MODEL_REOPEN) {
+ // eslint-disable-next-line @typescript-eslint/unbound-method
+ const originalReopen = Model.reopen;
+ const originalReopenClass = Model.reopenClass;
+
+ // @ts-expect-error Intentional override
+ Model.reopen = function deprecatedReopen() {
+ deprecate(`Model.reopen is deprecated. Use Foo extends Model to extend your class instead.`, false, {
+ id: 'ember-data:deprecate-model-reopen',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ });
+ return originalReopen.call(this, ...arguments);
+ };
+
+ // @ts-expect-error Intentional override
+ Model.reopenClass = function deprecatedReopenClass() {
+ deprecate(
+ `Model.reopenClass is deprecated. Use Foo extends Model to add static methods and properties to your class instead.`,
+ false,
+ {
+ id: 'ember-data:deprecate-model-reopenclass',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ return originalReopenClass.call(this, ...arguments);
+ };
+ } else {
+ delete (Model as unknown as { reopen: unknown }).reopen;
+ delete (Model as unknown as { reopenClass: unknown }).reopenClass;
+ }
}
export { Model };
@@ -2030,3 +2312,218 @@ function isRelationshipSchema(meta: unknown): meta is LegacyRelationshipSchema {
function isAttributeSchema(meta: unknown): meta is LegacyAttributeField {
return typeof meta === 'object' && meta !== null && 'kind' in meta && meta.kind === 'attribute';
}
+
+function findPossibleInverses(
+ Klass: typeof Model,
+ inverseType: typeof Model,
+ name: string,
+ relationshipsSoFar?: LegacyRelationshipSchema[]
+) {
+ const possibleRelationships = relationshipsSoFar || [];
+
+ const relationshipMap = inverseType.relationships;
+ if (!relationshipMap) {
+ return possibleRelationships;
+ }
+
+ const relationshipsForType = relationshipMap.get(Klass.modelName);
+ const relationships = Array.isArray(relationshipsForType)
+ ? relationshipsForType.filter((relationship) => {
+ const optionsForRelationship = relationship.options;
+
+ if (!optionsForRelationship.inverse && optionsForRelationship.inverse !== null) {
+ return true;
+ }
+
+ return name === optionsForRelationship.inverse;
+ })
+ : null;
+
+ if (relationships) {
+ // eslint-disable-next-line prefer-spread
+ possibleRelationships.push.apply(possibleRelationships, relationships);
+ }
+
+ //Recurse to support polymorphism
+ if (Klass.superclass) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
+ findPossibleInverses(Klass.superclass, inverseType, name, possibleRelationships);
+ }
+
+ return possibleRelationships;
+}
+
+function legacyFindInverseFor(Klass: typeof Model, name: string, store: Store) {
+ const relationship = Klass.relationshipsByName.get(name);
+ assert(`No relationship named '${name}' on '${Klass.modelName}' exists.`, relationship);
+
+ const { options } = relationship;
+ const isPolymorphic = options.polymorphic;
+
+ //If inverse is manually specified to be null, like `comments: hasMany('message', { inverse: null })`
+ const isExplicitInverseNull = options.inverse === null;
+ const isAbstractType = !isExplicitInverseNull && isPolymorphic && !store.schema.hasResource(relationship);
+
+ if (isExplicitInverseNull || isAbstractType) {
+ assert(
+ `No schema for the abstract type '${relationship.type}' for the polymorphic relationship '${name}' on '${Klass.modelName}' was provided by the SchemaDefinitionService.`,
+ !isPolymorphic || isExplicitInverseNull
+ );
+ return null;
+ }
+
+ let fieldOnInverse: string | null | undefined;
+ let inverseKind: 'belongsTo' | 'hasMany';
+ let inverseRelationship: LegacyRelationshipSchema | undefined;
+ let inverseOptions: LegacyRelationshipSchema['options'] | undefined;
+ const inverseSchema = Klass.typeForRelationship(name, store);
+ assert(`No model was found for '${relationship.type}'`, inverseSchema);
+
+ // if the type does not exist and we are not polymorphic
+ //If inverse is specified manually, return the inverse
+ if (options.inverse !== undefined) {
+ fieldOnInverse = options.inverse!;
+ inverseRelationship = inverseSchema?.relationshipsByName.get(fieldOnInverse);
+
+ assert(
+ `We found no field named '${fieldOnInverse}' on the schema for '${inverseSchema.modelName}' to be the inverse of the '${name}' relationship on '${Klass.modelName}'. This is most likely due to a missing field on your model definition.`,
+ inverseRelationship
+ );
+
+ // TODO probably just return the whole inverse here
+
+ inverseKind = inverseRelationship.kind;
+
+ inverseOptions = inverseRelationship.options;
+ } else {
+ //No inverse was specified manually, we need to use a heuristic to guess one
+ const parentModelName = relationship.options?.as ?? Klass.modelName;
+ if (relationship.type === parentModelName) {
+ warn(
+ `Detected a reflexive relationship named '${name}' on the schema for '${relationship.type}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`,
+ false,
+ {
+ id: 'ds.model.reflexive-relationship-without-inverse',
+ }
+ );
+ }
+
+ let possibleRelationships = findPossibleInverses(Klass, inverseSchema, name);
+
+ if (possibleRelationships.length === 0) {
+ return null;
+ }
+
+ if (DEBUG) {
+ const filteredRelationships = possibleRelationships.filter((possibleRelationship) => {
+ const optionsForRelationship = possibleRelationship.options;
+ return name === optionsForRelationship.inverse;
+ });
+
+ assert(
+ "You defined the '" +
+ name +
+ "' relationship on " +
+ String(Klass) +
+ ', but you defined the inverse relationships of type ' +
+ inverseSchema.toString() +
+ ' multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses',
+ filteredRelationships.length < 2
+ );
+ }
+
+ const explicitRelationship = possibleRelationships.find((rel) => rel.options?.inverse === name);
+ if (explicitRelationship) {
+ possibleRelationships = [explicitRelationship];
+ }
+
+ assert(
+ "You defined the '" +
+ name +
+ "' relationship on " +
+ String(Klass) +
+ ', but multiple possible inverse relationships of type ' +
+ String(Klass) +
+ ' were found on ' +
+ String(inverseSchema) +
+ '. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses',
+ possibleRelationships.length === 1
+ );
+
+ fieldOnInverse = possibleRelationships[0].name;
+ inverseKind = possibleRelationships[0].kind;
+ inverseOptions = possibleRelationships[0].options;
+ }
+
+ assert(`inverseOptions should be set by now`, inverseOptions);
+
+ // ensure inverse is properly configured
+ if (DEBUG) {
+ if (isPolymorphic) {
+ if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
+ if (!inverseOptions.as) {
+ deprecate(
+ `Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${fieldOnInverse}' on type '${inverseSchema.modelName}' is misconfigured.`,
+ false,
+ {
+ id: 'ember-data:non-explicit-relationships',
+ since: { enabled: '4.7', available: '4.7' },
+ until: '5.0',
+ for: 'ember-data',
+ }
+ );
+ }
+ } else {
+ assert(
+ `Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${fieldOnInverse}' on type '${inverseSchema.modelName}' is misconfigured.`,
+ inverseOptions.as
+ );
+ assert(
+ `options.as should match the expected type of the polymorphic relationship. Expected field '${fieldOnInverse}' on type '${inverseSchema.modelName}' to specify '${relationship.type}' but found '${inverseOptions.as}'`,
+ !!inverseOptions.as && relationship.type === inverseOptions.as
+ );
+ }
+ }
+ }
+
+ // ensure we are properly configured
+ if (DEBUG) {
+ if (inverseOptions.polymorphic) {
+ if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
+ if (!options.as) {
+ deprecate(
+ `Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${name}' on type '${Klass.modelName}' is misconfigured.`,
+ false,
+ {
+ id: 'ember-data:non-explicit-relationships',
+ since: { enabled: '4.7', available: '4.7' },
+ until: '5.0',
+ for: 'ember-data',
+ }
+ );
+ }
+ } else {
+ assert(
+ `Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${name}' on type '${Klass.modelName}' is misconfigured.`,
+ options.as
+ );
+ assert(
+ `options.as should match the expected type of the polymorphic relationship. Expected field '${name}' on type '${Klass.modelName}' to specify '${inverseRelationship!.type}' but found '${options.as}'`,
+ !!options.as && inverseRelationship!.type === options.as
+ );
+ }
+ }
+ }
+
+ assert(
+ `The ${inverseSchema.modelName}:${fieldOnInverse} relationship declares 'inverse: null', but it was resolved as the inverse for ${Klass.modelName}:${name}.`,
+ inverseOptions.inverse !== null
+ );
+
+ return {
+ type: inverseSchema.modelName,
+ name: fieldOnInverse,
+ kind: inverseKind,
+ options: inverseOptions,
+ };
+}
diff --git a/packages/model/src/-private/promise-many-array.ts b/packages/model/src/-private/promise-many-array.ts
index 8aa0873ac0b..7fe925d9023 100644
--- a/packages/model/src/-private/promise-many-array.ts
+++ b/packages/model/src/-private/promise-many-array.ts
@@ -1,7 +1,18 @@
+import ArrayMixin, { NativeArray } from '@ember/array';
+import type ArrayProxy from '@ember/array/proxy';
+import { deprecate } from '@ember/debug';
+import Ember from 'ember';
+
+import type { CreateRecordProperties } from '@ember-data/store/-private';
import type { BaseFinderOptions } from '@ember-data/store/types';
import { compat } from '@ember-data/tracking';
import { defineSignal } from '@ember-data/tracking/-private';
-import { DEPRECATE_COMPUTED_CHAINS } from '@warp-drive/build-config/deprecations';
+import {
+ DEPRECATE_A_USAGE,
+ DEPRECATE_COMPUTED_CHAINS,
+ DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS,
+} from '@warp-drive/build-config/deprecations';
+import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { RelatedCollection as ManyArray } from './many-array';
@@ -31,16 +42,46 @@ export interface HasManyProxyCreateArgs {
@class PromiseManyArray
@public
*/
+export interface PromiseManyArray extends Omit, 'destroy' | 'forEach'> {
+ createRecord(hash: CreateRecordProperties): T;
+ reload(options: Omit): PromiseManyArray;
+}
export class PromiseManyArray {
declare promise: Promise> | null;
declare isDestroyed: boolean;
+ // @deprecated (isDestroyed is not deprecated)
+ declare isDestroying: boolean;
declare content: ManyArray | null;
constructor(promise: Promise>, content?: ManyArray) {
this._update(promise, content);
this.isDestroyed = false;
+ this.isDestroying = false;
+
+ if (DEPRECATE_A_USAGE) {
+ const meta = Ember.meta(this);
+ meta.hasMixin = (mixin: object) => {
+ deprecate(`Do not use A() on an EmberData PromiseManyArray`, false, {
+ id: 'ember-data:no-a-with-array-like',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ for: 'ember-data',
+ });
+ if (mixin === NativeArray || mixin === ArrayMixin) {
+ return true;
+ }
+ return false;
+ };
+ } else if (DEBUG) {
+ const meta = Ember.meta(this);
+ meta.hasMixin = (mixin: object) => {
+ assert(`Do not use A() on an EmberData PromiseManyArray`);
+ };
+ }
}
+ //---- Methods/Properties on ArrayProxy that we will keep as our API
+
/**
* Retrieve the length of the content
* @property length
@@ -156,6 +197,7 @@ export class PromiseManyArray {
//---- Methods on EmberObject that we should keep
destroy() {
+ this.isDestroying = true;
this.isDestroyed = true;
this.content = null;
this.promise = null;
@@ -217,7 +259,7 @@ if (DEPRECATE_COMPUTED_CHAINS) {
return this.content?.length && this.content;
},
};
- compat(desc);
+ compat(PromiseManyArray.prototype, '[]', desc);
// ember-source < 3.23 (e.g. 3.20 lts)
// requires that the tag `'[]'` be notified
@@ -227,6 +269,62 @@ if (DEPRECATE_COMPUTED_CHAINS) {
Object.defineProperty(PromiseManyArray.prototype, '[]', desc);
}
+if (DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS) {
+ PromiseManyArray.prototype.createRecord = function createRecord(
+ this: PromiseManyArray,
+ hash: CreateRecordProperties
+ ) {
+ deprecate(
+ `The createRecord method on ember-data's PromiseManyArray is deprecated. await the promise and work with the ManyArray directly.`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-many-array-behaviors',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ for: 'ember-data',
+ }
+ );
+ assert('You are trying to createRecord on an async manyArray before it has been created', this.content);
+ return this.content.createRecord(hash);
+ };
+
+ Object.defineProperty(PromiseManyArray.prototype, 'firstObject', {
+ get() {
+ deprecate(
+ `The firstObject property on ember-data's PromiseManyArray is deprecated. await the promise and work with the ManyArray directly.`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-many-array-behaviors',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ for: 'ember-data',
+ }
+ );
+
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
+ return this.content ? this.content.firstObject : undefined;
+ },
+ });
+
+ Object.defineProperty(PromiseManyArray.prototype, 'lastObject', {
+ get() {
+ deprecate(
+ `The lastObject property on ember-data's PromiseManyArray is deprecated. await the promise and work with the ManyArray directly.`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-many-array-behaviors',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ for: 'ember-data',
+ }
+ );
+
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
+ return this.content ? this.content.lastObject : undefined;
+ },
+ });
+}
+
function tapPromise(proxy: PromiseManyArray, promise: Promise>) {
proxy.isPending = true;
proxy.isSettled = false;
@@ -249,3 +347,105 @@ function tapPromise(proxy: PromiseManyArray, promise: Promise
}
);
}
+
+if (DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS) {
+ const EmberObjectMethods = [
+ 'addObserver',
+ 'cacheFor',
+ 'decrementProperty',
+ 'get',
+ 'getProperties',
+ 'incrementProperty',
+ 'notifyPropertyChange',
+ 'removeObserver',
+ 'set',
+ 'setProperties',
+ 'toggleProperty',
+ ];
+ EmberObjectMethods.forEach((method) => {
+ PromiseManyArray.prototype[method] = function delegatedMethod(...args) {
+ deprecate(
+ `The ${method} method on ember-data's PromiseManyArray is deprecated. await the promise and work with the ManyArray directly.`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-many-array-behaviors',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ for: 'ember-data',
+ }
+ );
+
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
+ return Ember[method](this, ...args);
+ };
+ });
+
+ const InheritedProxyMethods = [
+ 'addArrayObserver',
+ 'addObject',
+ 'addObjects',
+ 'any',
+ 'arrayContentDidChange',
+ 'arrayContentWillChange',
+ 'clear',
+ 'compact',
+ 'every',
+ 'filter',
+ 'filterBy',
+ 'find',
+ 'findBy',
+ 'getEach',
+ 'includes',
+ 'indexOf',
+ 'insertAt',
+ 'invoke',
+ 'isAny',
+ 'isEvery',
+ 'lastIndexOf',
+ 'map',
+ 'mapBy',
+ // TODO update RFC to note objectAt was deprecated (forEach was left for iteration)
+ 'objectAt',
+ 'objectsAt',
+ 'popObject',
+ 'pushObject',
+ 'pushObjects',
+ 'reduce',
+ 'reject',
+ 'rejectBy',
+ 'removeArrayObserver',
+ 'removeAt',
+ 'removeObject',
+ 'removeObjects',
+ 'replace',
+ 'reverseObjects',
+ 'setEach',
+ 'setObjects',
+ 'shiftObject',
+ 'slice',
+ 'sortBy',
+ 'toArray',
+ 'uniq',
+ 'uniqBy',
+ 'unshiftObject',
+ 'unshiftObjects',
+ 'without',
+ ];
+ InheritedProxyMethods.forEach((method) => {
+ PromiseManyArray.prototype[method] = function proxiedMethod(...args) {
+ deprecate(
+ `The ${method} method on ember-data's PromiseManyArray is deprecated. await the promise and work with the ManyArray directly.`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-many-array-behaviors',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ for: 'ember-data',
+ }
+ );
+ assert(`Cannot call ${method} before content is assigned.`, this.content);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
+ return this.content[method](...args);
+ };
+ });
+}
diff --git a/packages/model/src/-private/references/belongs-to.ts b/packages/model/src/-private/references/belongs-to.ts
index f5363c091f9..c3b227115e5 100644
--- a/packages/model/src/-private/references/belongs-to.ts
+++ b/packages/model/src/-private/references/belongs-to.ts
@@ -1,8 +1,11 @@
+import { deprecate } from '@ember/debug';
+
import type { Graph, ResourceEdge } from '@ember-data/graph/-private';
import type Store from '@ember-data/store';
import type { NotificationType } from '@ember-data/store';
import { cached, compat } from '@ember-data/tracking';
import { defineSignal } from '@ember-data/tracking/-private';
+import { DEPRECATE_PROMISE_PROXIES } from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
import type { StableExistingRecordIdentifier } from '@warp-drive/core-types/identifier';
@@ -477,7 +480,32 @@ export default class BelongsToReference<
@param {Boolean} [skipFetch] if `true`, do not attempt to fetch unloaded records
@return {Promise}
*/
- async push(doc: SingleResourceDocument, skipFetch?: boolean): Promise {
+ async push(
+ maybeDoc: SingleResourceDocument | Promise,
+ skipFetch?: boolean
+ ): Promise {
+ let doc: SingleResourceDocument = maybeDoc as SingleResourceDocument;
+ if (DEPRECATE_PROMISE_PROXIES) {
+ if ((maybeDoc as { then: unknown }).then) {
+ doc = await maybeDoc;
+ if (doc !== maybeDoc) {
+ deprecate(
+ `You passed in a Promise to a Reference API that now expects a resolved value. await the value before setting it.`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-proxies',
+ until: '5.0',
+ since: {
+ enabled: '4.7',
+ available: '4.7',
+ },
+ for: 'ember-data',
+ }
+ );
+ }
+ }
+ }
+
const { store } = this;
const isResourceData = doc.data && isMaybeResource(doc.data);
const added = isResourceData
diff --git a/packages/model/src/-private/references/has-many.ts b/packages/model/src/-private/references/has-many.ts
index 2b13820b149..b41ecfed519 100644
--- a/packages/model/src/-private/references/has-many.ts
+++ b/packages/model/src/-private/references/has-many.ts
@@ -1,9 +1,12 @@
+import { deprecate } from '@ember/debug';
+
import type { CollectionEdge, Graph } from '@ember-data/graph/-private';
import type Store from '@ember-data/store';
import type { NotificationType } from '@ember-data/store';
import type { BaseFinderOptions } from '@ember-data/store/types';
import { cached, compat } from '@ember-data/tracking';
import { defineSignal } from '@ember-data/tracking/-private';
+import { DEPRECATE_PROMISE_PROXIES } from '@warp-drive/build-config/deprecations';
import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
@@ -494,9 +497,31 @@ export default class HasManyReference<
@return {Promise}
*/
async push(
- doc: ExistingResourceObject[] | CollectionResourceDocument,
+ maybeDoc: ExistingResourceObject[] | CollectionResourceDocument,
skipFetch?: boolean
): Promise | void> {
+ let doc = maybeDoc;
+ if (DEPRECATE_PROMISE_PROXIES) {
+ if ((maybeDoc as unknown as { then: unknown }).then) {
+ doc = await (maybeDoc as unknown as Promise);
+ if (doc !== maybeDoc) {
+ deprecate(
+ `You passed in a Promise to a Reference API that now expects a resolved value. await the value before setting it.`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-proxies',
+ until: '5.0',
+ since: {
+ enabled: '4.7',
+ available: '4.7',
+ },
+ for: 'ember-data',
+ }
+ );
+ }
+ }
+ }
+
const { store } = this;
const dataDoc = Array.isArray(doc) ? { data: doc } : doc;
const isResourceData = Array.isArray(dataDoc.data) && dataDoc.data.length > 0 && isMaybeResource(dataDoc.data[0]);
diff --git a/packages/model/src/-private/relationship-meta.ts b/packages/model/src/-private/relationship-meta.ts
new file mode 100644
index 00000000000..e03a181c389
--- /dev/null
+++ b/packages/model/src/-private/relationship-meta.ts
@@ -0,0 +1,93 @@
+import { dasherize, singularize } from '@ember-data/request-utils/string';
+import type Store from '@ember-data/store';
+import { DEBUG } from '@warp-drive/build-config/env';
+import type { LegacyRelationshipSchema } from '@warp-drive/core-types/schema/fields';
+
+import type { Model } from './model';
+
+function typeForRelationshipMeta(meta: LegacyRelationshipSchema): string {
+ let modelName = dasherize(meta.type || meta.name);
+
+ if (meta.kind === 'hasMany') {
+ modelName = singularize(modelName);
+ }
+
+ return modelName;
+}
+
+function shouldFindInverse(relationshipMeta: LegacyRelationshipSchema): boolean {
+ const options = relationshipMeta.options;
+ return !(options && options.inverse === null);
+}
+
+class RelationshipDefinition {
+ declare _type: string;
+ declare __inverseKey: string | null;
+ declare __hasCalculatedInverse: boolean;
+ declare parentModelName: string;
+ declare inverseIsAsync: string | null;
+ declare meta: LegacyRelationshipSchema;
+
+ constructor(meta: LegacyRelationshipSchema, parentModelName: string) {
+ this._type = '';
+ this.__inverseKey = '';
+ this.__hasCalculatedInverse = false;
+ this.parentModelName = parentModelName;
+ this.meta = meta;
+ }
+
+ get kind(): 'belongsTo' | 'hasMany' {
+ return this.meta.kind;
+ }
+ get type(): string {
+ if (this._type) {
+ return this._type;
+ }
+ this._type = typeForRelationshipMeta(this.meta);
+ return this._type;
+ }
+ get options() {
+ return this.meta.options;
+ }
+ get name(): string {
+ return this.meta.name;
+ }
+
+ _inverseKey(store: Store, modelClass: typeof Model): string | null {
+ if (this.__hasCalculatedInverse === false) {
+ this._calculateInverse(store, modelClass);
+ }
+ return this.__inverseKey;
+ }
+
+ _calculateInverse(store: Store, modelClass: typeof Model): void {
+ this.__hasCalculatedInverse = true;
+ let inverseKey: string | null = null;
+ let inverse: LegacyRelationshipSchema | null = null;
+
+ if (shouldFindInverse(this.meta)) {
+ inverse = modelClass.inverseFor(this.name, store);
+ }
+ // TODO make this error again for the non-polymorphic case
+ if (DEBUG) {
+ if (!this.options.polymorphic) {
+ modelClass.typeForRelationship(this.name, store);
+ }
+ }
+
+ if (inverse) {
+ inverseKey = inverse.name;
+ } else {
+ inverseKey = null;
+ }
+ this.__inverseKey = inverseKey;
+ }
+}
+export type { RelationshipDefinition };
+
+export function relationshipFromMeta(
+ meta: LegacyRelationshipSchema,
+ parentModelName: string
+): LegacyRelationshipSchema {
+ return new RelationshipDefinition(meta, parentModelName) as unknown as LegacyRelationshipSchema;
+}
diff --git a/packages/model/src/-private/schema-provider.ts b/packages/model/src/-private/schema-provider.ts
index 88fe9563043..d906b9b29f2 100644
--- a/packages/model/src/-private/schema-provider.ts
+++ b/packages/model/src/-private/schema-provider.ts
@@ -3,7 +3,11 @@ import { deprecate } from '@ember/debug';
import type Store from '@ember-data/store';
import type { SchemaService } from '@ember-data/store/types';
-import { ENABLE_LEGACY_SCHEMA_SERVICE } from '@warp-drive/build-config/deprecations';
+import {
+ DEPRECATE_STRING_ARG_SCHEMAS,
+ DISABLE_6X_DEPRECATIONS,
+ ENABLE_LEGACY_SCHEMA_SERVICE,
+} from '@warp-drive/build-config/deprecations';
import { assert } from '@warp-drive/build-config/macros';
import type { RecordIdentifier, StableRecordIdentifier } from '@warp-drive/core-types/identifier';
import type { ObjectValue } from '@warp-drive/core-types/json/raw';
@@ -164,31 +168,60 @@ export class ModelSchemaProvider implements SchemaService {
if (ENABLE_LEGACY_SCHEMA_SERVICE) {
ModelSchemaProvider.prototype.doesTypeExist = function (type: string): boolean {
- deprecate(`Use \`schema.hasResource({ type })\` instead of \`schema.doesTypeExist(type)\``, false, {
- id: 'ember-data:schema-service-updates',
- until: '6.0',
- for: 'ember-data',
- since: {
- available: '4.13',
- enabled: '5.4',
- },
- });
+ deprecate(
+ `Use \`schema.hasResource({ type })\` instead of \`schema.doesTypeExist(type)\``,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
+ {
+ id: 'ember-data:schema-service-updates',
+ until: '6.0',
+ for: 'ember-data',
+ since: {
+ available: '4.13',
+ enabled: '5.4',
+ },
+ }
+ );
return this.hasResource({ type });
};
ModelSchemaProvider.prototype.attributesDefinitionFor = function (
resource: RecordIdentifier | { type: string }
): AttributesSchema {
- deprecate(`Use \`schema.fields({ type })\` instead of \`schema.attributesDefinitionFor({ type })\``, false, {
- id: 'ember-data:schema-service-updates',
- until: '6.0',
- for: 'ember-data',
- since: {
- available: '4.13',
- enabled: '5.4',
- },
- });
- const type = normalizeModelName(resource.type);
+ let rawType: string;
+ if (DEPRECATE_STRING_ARG_SCHEMAS) {
+ if (typeof resource === 'string') {
+ deprecate(
+ `relationshipsDefinitionFor expects either a record identifier or an argument of shape { type: string }, received a string.`,
+ false,
+ {
+ id: 'ember-data:deprecate-string-arg-schemas',
+ for: 'ember-data',
+ until: '5.0',
+ since: { enabled: '4.5', available: '4.5' },
+ }
+ );
+ rawType = resource;
+ } else {
+ rawType = resource.type;
+ }
+ } else {
+ rawType = resource.type;
+ }
+
+ deprecate(
+ `Use \`schema.fields({ type })\` instead of \`schema.attributesDefinitionFor({ type })\``,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
+ {
+ id: 'ember-data:schema-service-updates',
+ until: '6.0',
+ for: 'ember-data',
+ since: {
+ available: '4.13',
+ enabled: '5.4',
+ },
+ }
+ );
+ const type = normalizeModelName(rawType);
if (!this._schemas.has(type)) {
this._loadModelSchema(type);
@@ -200,16 +233,41 @@ if (ENABLE_LEGACY_SCHEMA_SERVICE) {
ModelSchemaProvider.prototype.relationshipsDefinitionFor = function (
resource: RecordIdentifier | { type: string }
): RelationshipsSchema {
- deprecate(`Use \`schema.fields({ type })\` instead of \`schema.relationshipsDefinitionFor({ type })\``, false, {
- id: 'ember-data:schema-service-updates',
- until: '6.0',
- for: 'ember-data',
- since: {
- available: '4.13',
- enabled: '5.4',
- },
- });
- const type = normalizeModelName(resource.type);
+ let rawType: string;
+ if (DEPRECATE_STRING_ARG_SCHEMAS) {
+ if (typeof resource === 'string') {
+ deprecate(
+ `relationshipsDefinitionFor expects either a record identifier or an argument of shape { type: string }, received a string.`,
+ false,
+ {
+ id: 'ember-data:deprecate-string-arg-schemas',
+ for: 'ember-data',
+ until: '5.0',
+ since: { enabled: '4.5', available: '4.5' },
+ }
+ );
+ rawType = resource;
+ } else {
+ rawType = resource.type;
+ }
+ } else {
+ rawType = resource.type;
+ }
+
+ deprecate(
+ `Use \`schema.fields({ type })\` instead of \`schema.relationshipsDefinitionFor({ type })\``,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
+ {
+ id: 'ember-data:schema-service-updates',
+ until: '6.0',
+ for: 'ember-data',
+ since: {
+ available: '4.13',
+ enabled: '5.4',
+ },
+ }
+ );
+ const type = normalizeModelName(rawType);
if (!this._schemas.has(type)) {
this._loadModelSchema(type);
diff --git a/packages/model/src/-private/util.ts b/packages/model/src/-private/util.ts
index b6f924f360d..b9f0380dde3 100644
--- a/packages/model/src/-private/util.ts
+++ b/packages/model/src/-private/util.ts
@@ -1,7 +1,7 @@
import { deprecate } from '@ember/debug';
import { dasherize } from '@ember-data/request-utils/string';
-import { DEPRECATE_NON_STRICT_TYPES } from '@warp-drive/build-config/deprecations';
+import { DEPRECATE_NON_STRICT_TYPES, DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
export type DecoratorPropertyDescriptor = (PropertyDescriptor & { initializer?: () => unknown }) | undefined;
@@ -31,7 +31,7 @@ export function normalizeModelName(type: string): string {
deprecate(
`The resource type '${type}' is not normalized. Update your application code to use '${result}' instead of '${type}'.`,
- result === type,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS ? true : result === type,
{
id: 'ember-data:deprecate-non-strict-types',
until: '6.0',
diff --git a/packages/model/vite.config.mjs b/packages/model/vite.config.mjs
index 0bd74020510..c06cb9e5c61 100644
--- a/packages/model/vite.config.mjs
+++ b/packages/model/vite.config.mjs
@@ -1,6 +1,7 @@
import { createConfig } from '@warp-drive/internal-config/vite/config.js';
export const externals = [
+ 'ember',
'@ember/service',
'@ember/debug',
'@ember/object/computed',
diff --git a/packages/request-utils/package.json b/packages/request-utils/package.json
index 2ff1dc08010..eb27c28be46 100644
--- a/packages/request-utils/package.json
+++ b/packages/request-utils/package.json
@@ -1,7 +1,7 @@
{
"name": "@ember-data/request-utils",
"description": "Request Building Utilities for use with EmberData",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"private": false,
"license": "MIT",
"author": "Chris Thoburn ",
diff --git a/packages/request-utils/src/deprecation-support.ts b/packages/request-utils/src/deprecation-support.ts
index 15a4d9ab05c..d0229dc3906 100644
--- a/packages/request-utils/src/deprecation-support.ts
+++ b/packages/request-utils/src/deprecation-support.ts
@@ -2,7 +2,7 @@ import { deprecate } from '@ember/debug';
import { dependencySatisfies, importSync, macroCondition } from '@embroider/macros';
-import { DEPRECATE_EMBER_INFLECTOR } from '@warp-drive/build-config/deprecations';
+import { DEPRECATE_EMBER_INFLECTOR, DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
import { defaultRules as WarpDriveDefaults } from './-private/string/inflections';
import { irregular, plural, singular, uncountable } from './string';
@@ -85,7 +85,7 @@ if (DEPRECATE_EMBER_INFLECTOR) {
deprecate(
`WarpDrive/EmberData no longer uses ember-inflector for pluralization.\nPlease \`import { plural } from '@ember-data/request-utils/string';\` instead to register a custom pluralization rule for use with EmberData.`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'warp-drive.ember-inflector',
until: '6.0.0',
@@ -109,7 +109,7 @@ if (DEPRECATE_EMBER_INFLECTOR) {
deprecate(
`WarpDrive/EmberData no longer uses ember-inflector for singularization.\nPlease \`import { singular } from '@ember-data/request-utils/string';\` instead to register a custom singularization rule for use with EmberData.`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'warp-drive.ember-inflector',
until: '6.0.0',
@@ -141,7 +141,7 @@ if (DEPRECATE_EMBER_INFLECTOR) {
deprecate(
`WarpDrive/EmberData no longer uses ember-inflector for irregular rules.\nPlease \`import { irregular } from '@ember-data/request-utils/string';\` instead to register a custom irregular rule for use with EmberData for '${actualSingle}' <=> '${plur}'.`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'warp-drive.ember-inflector',
until: '6.0.0',
@@ -165,7 +165,7 @@ if (DEPRECATE_EMBER_INFLECTOR) {
deprecate(
`WarpDrive/EmberData no longer uses ember-inflector for uncountable rules.\nPlease \`import { uncountable } from '@ember-data/request-utils/string';\` instead to register a custom uncountable rule for '${word}' for use with EmberData.`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'warp-drive.ember-inflector',
until: '6.0.0',
@@ -184,7 +184,7 @@ if (DEPRECATE_EMBER_INFLECTOR) {
deprecate(
`WarpDrive/EmberData no longer uses ember-inflector for pluralization.\nPlease \`import { plural } from '@ember-data/request-utils/string';\` instead to register a custom pluralization rule for use with EmberData.`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'warp-drive.ember-inflector',
until: '6.0.0',
@@ -205,7 +205,7 @@ if (DEPRECATE_EMBER_INFLECTOR) {
deprecate(
`WarpDrive/EmberData no longer uses ember-inflector for singularization.\nPlease \`import { singular } from '@ember-data/request-utils/string';\` instead to register a custom singularization rule for use with EmberData.`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'warp-drive.ember-inflector',
until: '6.0.0',
@@ -226,7 +226,7 @@ if (DEPRECATE_EMBER_INFLECTOR) {
deprecate(
`WarpDrive/EmberData no longer uses ember-inflector for irregular rules.\nPlease \`import { irregular } from '@ember-data/request-utils/string';\` instead to register a custom irregular rule for use with EmberData.`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'warp-drive.ember-inflector',
until: '6.0.0',
@@ -247,7 +247,7 @@ if (DEPRECATE_EMBER_INFLECTOR) {
deprecate(
`WarpDrive/EmberData no longer uses ember-inflector for uncountable rules.\nPlease \`import { uncountable } from '@ember-data/request-utils/string';\` instead to register a custom uncountable rule for use with EmberData.`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'warp-drive.ember-inflector',
until: '6.0.0',
diff --git a/packages/request-utils/src/index.ts b/packages/request-utils/src/index.ts
index 337195d6c4e..6a52199e6b0 100644
--- a/packages/request-utils/src/index.ts
+++ b/packages/request-utils/src/index.ts
@@ -1,5 +1,6 @@
import { deprecate } from '@ember/debug';
+import { DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
import type { Cache } from '@warp-drive/core-types/cache';
@@ -753,7 +754,7 @@ export class CachePolicy {
const _config = arguments.length === 1 ? config : (arguments[1] as unknown as PolicyConfig);
deprecate(
`Passing a Store to the CachePolicy is deprecated, please pass only a config instead.`,
- arguments.length === 1,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS ? true : arguments.length === 1,
{
id: 'ember-data:request-utils:lifetimes-service-store-arg',
since: {
@@ -934,7 +935,7 @@ export class LifetimesService extends CachePolicy {
constructor(config: PolicyConfig) {
deprecate(
`\`import { LifetimesService } from '@ember-data/request-utils';\` is deprecated, please use \`import { CachePolicy } from '@ember-data/request-utils';\` instead.`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-lifetimes-service-import',
since: {
diff --git a/packages/request/package.json b/packages/request/package.json
index 595810bb474..d53beac17cd 100644
--- a/packages/request/package.json
+++ b/packages/request/package.json
@@ -1,7 +1,7 @@
{
"name": "@ember-data/request",
"description": "⚡️ A simple, small and fast framework-agnostic library to make `fetch` happen",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"license": "MIT",
"author": "Chris Thoburn ",
"repository": {
diff --git a/packages/rest/package.json b/packages/rest/package.json
index 33e757cb3b0..2815c20498b 100644
--- a/packages/rest/package.json
+++ b/packages/rest/package.json
@@ -1,7 +1,7 @@
{
"name": "@ember-data/rest",
"description": "REST Format Support for EmberData",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"private": false,
"license": "MIT",
"author": "Chris Thoburn ",
diff --git a/packages/serializer/package.json b/packages/serializer/package.json
index 143a96af484..00d97de292d 100644
--- a/packages/serializer/package.json
+++ b/packages/serializer/package.json
@@ -1,6 +1,6 @@
{
"name": "@ember-data/serializer",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"description": "Provides Legacy JSON, JSON:API and REST Implementations of the Serializer Interface for use with @ember-data/store",
"keywords": [
"ember-addon"
diff --git a/packages/store/package.json b/packages/store/package.json
index 1280d1236e4..0898da76cd9 100644
--- a/packages/store/package.json
+++ b/packages/store/package.json
@@ -1,6 +1,6 @@
{
"name": "@ember-data/store",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"description": "The core of EmberData. Provides the Store service which coordinates the cache with the network and presentation layers.",
"keywords": [
"ember-addon"
diff --git a/packages/store/src/-private.ts b/packages/store/src/-private.ts
index 532b54b8e04..9100d7b2a94 100644
--- a/packages/store/src/-private.ts
+++ b/packages/store/src/-private.ts
@@ -1,6 +1,11 @@
/**
@module @ember-data/store
*/
+import { assert, deprecate } from '@ember/debug';
+
+import { DEPRECATE_HELPERS } from '@warp-drive/build-config/deprecations';
+
+import { normalizeModelName as _normalize } from './-private/utils/normalize-model-name';
export { Store, storeFor } from './-private/store-service';
@@ -47,5 +52,33 @@ export { peekCache, removeRecordDataFor } from './-private/caches/cache-utils';
// @ember-data/model needs these temporarily
export { setRecordIdentifier, StoreMap } from './-private/caches/instance-cache';
export { setCacheFor } from './-private/caches/cache-utils';
-export { normalizeModelName as _deprecatingNormalize } from './-private/utils/normalize-model-name';
export type { StoreRequestInput } from './-private/cache-handler/handler';
+
+/**
+ This method normalizes a modelName into the format EmberData uses
+ internally by dasherizing it.
+
+ @method normalizeModelName
+ @static
+ @public
+ @deprecated
+ @for @ember-data/store
+ @param {String} modelName
+ @return {String} normalizedModelName
+*/
+export function normalizeModelName(modelName: string) {
+ if (DEPRECATE_HELPERS) {
+ deprecate(
+ `the helper function normalizeModelName is deprecated. You should use model names that are already normalized, or use string helpers of your own. This function is primarily an alias for dasherize from @ember/string.`,
+ false,
+ {
+ id: 'ember-data:deprecate-normalize-modelname-helper',
+ for: 'ember-data',
+ until: '5.0',
+ since: { available: '4.7', enabled: '4.7' },
+ }
+ );
+ return _normalize(modelName);
+ }
+ assert(`normalizeModelName support has been removed`);
+}
diff --git a/packages/store/src/-private/proxies/promise-proxies.ts b/packages/store/src/-private/proxies/promise-proxies.ts
new file mode 100644
index 00000000000..bc2d0f69b10
--- /dev/null
+++ b/packages/store/src/-private/proxies/promise-proxies.ts
@@ -0,0 +1,225 @@
+import { deprecate } from '@ember/debug';
+import { get } from '@ember/object';
+
+import { DEBUG } from '@warp-drive/build-config/env';
+
+import type IdentifierArray from '../record-arrays/identifier-array';
+import { PromiseArrayProxy, PromiseObjectProxy } from './promise-proxy-base';
+
+/**
+ @module @ember-data/store
+*/
+
+/**
+ A `PromiseArray` is an object that acts like both an `Ember.Array`
+ and a promise. When the promise is resolved the resulting value
+ will be set to the `PromiseArray`'s `content` property. This makes
+ it easy to create data bindings with the `PromiseArray` that will be
+ updated when the promise resolves.
+
+ This class should not be imported and instantiated directly.
+
+ For more information see the [Ember.PromiseProxyMixin
+ documentation](/ember/release/classes/PromiseProxyMixin).
+
+ Example
+
+ ```javascript
+ let promiseArray = PromiseArray.create({
+ promise: $.getJSON('/some/remote/data.json')
+ });
+
+ promiseArray.length; // 0
+
+ promiseArray.then(function() {
+ promiseArray.length; // 100
+ });
+ ```
+
+ @class PromiseArray
+ @public
+ @extends Ember.ArrayProxy
+ @uses Ember.PromiseProxyMixin
+*/
+
+/**
+ A `PromiseObject` is an object that acts like both an `EmberObject`
+ and a promise. When the promise is resolved, then the resulting value
+ will be set to the `PromiseObject`'s `content` property. This makes
+ it easy to create data bindings with the `PromiseObject` that will
+ be updated when the promise resolves.
+
+ This class should not be imported and instantiated directly.
+
+ For more information see the [Ember.PromiseProxyMixin
+ documentation](/ember/release/classes/PromiseProxyMixin.html).
+
+ Example
+
+ ```javascript
+ let promiseObject = PromiseObject.create({
+ promise: $.getJSON('/some/remote/data.json')
+ });
+
+ promiseObject.name; // null
+
+ promiseObject.then(function() {
+ promiseObject.name; // 'Tomster'
+ });
+ ```
+
+ @class PromiseObject
+ @public
+ @extends Ember.ObjectProxy
+ @uses Ember.PromiseProxyMixin
+*/
+export { PromiseObjectProxy as PromiseObject };
+
+function _promiseObject(promise: Promise): Promise {
+ return PromiseObjectProxy.create({ promise }) as Promise;
+}
+
+function _promiseArray(promise: Promise>): Promise> {
+ // @ts-expect-error this bucket of lies allows us to avoid typing the promise proxy which would
+ // require us to override a lot of Ember's types.
+ return PromiseArrayProxy.create({ promise }) as unknown as Promise>;
+}
+
+// constructor is accessed in some internals but not including it in the copyright for the deprecation
+const ALLOWABLE_METHODS = ['constructor', 'then', 'catch', 'finally'];
+const ALLOWABLE_PROPS = ['__ec_yieldable__', '__ec_cancel__'] as const;
+const PROXIED_ARRAY_PROPS = [
+ 'length',
+ '[]',
+ 'firstObject',
+ 'lastObject',
+ 'meta',
+ 'content',
+ 'isPending',
+ 'isSettled',
+ 'isRejected',
+ 'isFulfilled',
+ 'promise',
+ 'reason',
+];
+const PROXIED_OBJECT_PROPS = ['content', 'isPending', 'isSettled', 'isRejected', 'isFulfilled', 'promise', 'reason'];
+
+function isAllowedProp(prop: string): prop is (typeof ALLOWABLE_PROPS)[number] {
+ return ALLOWABLE_PROPS.includes(prop as (typeof ALLOWABLE_PROPS)[number]);
+}
+
+type SensitiveArray = {
+ __ec_yieldable__: unknown;
+ __ec_cancel__: unknown;
+} & Promise>;
+
+type SensitiveObject = {
+ __ec_yieldable__: unknown;
+ __ec_cancel__: unknown;
+} & Promise;
+
+export function promiseArray(promise: Promise>): Promise> {
+ const promiseObjectProxy = _promiseArray(promise);
+ if (!DEBUG) {
+ return promiseObjectProxy;
+ }
+ const handler = {
+ get(target: SensitiveArray, prop: string, receiver: object): unknown {
+ if (typeof prop === 'symbol') {
+ return Reflect.get(target, prop, receiver);
+ }
+ if (isAllowedProp(prop)) {
+ return target[prop];
+ }
+ if (!ALLOWABLE_METHODS.includes(prop)) {
+ deprecate(
+ `Accessing ${prop} on this PromiseArray is deprecated. The return type is being changed from PromiseArray to a Promise. The only available methods to access on this promise are .then, .catch and .finally`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-proxies',
+ until: '5.0',
+ for: '@ember-data/store',
+ since: {
+ available: '4.7',
+ enabled: '4.7',
+ },
+ }
+ );
+ }
+
+ // @ts-expect-error difficult to coerce target to the classic ember proxy
+ const value: unknown = target[prop];
+ if (value && typeof value === 'function' && typeof value.bind === 'function') {
+ return value.bind(target);
+ }
+
+ if (PROXIED_ARRAY_PROPS.includes(prop)) {
+ return value;
+ }
+
+ return undefined;
+ },
+ };
+
+ return new Proxy(promiseObjectProxy, handler);
+}
+
+const ProxySymbolString = String(Symbol.for('PROXY_CONTENT'));
+
+export function promiseObject(promise: Promise): Promise {
+ const promiseObjectProxy = _promiseObject(promise);
+ if (!DEBUG) {
+ return promiseObjectProxy;
+ }
+ const handler = {
+ get(target: SensitiveObject, prop: string, receiver: object): unknown {
+ if (typeof prop === 'symbol') {
+ if (String(prop) === ProxySymbolString) {
+ return;
+ }
+ return Reflect.get(target, prop, receiver);
+ }
+
+ if (prop === 'constructor') {
+ return target.constructor;
+ }
+
+ if (isAllowedProp(prop)) {
+ return target[prop];
+ }
+
+ if (!ALLOWABLE_METHODS.includes(prop)) {
+ deprecate(
+ `Accessing ${prop} on this PromiseObject is deprecated. The return type is being changed from PromiseObject to a Promise. The only available methods to access on this promise are .then, .catch and .finally`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-proxies',
+ until: '5.0',
+ for: '@ember-data/store',
+ since: {
+ available: '4.7',
+ enabled: '4.7',
+ },
+ }
+ );
+ } else {
+ // @ts-expect-error difficult to coerce target to the classic ember proxy
+ return (target[prop] as () => unknown).bind(target);
+ }
+
+ if (PROXIED_OBJECT_PROPS.includes(prop)) {
+ // @ts-expect-error difficult to coerce target to the classic ember proxy
+ return target[prop];
+ }
+
+ const value: unknown = get(target, prop);
+ if (value && typeof value === 'function' && typeof value.bind === 'function') {
+ return value.bind(receiver);
+ }
+
+ return undefined;
+ },
+ };
+
+ return new Proxy(promiseObjectProxy, handler);
+}
diff --git a/packages/store/src/-private/proxies/promise-proxy-base.d.ts b/packages/store/src/-private/proxies/promise-proxy-base.d.ts
new file mode 100644
index 00000000000..8c54a04b1de
--- /dev/null
+++ b/packages/store/src/-private/proxies/promise-proxy-base.d.ts
@@ -0,0 +1,65 @@
+import ArrayProxy from '@ember/array/proxy';
+import ObjectProxy from '@ember/object/proxy';
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export interface PromiseArrayProxy extends ArrayProxy, Promise {}
+export class PromiseArrayProxy extends ArrayProxy {
+ declare content: T;
+
+ /*
+ * If the proxied promise is rejected this will contain the reason
+ * provided.
+ */
+ declare reason: string | Error;
+ /*
+ * Once the proxied promise has settled this will become `false`.
+ */
+ declare isPending: boolean;
+ /*
+ * Once the proxied promise has settled this will become `true`.
+ */
+ declare isSettled: boolean;
+ /*
+ * Will become `true` if the proxied promise is rejected.
+ */
+ declare isRejected: boolean;
+ /*
+ * Will become `true` if the proxied promise is fulfilled.
+ */
+ declare isFulfilled: boolean;
+ /*
+ * The promise whose fulfillment value is being proxied by this object.
+ */
+ declare promise: Promise;
+}
+
+export interface PromiseObjectProxy extends ObjectProxy, Promise {}
+export class PromiseObjectProxy extends ObjectProxy {
+ declare content?: T | null;
+
+ /*
+ * If the proxied promise is rejected this will contain the reason
+ * provided.
+ */
+ reason: string | Error;
+ /*
+ * Once the proxied promise has settled this will become `false`.
+ */
+ isPending: boolean;
+ /*
+ * Once the proxied promise has settled this will become `true`.
+ */
+ isSettled: boolean;
+ /*
+ * Will become `true` if the proxied promise is rejected.
+ */
+ isRejected: boolean;
+ /*
+ * Will become `true` if the proxied promise is fulfilled.
+ */
+ isFulfilled: boolean;
+ /*
+ * The promise whose fulfillment value is being proxied by this object.
+ */
+ promise: Promise;
+}
diff --git a/packages/store/src/-private/proxies/promise-proxy-base.js b/packages/store/src/-private/proxies/promise-proxy-base.js
new file mode 100644
index 00000000000..87c98734d04
--- /dev/null
+++ b/packages/store/src/-private/proxies/promise-proxy-base.js
@@ -0,0 +1,9 @@
+import ArrayProxy from '@ember/array/proxy';
+import { reads } from '@ember/object/computed';
+import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
+import ObjectProxy from '@ember/object/proxy';
+
+export class PromiseArrayProxy extends ArrayProxy.extend(PromiseProxyMixin) {
+ @reads('content.meta') meta;
+}
+export const PromiseObjectProxy = ObjectProxy.extend(PromiseProxyMixin);
diff --git a/packages/store/src/-private/record-arrays/identifier-array.ts b/packages/store/src/-private/record-arrays/identifier-array.ts
index d884f92f0ec..ae693334122 100644
--- a/packages/store/src/-private/record-arrays/identifier-array.ts
+++ b/packages/store/src/-private/record-arrays/identifier-array.ts
@@ -1,6 +1,11 @@
/**
@module @ember-data/store
*/
+import { deprecate } from '@ember/debug';
+import { get, set } from '@ember/object';
+import { compare } from '@ember/utils';
+import Ember from 'ember';
+
import { compat } from '@ember-data/tracking';
import type { Signal } from '@ember-data/tracking/-private';
import {
@@ -10,6 +15,14 @@ import {
defineSignal,
subscribe,
} from '@ember-data/tracking/-private';
+import {
+ DEPRECATE_A_USAGE,
+ DEPRECATE_ARRAY_LIKE,
+ DEPRECATE_COMPUTED_CHAINS,
+ DEPRECATE_PROMISE_PROXIES,
+ DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS,
+} from '@warp-drive/build-config/deprecations';
+import { DEBUG } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import { getOrSetGlobal } from '@warp-drive/core-types/-private';
import type { StableRecordIdentifier } from '@warp-drive/core-types/identifier';
@@ -21,6 +34,7 @@ import type { OpaqueRecordInstance } from '../../-types/q/record-instance';
import { isStableIdentifier } from '../caches/identifier-cache';
import { recordIdentifierFor } from '../caches/instance-cache';
import type { RecordArrayManager } from '../managers/record-array-manager';
+import { promiseArray } from '../proxies/promise-proxies';
import type { Store } from '../store-service';
import { NativeProxy } from './native-proxy-type-fix';
@@ -93,6 +107,19 @@ export type IdentifierArrayCreateOptions = {
meta?: Record | null;
};
+function deprecateArrayLike(className: string, fnName: string, replName: string) {
+ deprecate(
+ `The \`${fnName}\` method on the class ${className} is deprecated. Use the native array method \`${replName}\` instead.`,
+ false,
+ {
+ id: 'ember-data:deprecate-array-like',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ for: 'ember-data',
+ }
+ );
+}
+
interface PrivateState {
links: Links | PaginationLinks | null;
meta: Record | null;
@@ -182,6 +209,16 @@ export class IdentifierArray {
declare links: Links | PaginationLinks | null;
declare meta: Record | null;
declare modelName?: TypeFromInstanceOrString;
+
+ /**
+ The modelClass represented by this record array.
+
+ @property type
+ @public
+ @deprecated
+ @type {subclass of Model}
+ */
+ declare type: unknown;
/**
The store that created this record array.
@@ -299,6 +336,7 @@ export class IdentifierArray {
}
const args: unknown[] = Array.prototype.slice.call(arguments);
assert(`Cannot start a new array transaction while a previous transaction is underway`, !transaction);
+
transaction = true;
const result = self[MUTATE]!(target, receiver, prop as string, args, _SIGNAL);
transaction = false;
@@ -312,6 +350,18 @@ export class IdentifierArray {
}
if (isSelfProp(self, prop)) {
+ if (DEPRECATE_ARRAY_LIKE) {
+ if (prop === 'firstObject') {
+ deprecateArrayLike(self.DEPRECATED_CLASS_NAME, prop as string, '[0]');
+ // @ts-expect-error adding MutableArray method calling index signature
+ return receiver[0];
+ } else if (prop === 'lastObject') {
+ deprecateArrayLike(self.DEPRECATED_CLASS_NAME, prop as string, 'at(-1)');
+ // @ts-expect-error adding MutableArray method calling index signature
+ return receiver[receiver.length - 1];
+ }
+ }
+
if (prop === NOTIFY || prop === ARRAY_SIGNAL || prop === SOURCE) {
return self[prop];
}
@@ -396,6 +446,7 @@ export class IdentifierArray {
const original: StableRecordIdentifier | undefined = target[index];
const newIdentifier = extractIdentifierFromRecord(value);
+ // FIXME this line was added on main and I'm not sure why
(target as unknown as Record)[index] = newIdentifier;
assert(`Expected a record`, isStableIdentifier(newIdentifier));
// We generate "transactions" whenever a setter method on the array
@@ -436,6 +487,28 @@ export class IdentifierArray {
},
}) as IdentifierArray;
+ if (DEPRECATE_A_USAGE) {
+ const meta = Ember.meta(this);
+ meta.hasMixin = (mixin: object) => {
+ deprecate(`Do not call A() on EmberData RecordArrays`, false, {
+ id: 'ember-data:no-a-with-array-like',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ for: 'ember-data',
+ });
+ // @ts-expect-error ArrayMixin is more than a type
+ if (mixin === NativeArray || mixin === ArrayMixin) {
+ return true;
+ }
+ return false;
+ };
+ } else if (DEBUG) {
+ const meta = Ember.meta(this);
+ meta.hasMixin = (mixin: object) => {
+ assert(`Do not call A() on EmberData RecordArrays`);
+ };
+ }
+
createArrayTags(proxy, _SIGNAL);
this[NOTIFY] = this[NOTIFY].bind(proxy);
@@ -485,7 +558,7 @@ export class IdentifierArray {
}
/*
- Update this Array and return a promise which resolves once the update
+ Update this RecordArray and return a promise which resolves once the update
is finished.
*/
_update(): Promise> {
@@ -515,9 +588,14 @@ export class IdentifierArray {
@public
@return {Promise} promise
*/
- save(): Promise {
+ save(): Promise> {
const promise = Promise.all(this.map((record) => this.store.saveRecord(record))).then(() => this);
+ if (DEPRECATE_PROMISE_PROXIES) {
+ // @ts-expect-error IdentifierArray is not a MutableArray
+ return promiseArray>(promise);
+ }
+
return promise;
}
}
@@ -530,7 +608,11 @@ const desc = {
enumerable: true,
configurable: false,
get: function () {
- return this;
+ // here to support computed chains
+ // and {{#each}}
+ if (DEPRECATE_COMPUTED_CHAINS) {
+ return this;
+ }
},
};
compat(desc);
@@ -538,6 +620,31 @@ Object.defineProperty(IdentifierArray.prototype, '[]', desc);
defineSignal(IdentifierArray.prototype, 'isUpdating', false);
+export default IdentifierArray;
+
+if (DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS) {
+ Object.defineProperty(IdentifierArray.prototype, 'type', {
+ get() {
+ deprecate(
+ `Using RecordArray.type to access the ModelClass for a record is deprecated. Use store.modelFor() instead.`,
+ false,
+ {
+ id: 'ember-data:deprecate-snapshot-model-class-access',
+ until: '5.0',
+ for: 'ember-data',
+ since: { available: '4.5.0', enabled: '4.5.0' },
+ }
+ );
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ if (!this.modelName) {
+ return null;
+ }
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
+ return this.store.modelFor(this.modelName);
+ },
+ });
+}
+
export type CollectionCreateOptions = IdentifierArrayCreateOptions & {
manager: RecordArrayManager;
query: ImmutableRequestInfo | Record | null;
@@ -566,6 +673,11 @@ export class Collection extends IdentifierArray {
// both being valid options to pass through here.
const promise = store.query(this.modelName, query as Record, { _recordArray: this });
+ if (DEPRECATE_PROMISE_PROXIES) {
+ // @ts-expect-error Collection is not a MutableArray
+ return promiseArray(promise);
+ }
+
return promise;
}
@@ -579,7 +691,415 @@ export class Collection extends IdentifierArray {
Collection.prototype.query = null;
// Ensure instanceof works correctly
-// Object.setPrototypeOf(IdentifierArray.prototype, Array.prototype);
+//Object.setPrototypeOf(IdentifierArray.prototype, Array.prototype);
+
+if (DEPRECATE_ARRAY_LIKE) {
+ IdentifierArray.prototype.DEPRECATED_CLASS_NAME = 'RecordArray';
+ Collection.prototype.DEPRECATED_CLASS_NAME = 'RecordArray';
+ const EmberObjectMethods = [
+ 'addObserver',
+ 'cacheFor',
+ 'decrementProperty',
+ 'get',
+ 'getProperties',
+ 'incrementProperty',
+ 'notifyPropertyChange',
+ 'removeObserver',
+ 'set',
+ 'setProperties',
+ 'toggleProperty',
+ ] as const;
+ EmberObjectMethods.forEach((method) => {
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype[method] = function delegatedMethod(...args: unknown[]): unknown {
+ deprecate(
+ `The EmberObject ${method} method on the class ${this.DEPRECATED_CLASS_NAME} is deprecated. Use dot-notation javascript get/set access instead.`,
+ false,
+ {
+ id: 'ember-data:deprecate-array-like',
+ until: '5.0',
+ since: { enabled: '4.7', available: '4.7' },
+ for: 'ember-data',
+ }
+ );
+ // @ts-expect-error ember is missing types for some methods
+ return (Ember[method] as (...args: unknown[]) => unknown)(this, ...args);
+ };
+ });
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.addObject = function (obj: OpaqueRecordInstance) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'addObject', 'push');
+ const index = this.indexOf(obj);
+ if (index === -1) {
+ this.push(obj);
+ }
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.addObjects = function (objs: OpaqueRecordInstance[]) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'addObjects', 'push');
+ objs.forEach((obj: OpaqueRecordInstance) => {
+ const index = this.indexOf(obj);
+ if (index === -1) {
+ this.push(obj);
+ }
+ });
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.popObject = function () {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'popObject', 'pop');
+ return this.pop() as OpaqueRecordInstance;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.pushObject = function (obj: OpaqueRecordInstance) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'pushObject', 'push');
+ this.push(obj);
+ return obj;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.pushObjects = function (objs: OpaqueRecordInstance[]) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'pushObjects', 'push');
+ this.push(...objs);
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.shiftObject = function () {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'shiftObject', 'shift');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.shift()!;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.unshiftObject = function (obj: OpaqueRecordInstance) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'unshiftObject', 'unshift');
+ this.unshift(obj);
+ return obj;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.unshiftObjects = function (objs: OpaqueRecordInstance[]) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'unshiftObjects', 'unshift');
+ this.unshift(...objs);
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.objectAt = function (index: number) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'objectAt', 'at');
+ //For negative index values go back from the end of the array
+ const arrIndex = Math.sign(index) === -1 ? this.length + index : index;
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this[arrIndex];
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.objectsAt = function (indices: number[]) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'objectsAt', 'at');
+ // @ts-expect-error adding MutableArray method
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
+ return indices.map((index) => this.objectAt(index)!);
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.removeAt = function (index: number) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'removeAt', 'splice');
+ this.splice(index, 1);
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.insertAt = function (index: number, obj: OpaqueRecordInstance) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'insertAt', 'splice');
+ this.splice(index, 0, obj);
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.removeObject = function (obj: OpaqueRecordInstance) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'removeObject', 'splice');
+ const index = this.indexOf(obj);
+ if (index !== -1) {
+ this.splice(index, 1);
+ }
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.removeObjects = function (objs: OpaqueRecordInstance[]) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'removeObjects', 'splice');
+ objs.forEach((obj) => {
+ const index = this.indexOf(obj);
+ if (index !== -1) {
+ this.splice(index, 1);
+ }
+ });
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.toArray = function () {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'toArray', 'slice');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.slice();
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.replace = function (idx: number, amt: number, objects?: OpaqueRecordInstance[]) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'replace', 'splice');
+ if (objects) {
+ this.splice(idx, amt, ...objects);
+ } else {
+ this.splice(idx, amt);
+ }
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.clear = function () {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'clear', 'length = 0');
+ this.splice(0, this.length);
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.setObjects = function (objects: OpaqueRecordInstance[]) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'setObjects', '`arr.length = 0; arr.push(objects);`');
+ assert(
+ `${this.DEPRECATED_CLASS_NAME}.setObjects expects to receive an array as its argument`,
+ Array.isArray(objects)
+ );
+ this.splice(0, this.length);
+ this.push(...objects);
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.reverseObjects = function () {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'reverseObjects', 'reverse');
+ this.reverse();
+ return this;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.compact = function () {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'compact', 'filter');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.filter((v) => v !== null && v !== undefined);
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.any = function (callback, target) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'any', 'some');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
+ return this.some(callback, target);
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.isAny = function (prop, value) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'isAny', 'some');
+ const hasValue = arguments.length === 2;
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ return this.some((v) => (hasValue ? v[prop] === value : v[prop] === true));
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.isEvery = function (prop, value) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'isEvery', 'every');
+ const hasValue = arguments.length === 2;
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ return this.every((v) => (hasValue ? v[prop] === value : v[prop] === true));
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.getEach = function (key: string) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'getEach', 'map');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.map((value) => get(value, key));
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.mapBy = function (key: string) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'mapBy', 'map');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.map((value) => get(value, key));
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.findBy = function (key: string, value?: unknown) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'findBy', 'find');
+ if (arguments.length === 2) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.find((val) => {
+ return get(val, key) === value;
+ });
+ } else {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.find((val) => Boolean(get(val, key)));
+ }
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.filterBy = function (key: string, value?: unknown) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'filterBy', 'filter');
+ if (arguments.length === 2) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.filter((record) => {
+ return get(record, key) === value;
+ });
+ }
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.filter((record) => {
+ return Boolean(get(record, key));
+ });
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.sortBy = function (...sortKeys: string[]) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'sortBy', '.slice().sort');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.slice().sort((a, b) => {
+ for (let i = 0; i < sortKeys.length; i++) {
+ const key = sortKeys[i];
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+ const propA = get(a, key);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+ const propB = get(b, key);
+ // return 1 or -1 else continue to the next sortKey
+ const compareValue = compare(propA, propB);
+
+ if (compareValue) {
+ return compareValue;
+ }
+ }
+ return 0;
+ });
+ };
+
+ // @ts-expect-error
+ IdentifierArray.prototype.invoke = function (key: string, ...args: unknown[]) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'invoke', 'forEach');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ return this.map((value) => (value[key] as (...args: unknown[]) => unknown)(...args));
+ };
+
+ // @ts-expect-error
+ IdentifierArray.prototype.addArrayObserver = function () {
+ deprecateArrayLike(
+ this.DEPRECATED_CLASS_NAME,
+ 'addArrayObserver',
+ 'derived state or reacting at the change source'
+ );
+ };
+
+ // @ts-expect-error
+ IdentifierArray.prototype.removeArrayObserver = function () {
+ deprecateArrayLike(
+ this.DEPRECATED_CLASS_NAME,
+ 'removeArrayObserver',
+ 'derived state or reacting at the change source'
+ );
+ };
+
+ // @ts-expect-error
+ IdentifierArray.prototype.arrayContentWillChange = function () {
+ deprecateArrayLike(
+ this.DEPRECATED_CLASS_NAME,
+ 'arrayContentWillChange',
+ 'derived state or reacting at the change source'
+ );
+ };
+
+ // @ts-expect-error
+ IdentifierArray.prototype.arrayContentDidChange = function () {
+ deprecateArrayLike(
+ this.DEPRECATED_CLASS_NAME,
+ 'arrayContentDidChange',
+ 'derived state or reacting at the change source.'
+ );
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.reject = function (callback, target?: unknown) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'reject', 'filter');
+ assert('`reject` expects a function as first argument.', typeof callback === 'function');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.filter((...args) => {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
+ return !callback.apply(target, args);
+ });
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.rejectBy = function (key: string, value?: unknown) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'rejectBy', 'filter');
+ if (arguments.length === 2) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.filter((record) => {
+ return get(record, key) !== value;
+ });
+ }
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.filter((record) => {
+ return !get(record, key);
+ });
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.setEach = function (key: string, value: unknown) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'setEach', 'forEach');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
+ this.forEach((item) => set(item, key, value));
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.uniq = function () {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'uniq', 'filter');
+ // all current managed arrays are already enforced as unique
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return this.slice();
+ };
+
+ // @ts-expect-error
+ IdentifierArray.prototype.uniqBy = function (key: string) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'uniqBy', 'filter');
+ // all current managed arrays are already enforced as unique
+ const seen = new Set();
+ const result: OpaqueRecordInstance[] = [];
+ this.forEach((item) => {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+ const value = get(item, key);
+ if (seen.has(value)) {
+ return;
+ }
+ seen.add(value);
+ result.push(item);
+ });
+ return result;
+ };
+
+ // @ts-expect-error adding MutableArray method
+ IdentifierArray.prototype.without = function (value: OpaqueRecordInstance) {
+ deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'without', 'slice');
+ const newArr = this.slice();
+ const index = this.indexOf(value);
+ if (index !== -1) {
+ newArr.splice(index, 1);
+ }
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return newArr;
+ };
+
+ // @ts-expect-error
+ IdentifierArray.prototype.firstObject = null;
+ // @ts-expect-error
+ IdentifierArray.prototype.lastObject = null;
+}
type PromiseProxyRecord = { then(): void; content: OpaqueRecordInstance | null | undefined };
@@ -597,11 +1117,25 @@ function assertRecordPassedToHasMany(record: OpaqueRecordInstance | PromiseProxy
);
}
-function extractIdentifierFromRecord(record: PromiseProxyRecord | OpaqueRecordInstance | null) {
- if (!record) {
+function extractIdentifierFromRecord(recordOrPromiseRecord: PromiseProxyRecord | OpaqueRecordInstance | null) {
+ if (!recordOrPromiseRecord) {
return null;
}
- assertRecordPassedToHasMany(record);
- return recordIdentifierFor(record);
+ if (isPromiseRecord(recordOrPromiseRecord)) {
+ const content = recordOrPromiseRecord.content;
+ assert(
+ 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo relationship.',
+ content !== undefined && content !== null
+ );
+ assertRecordPassedToHasMany(content);
+ return recordIdentifierFor(content);
+ }
+
+ assertRecordPassedToHasMany(recordOrPromiseRecord);
+ return recordIdentifierFor(recordOrPromiseRecord);
+}
+
+function isPromiseRecord(record: PromiseProxyRecord | OpaqueRecordInstance): record is PromiseProxyRecord {
+ return Boolean(typeof record === 'object' && record && 'then' in record);
}
diff --git a/packages/store/src/-private/store-service.ts b/packages/store/src/-private/store-service.ts
index 2405687a75f..00323a16347 100644
--- a/packages/store/src/-private/store-service.ts
+++ b/packages/store/src/-private/store-service.ts
@@ -10,7 +10,11 @@ import type RequestManager from '@ember-data/request';
import type { Future } from '@ember-data/request';
import { LOG_PAYLOADS, LOG_REQUESTS } from '@warp-drive/build-config/debugging';
import {
+ DEPRECATE_HAS_RECORD,
+ DEPRECATE_PROMISE_PROXIES,
DEPRECATE_STORE_EXTENDS_EMBER_OBJECT,
+ DEPRECATE_STORE_FIND,
+ DISABLE_6X_DEPRECATIONS,
ENABLE_LEGACY_SCHEMA_SERVICE,
} from '@warp-drive/build-config/deprecations';
import { DEBUG, TESTING } from '@warp-drive/build-config/env';
@@ -57,6 +61,7 @@ import { CacheManager } from './managers/cache-manager';
import NotificationManager from './managers/notification-manager';
import { RecordArrayManager } from './managers/record-array-manager';
import { RequestPromise, RequestStateService } from './network/request-cache';
+import { promiseArray, promiseObject } from './proxies/promise-proxies';
import type { Collection, IdentifierArray } from './record-arrays/identifier-array';
import { coerceId, ensureStringId } from './utils/coerce-id';
import { constructResource } from './utils/construct-resource';
@@ -215,7 +220,7 @@ const app = new EmberApp(defaults, {
});
\`\`\`
`,
- false,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
{
id: 'ember-data:deprecate-store-extends-ember-object',
until: '6.0',
@@ -1021,6 +1026,60 @@ export class Store extends BaseClass {
}
}
+ /**
+ @method find
+ @param {String} modelName
+ @param {String|Integer} id
+ @param {Object} options
+ @return {Promise} promise
+ @deprecated
+ @private
+ */
+ find(modelName: string, id: string | number, options?: FindRecordOptions): Promise {
+ if (DEBUG) {
+ assertDestroyingStore(this, 'find');
+ }
+ // The default `model` hook in Route calls `find(modelName, id)`,
+ // that's why we have to keep this method around even though `findRecord` is
+ // the public way to get a record by modelName and id.
+ assert(
+ `Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`,
+ arguments.length !== 1
+ );
+ assert(
+ `Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`,
+ !options
+ );
+ assert(`You need to pass the model name and id to the store's find method`, arguments.length === 2);
+ assert(
+ `You cannot pass '${id}' as id to the store's find method`,
+ typeof id === 'string' || typeof id === 'number'
+ );
+ assert(
+ `Calling store.find() with a query object is no longer supported. Use store.query() instead.`,
+ typeof id !== 'object'
+ );
+ assert(
+ `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`,
+ typeof modelName === 'string'
+ );
+
+ if (DEPRECATE_STORE_FIND) {
+ deprecate(
+ `Using store.find is deprecated, use store.findRecord instead. Likely this means you are relying on the implicit store fetching behavior of routes unknowingly.`,
+ false,
+ {
+ id: 'ember-data:deprecate-store-find',
+ since: { available: '4.5', enabled: '4.5' },
+ for: 'ember-data',
+ until: '5.0',
+ }
+ );
+ return this.findRecord(modelName, id);
+ }
+ assert(`store.find has been removed. Use store.findRecord instead.`);
+ }
+
/**
This method returns a record for a given identifier or type and id combination.
@@ -1427,6 +1486,14 @@ export class Store extends BaseClass {
cacheOptions: { [SkipCache]: true },
});
+ if (DEPRECATE_PROMISE_PROXIES) {
+ return promiseObject(
+ promise.then((document) => {
+ return document.content;
+ })
+ );
+ }
+
return promise.then((document) => {
return document.content;
});
@@ -1577,6 +1644,54 @@ export class Store extends BaseClass {
return isLoaded ? (this._instanceCache.getRecord(stableIdentifier) as T) : null;
}
+ /**
+ This method returns true if a record for a given modelName and id is already
+ loaded in the store. Use this function to know beforehand if a findRecord()
+ will result in a request or that it will be a cache hit.
+
+ Example
+
+ ```javascript
+ store.hasRecordForId('post', 1); // false
+ store.findRecord('post', 1).then(function() {
+ store.hasRecordForId('post', 1); // true
+ });
+ ```
+
+ @method hasRecordForId
+ @deprecated
+ @public
+ @param {String} modelName
+ @param {(String|Integer)} id
+ @return {Boolean}
+ */
+ hasRecordForId(modelName: string, id: string | number): boolean {
+ if (DEPRECATE_HAS_RECORD) {
+ deprecate(`store.hasRecordForId has been deprecated in favor of store.peekRecord`, false, {
+ id: 'ember-data:deprecate-has-record-for-id',
+ since: { available: '4.5', enabled: '4.5' },
+ until: '5.0',
+ for: 'ember-data',
+ });
+ if (DEBUG) {
+ assertDestroyingStore(this, 'hasRecordForId');
+ }
+ assert(`You need to pass a model name to the store's hasRecordForId method`, modelName);
+ assert(
+ `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`,
+ typeof modelName === 'string'
+ );
+
+ const type = normalizeModelName(modelName);
+ const trueId = ensureStringId(id);
+ const resource = { type, id: trueId };
+
+ const identifier = this.identifierCache.peekRecordIdentifier(resource);
+ return Boolean(identifier && this._instanceCache.recordIsLoaded(identifier));
+ }
+ assert(`store.hasRecordForId has been removed`);
+ }
+
/**
This method delegates a query to the adapter. This is the one place where
adapter-level semantics are exposed to the application.
@@ -1651,6 +1766,9 @@ export class Store extends BaseClass {
cacheOptions: { [SkipCache]: true },
});
+ if (DEPRECATE_PROMISE_PROXIES) {
+ return promiseArray(promise.then((document) => document.content)) as unknown as Promise;
+ }
return promise.then((document) => document.content);
}
@@ -1779,6 +1897,10 @@ export class Store extends BaseClass {
cacheOptions: { [SkipCache]: true },
});
+ if (DEPRECATE_PROMISE_PROXIES) {
+ return promiseObject(promise.then((document) => document.content));
+ }
+
return promise.then((document) => document.content);
}
@@ -1981,6 +2103,10 @@ export class Store extends BaseClass {
cacheOptions: { [SkipCache]: true },
});
+ if (DEPRECATE_PROMISE_PROXIES) {
+ return promiseArray(promise.then((document) => document.content)) as unknown as Promise>;
+ }
+
return promise.then((document) => document.content);
}
@@ -2392,39 +2518,51 @@ export class Store extends BaseClass {
if (ENABLE_LEGACY_SCHEMA_SERVICE) {
Store.prototype.getSchemaDefinitionService = function (): SchemaService {
assert(`You must registerSchemaDefinitionService with the store to use custom model classes`, this._schema);
- deprecate(`Use \`store.schema\` instead of \`store.getSchemaDefinitionService()\``, false, {
- id: 'ember-data:schema-service-updates',
- until: '6.0',
- for: 'ember-data',
- since: {
- available: '4.13',
- enabled: '5.4',
- },
- });
+ deprecate(
+ `Use \`store.schema\` instead of \`store.getSchemaDefinitionService()\``,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
+ {
+ id: 'ember-data:schema-service-updates',
+ until: '6.0',
+ for: 'ember-data',
+ since: {
+ available: '4.13',
+ enabled: '5.4',
+ },
+ }
+ );
return this._schema;
};
Store.prototype.registerSchemaDefinitionService = function (schema: SchemaService) {
- deprecate(`Use \`store.createSchemaService\` instead of \`store.registerSchemaDefinitionService()\``, false, {
- id: 'ember-data:schema-service-updates',
- until: '6.0',
- for: 'ember-data',
- since: {
- available: '4.13',
- enabled: '5.4',
- },
- });
+ deprecate(
+ `Use \`store.createSchemaService\` instead of \`store.registerSchemaDefinitionService()\``,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
+ {
+ id: 'ember-data:schema-service-updates',
+ until: '6.0',
+ for: 'ember-data',
+ since: {
+ available: '4.13',
+ enabled: '5.4',
+ },
+ }
+ );
this._schema = schema;
};
Store.prototype.registerSchema = function (schema: SchemaService) {
- deprecate(`Use \`store.createSchemaService\` instead of \`store.registerSchema()\``, false, {
- id: 'ember-data:schema-service-updates',
- until: '6.0',
- for: 'ember-data',
- since: {
- available: '4.13',
- enabled: '5.4',
- },
- });
+ deprecate(
+ `Use \`store.createSchemaService\` instead of \`store.registerSchema()\``,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS,
+ {
+ id: 'ember-data:schema-service-updates',
+ until: '6.0',
+ for: 'ember-data',
+ since: {
+ available: '4.13',
+ enabled: '5.4',
+ },
+ }
+ );
this._schema = schema;
};
}
@@ -2534,5 +2672,33 @@ function extractIdentifierFromRecord(recordOrPromiseRecord: PromiseProxyRecord |
}
const extract = recordIdentifierFor;
+ if (DEPRECATE_PROMISE_PROXIES) {
+ if (isPromiseRecord(recordOrPromiseRecord)) {
+ const content = recordOrPromiseRecord.content;
+ assert(
+ 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.',
+ content !== undefined
+ );
+ deprecate(
+ `You passed in a PromiseProxy to a Relationship API that now expects a resolved value. await the value before setting it.`,
+ false,
+ {
+ id: 'ember-data:deprecate-promise-proxies',
+ until: '5.0',
+ since: {
+ enabled: '4.7',
+ available: '4.7',
+ },
+ for: 'ember-data',
+ }
+ );
+ return content ? extract(content) : null;
+ }
+ }
+
return extract(recordOrPromiseRecord);
}
+
+function isPromiseRecord(record: PromiseProxyRecord | OpaqueRecordInstance): record is PromiseProxyRecord {
+ return typeof record === 'object' && !!record && 'then' in record && typeof record.then === 'function';
+}
diff --git a/packages/store/src/-private/utils/coerce-id.ts b/packages/store/src/-private/utils/coerce-id.ts
index ceb1f6f8dda..2be265ef878 100644
--- a/packages/store/src/-private/utils/coerce-id.ts
+++ b/packages/store/src/-private/utils/coerce-id.ts
@@ -4,7 +4,7 @@
import { deprecate } from '@ember/debug';
-import { DEPRECATE_NON_STRICT_ID } from '@warp-drive/build-config/deprecations';
+import { DEPRECATE_NON_STRICT_ID, DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
import { assert } from '@warp-drive/build-config/macros';
// Used by the store to normalize IDs entering the store. Despite the fact
@@ -28,7 +28,7 @@ export function coerceId(id: unknown): string | null {
`The resource id '<${typeof id}> ${String(
id
)} ' is not normalized. Update your application code to use '${JSON.stringify(normalized)}' instead.`,
- normalized === id,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS ? true : normalized === id,
{
id: 'ember-data:deprecate-non-strict-id',
until: '6.0',
diff --git a/packages/store/src/-private/utils/normalize-model-name.ts b/packages/store/src/-private/utils/normalize-model-name.ts
index 91e12a8e829..dba54a8b1c1 100644
--- a/packages/store/src/-private/utils/normalize-model-name.ts
+++ b/packages/store/src/-private/utils/normalize-model-name.ts
@@ -1,7 +1,7 @@
import { deprecate } from '@ember/debug';
import { dasherize } from '@ember-data/request-utils/string';
-import { DEPRECATE_NON_STRICT_TYPES } from '@warp-drive/build-config/deprecations';
+import { DEPRECATE_NON_STRICT_TYPES, DISABLE_6X_DEPRECATIONS } from '@warp-drive/build-config/deprecations';
export function normalizeModelName(type: string): string {
if (DEPRECATE_NON_STRICT_TYPES) {
@@ -9,7 +9,7 @@ export function normalizeModelName(type: string): string {
deprecate(
`The resource type '${type}' is not normalized. Update your application code to use '${result}' instead of '${type}'.`,
- result === type,
+ /* inline-macro-config */ DISABLE_6X_DEPRECATIONS ? true : result === type,
{
id: 'ember-data:deprecate-non-strict-types',
until: '6.0',
diff --git a/packages/store/src/index.ts b/packages/store/src/index.ts
index 6b31bf43285..c30dab7d595 100644
--- a/packages/store/src/index.ts
+++ b/packages/store/src/index.ts
@@ -186,6 +186,7 @@ export {
Store as default,
type StoreRequestContext,
CacheHandler,
+ normalizeModelName,
type Document,
type CachePolicy,
type StoreRequestInput,
diff --git a/packages/store/vite.config.mjs b/packages/store/vite.config.mjs
index ca9aa0e126f..ba7aaf03493 100644
--- a/packages/store/vite.config.mjs
+++ b/packages/store/vite.config.mjs
@@ -1,6 +1,20 @@
import { createConfig } from '@warp-drive/internal-config/vite/config.js';
-export const externals = ['@ember/runloop', '@ember/object', '@ember/debug'];
+export const externals = [
+ 'ember',
+ '@ember/object/computed',
+ '@ember/object/promise-proxy-mixin',
+ '@ember/object/proxy',
+ '@ember/array/proxy',
+ '@ember/application',
+ '@ember/debug',
+ '@ember/owner',
+ '@ember/utils',
+ '@ember/runloop',
+ '@ember/object',
+ '@ember/debug',
+];
+
export const entryPoints = ['./src/index.ts', './src/types.ts', './src/-private.ts'];
export default createConfig(
diff --git a/packages/tracking/package.json b/packages/tracking/package.json
index 130568171cb..18c402d8342 100644
--- a/packages/tracking/package.json
+++ b/packages/tracking/package.json
@@ -1,7 +1,7 @@
{
"name": "@ember-data/tracking",
"description": "Tracking Primitives for controlling change notification of Tracked properties when working with EmberData",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"private": false,
"license": "MIT",
"author": "Chris Thoburn ",
diff --git a/packages/unpublished-eslint-rules/package.json b/packages/unpublished-eslint-rules/package.json
index 300ea311226..087147bc3e1 100644
--- a/packages/unpublished-eslint-rules/package.json
+++ b/packages/unpublished-eslint-rules/package.json
@@ -1,7 +1,7 @@
{
"name": "eslint-plugin-ember-data-internal",
"main": "./src/index.js",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"private": true,
"repository": {
"type": "git",
diff --git a/packages/unpublished-test-infra/package.json b/packages/unpublished-test-infra/package.json
index 76886dea1b6..d78bd734555 100644
--- a/packages/unpublished-test-infra/package.json
+++ b/packages/unpublished-test-infra/package.json
@@ -1,6 +1,6 @@
{
"name": "@ember-data/unpublished-test-infra",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"private": true,
"description": "The default blueprint for ember-data private packages.",
"keywords": [
diff --git a/release/strategy.json b/release/strategy.json
index 3fa6ae166fd..2146afbc7d2 100644
--- a/release/strategy.json
+++ b/release/strategy.json
@@ -30,74 +30,20 @@
"typesPublish": true
},
"rules": {
- "@ember-data/codemods": {
- "stage": "stable",
- "types": "private",
- "typesPublish": false,
- "mirrorPublish": false
- },
"@ember-data/debug": {
"stage": "stable",
"types": "private",
"typesPublish": false
},
- "warp-drive": {
- "stage": "alpha",
- "types": "private",
- "typesPublish": false,
- "mirrorPublish": false
- },
"@warp-drive/build-config": {
"stage": "alpha",
"types": "alpha",
"typesPublish": false,
"mirrorPublish": true
},
- "@warp-drive/holodeck": {
- "stage": "alpha",
- "types": "private",
- "typesPublish": false,
- "mirrorPublish": false
- },
- "@warp-drive/diagnostic": {
- "stage": "alpha",
- "types": "private",
- "typesPublish": false,
- "mirrorPublish": false
- },
- "eslint-plugin-ember-data": {
- "stage": "alpha",
- "types": "private",
- "typesPublish": false,
- "mirrorPublish": false
- },
- "eslint-plugin-warp-drive": {
- "stage": "alpha",
- "types": "private",
- "typesPublish": false,
- "mirrorPublish": false
- },
"@warp-drive/core-types": {
"stage": "alpha",
"types": "alpha"
- },
- "@warp-drive/ember": {
- "stage": "alpha",
- "types": "alpha",
- "typesPublish": false,
- "mirrorPublish": false
- },
- "@warp-drive/schema": {
- "stage": "alpha",
- "types": "private",
- "typesPublish": false,
- "mirrorPublish": false
- },
- "@warp-drive/schema-record": {
- "stage": "alpha",
- "types": "alpha",
- "typesPublish": false,
- "mirrorPublish": true
}
}
}
diff --git a/tests/blueprints/package.json b/tests/blueprints/package.json
index 3ed8e3625af..5e1718cde57 100644
--- a/tests/blueprints/package.json
+++ b/tests/blueprints/package.json
@@ -1,6 +1,6 @@
{
"name": "blueprint-tests",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"private": true,
"description": "Provides tests for blueprints",
"repository": {
diff --git a/tests/builders/package.json b/tests/builders/package.json
index d2fd7a8cbf9..d6373c3874b 100644
--- a/tests/builders/package.json
+++ b/tests/builders/package.json
@@ -1,6 +1,6 @@
{
"name": "builders-test-app",
- "version": "5.4.0-alpha.121",
+ "version": "4.12.8",
"private": true,
"description": "Provides tests for URL and Request Building Capabilities",
"keywords": [],
diff --git a/tests/docs/fixtures/expected.js b/tests/docs/fixtures/expected.js
index 9ce30a7bc97..26d281b8e3f 100644
--- a/tests/docs/fixtures/expected.js
+++ b/tests/docs/fixtures/expected.js
@@ -30,27 +30,6 @@ module.exports = {
'ember-data-overview',
],
classitems: [
- '(public) @ember-data/store Document#data',
- '(public) @ember-data/store Document#errors',
- '(public) @ember-data/store Document#fetch',
- '(public) @ember-data/store Document#first',
- '(public) @ember-data/store Document#identifier',
- '(public) @ember-data/store Document#last',
- '(public) @ember-data/store Document#links',
- '(public) @ember-data/store Document#meta',
- '(public) @ember-data/store Document#next',
- '(public) @ember-data/store Document#prev',
- '(public) @ember-data/store Document#toJSON',
- '(public) @ember-data/store RequestStateService#getLastRequestForRecord',
- '(public) @ember-data/store RequestStateService#getPendingRequestsForRecord',
- '(public) @ember-data/store RequestStateService#subscribeForRecord',
- '(public) @ember-data/store IdentifierCache#getOrCreateDocumentIdentifier',
- '(public) @ember-data/store Store#registerSchema',
- '(public) @ember-data/store Store#schema',
- '(public) @ember-data/store CachePolicy#didRequest [Optional]',
- '(public) @ember-data/store CachePolicy#isHardExpired',
- '(public) @ember-data/store CachePolicy#isSoftExpired',
- '(public) @ember-data/store CachePolicy#willRequest [Optional]',
'(private) @ember-data/adapter BuildURLMixin#_buildURL',
'(private) @ember-data/adapter BuildURLMixin#urlPrefix',
'(private) @ember-data/adapter/json-api JSONAPIAdapter#ajaxOptions',
@@ -72,28 +51,6 @@ module.exports = {
'(private) @ember-data/debug InspectorDataAdapter#observeRecord',
'(private) @ember-data/debug InspectorDataAdapter#watchModelTypes',
'(private) @ember-data/debug InspectorDataAdapter#watchTypeIfUnseen',
- '(public) @warp-drive/build-config/deprecations CurrentDeprecations#DEPRECATE_COMPUTED_CHAINS',
- '(public) @warp-drive/build-config/deprecations CurrentDeprecations#DEPRECATE_LEGACY_IMPORTS',
- '(public) @warp-drive/build-config/deprecations CurrentDeprecations#DEPRECATE_MANY_ARRAY_DUPLICATES',
- '(public) @warp-drive/build-config/deprecations CurrentDeprecations#DEPRECATE_NON_STRICT_ID',
- '(public) @warp-drive/build-config/deprecations CurrentDeprecations#DEPRECATE_NON_STRICT_TYPES',
- '(public) @warp-drive/build-config/deprecations CurrentDeprecations#DEPRECATE_NON_UNIQUE_PAYLOADS',
- '(public) @warp-drive/build-config/deprecations CurrentDeprecations#DEPRECATE_RELATIONSHIP_REMOTE_UPDATE_CLEARING_LOCAL_STATE',
- '(public) @warp-drive/build-config/deprecations CurrentDeprecations#DEPRECATE_STORE_EXTENDS_EMBER_OBJECT',
- '(public) @warp-drive/build-config/deprecations CurrentDeprecations#ENABLE_LEGACY_SCHEMA_SERVICE',
- '(public) @warp-drive/build-config/deprecations CurrentDeprecations#DEPRECATE_EMBER_INFLECTOR',
- '(public) @ember-data/legacy-compat/builders @ember-data/legacy-compat/builders#findAll',
- '(public) @ember-data/legacy-compat/builders @ember-data/legacy-compat/builders#findRecord',
- '(public) @ember-data/legacy-compat/builders @ember-data/legacy-compat/builders#query',
- '(public) @ember-data/legacy-compat/builders @ember-data/legacy-compat/builders#queryRecord',
- '(public) @ember-data/legacy-compat/builders @ember-data/legacy-compat/builders#saveRecord',
- '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#configureAssertFn',
- '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#configureMismatchReporter',
- '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#configureTypeNormalization',
- '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#formattedId',
- '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#formattedType',
- '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#isEquivId',
- '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#isEquivType',
'(private) @ember-data/legacy-compat SnapshotRecordArray#_recordArray',
'(private) @ember-data/legacy-compat SnapshotRecordArray#_snapshots',
'(private) @ember-data/legacy-compat SnapshotRecordArray#constructor',
@@ -134,11 +91,12 @@ module.exports = {
'(private) @ember-data/store RecordArray#store',
'(private) @ember-data/store Snapshot#constructor',
'(private) @ember-data/store Store#_push',
+ '(private) @ember-data/store Store#find',
'(private) @ember-data/store Store#init',
- '(public) @ember-data/active-record/request @ember-data/active-record/request#query',
- '(public) @ember-data/active-record/request @ember-data/active-record/request#findRecord',
'(public) @ember-data/active-record/request @ember-data/active-record/request#createRecord',
'(public) @ember-data/active-record/request @ember-data/active-record/request#deleteRecord',
+ '(public) @ember-data/active-record/request @ember-data/active-record/request#findRecord',
+ '(public) @ember-data/active-record/request @ember-data/active-record/request#query',
'(public) @ember-data/active-record/request @ember-data/active-record/request#updateRecord',
'(public) @ember-data/adapter Adapter#coalesceFindRequests',
'(public) @ember-data/adapter Adapter#createRecord',
@@ -168,8 +126,10 @@ module.exports = {
'(public) @ember-data/adapter BuildURLMixin#urlForQuery',
'(public) @ember-data/adapter BuildURLMixin#urlForQueryRecord',
'(public) @ember-data/adapter BuildURLMixin#urlForUpdateRecord',
- '(public) @ember-data/adapter/json-api JSONAPIAdapter#coalesceFindRequests',
+ '(public) @ember-data/adapter/error @ember-data/adapter/error#errorsArrayToHash',
+ '(public) @ember-data/adapter/error @ember-data/adapter/error#errorsHashToArray',
'(public) @ember-data/adapter/json-api JSONAPIAdapter#buildQuery',
+ '(public) @ember-data/adapter/json-api JSONAPIAdapter#coalesceFindRequests',
'(public) @ember-data/adapter/rest RESTAdapter#buildQuery',
'(public) @ember-data/adapter/rest RESTAdapter#coalesceFindRequests',
'(public) @ember-data/adapter/rest RESTAdapter#createRecord',
@@ -191,24 +151,15 @@ module.exports = {
'(public) @ember-data/adapter/rest RESTAdapter#sortQueryParams',
'(public) @ember-data/adapter/rest RESTAdapter#updateRecord',
'(public) @ember-data/adapter/rest RESTAdapter#useFetch',
- '(public) @warp-drive/build-config/debugging DebugLogging#LOG_GRAPH',
- '(public) @warp-drive/build-config/debugging DebugLogging#LOG_IDENTIFIERS',
- '(public) @warp-drive/build-config/debugging DebugLogging#LOG_INSTANCE_CACHE',
- '(public) @warp-drive/build-config/debugging DebugLogging#LOG_MUTATIONS',
- '(public) @warp-drive/build-config/debugging DebugLogging#LOG_NOTIFICATIONS',
- '(public) @warp-drive/build-config/debugging DebugLogging#LOG_OPERATIONS',
- '(public) @warp-drive/build-config/debugging DebugLogging#LOG_PAYLOADS',
- '(public) @warp-drive/build-config/debugging DebugLogging#LOG_REQUESTS',
- '(public) @warp-drive/build-config/debugging DebugLogging#LOG_REQUEST_STATUS',
'(public) @ember-data/experimental-preview-types Adapter#coalesceFindRequests [OPTIONAL]',
'(public) @ember-data/experimental-preview-types Adapter#createRecord',
'(public) @ember-data/experimental-preview-types Adapter#deleteRecord',
'(public) @ember-data/experimental-preview-types Adapter#destroy [OPTIONAL]',
'(public) @ember-data/experimental-preview-types Adapter#findAll',
'(public) @ember-data/experimental-preview-types Adapter#findBelongsTo [OPTIONAL]',
+ '(public) @ember-data/experimental-preview-types Adapter#findhasMany [OPTIONAL]',
'(public) @ember-data/experimental-preview-types Adapter#findMany [OPTIONAL]',
'(public) @ember-data/experimental-preview-types Adapter#findRecord',
- '(public) @ember-data/experimental-preview-types Adapter#findhasMany [OPTIONAL]',
'(public) @ember-data/experimental-preview-types Adapter#generateIdForRecord [OPTIONAL]',
'(public) @ember-data/experimental-preview-types Adapter#groupRecordsForFindMany [OPTIONAL]',
'(public) @ember-data/experimental-preview-types Adapter#query',
@@ -219,6 +170,7 @@ module.exports = {
'(public) @ember-data/experimental-preview-types Adapter#shouldReloadRecord [OPTIONAL]',
'(public) @ember-data/experimental-preview-types Adapter#updateRecord',
'(public) @ember-data/experimental-preview-types Cache#changedAttrs',
+ '(public) @ember-data/experimental-preview-types Cache#changedRelationships',
'(public) @ember-data/experimental-preview-types Cache#clientDidCreate',
'(public) @ember-data/experimental-preview-types Cache#commitWasRejected',
'(public) @ember-data/experimental-preview-types Cache#didCommit',
@@ -229,6 +181,7 @@ module.exports = {
'(public) @ember-data/experimental-preview-types Cache#getErrors',
'(public) @ember-data/experimental-preview-types Cache#getRelationship',
'(public) @ember-data/experimental-preview-types Cache#hasChangedAttrs',
+ '(public) @ember-data/experimental-preview-types Cache#hasChangedRelationships',
'(public) @ember-data/experimental-preview-types Cache#hydrate',
'(public) @ember-data/experimental-preview-types Cache#isDeleted',
'(public) @ember-data/experimental-preview-types Cache#isDeletionCommitted',
@@ -241,15 +194,13 @@ module.exports = {
'(public) @ember-data/experimental-preview-types Cache#peekRequest',
'(public) @ember-data/experimental-preview-types Cache#put',
'(public) @ember-data/experimental-preview-types Cache#rollbackAttrs',
+ '(public) @ember-data/experimental-preview-types Cache#rollbackRelationships',
'(public) @ember-data/experimental-preview-types Cache#setAttr',
'(public) @ember-data/experimental-preview-types Cache#setIsDeleted',
'(public) @ember-data/experimental-preview-types Cache#unloadRecord',
'(public) @ember-data/experimental-preview-types Cache#upsert',
'(public) @ember-data/experimental-preview-types Cache#version',
'(public) @ember-data/experimental-preview-types Cache#willCommit',
- '(public) @ember-data/experimental-preview-types Cache#changedRelationships',
- '(public) @ember-data/experimental-preview-types Cache#hasChangedRelationships',
- '(public) @ember-data/experimental-preview-types Cache#rollbackRelationships',
'(public) @ember-data/experimental-preview-types Serializer#destroy [OPTIONAL]',
'(public) @ember-data/experimental-preview-types Serializer#normalize [OPTIONAL]',
'(public) @ember-data/experimental-preview-types Serializer#normalizeResponse',
@@ -257,6 +208,7 @@ module.exports = {
'(public) @ember-data/experimental-preview-types Serializer#serialize',
'(public) @ember-data/experimental-preview-types Serializer#serializeIntoHash [OPTIONAL]',
'(public) @ember-data/json-api Cache#changedAttrs',
+ '(public) @ember-data/json-api Cache#changedRelationships',
'(public) @ember-data/json-api Cache#clientDidCreate',
'(public) @ember-data/json-api Cache#commitWasRejected',
'(public) @ember-data/json-api Cache#didCommit',
@@ -266,6 +218,7 @@ module.exports = {
'(public) @ember-data/json-api Cache#getErrors',
'(public) @ember-data/json-api Cache#getRelationship',
'(public) @ember-data/json-api Cache#hasChangedAttrs',
+ '(public) @ember-data/json-api Cache#hasChangedRelationships',
'(public) @ember-data/json-api Cache#hydrate',
'(public) @ember-data/json-api Cache#isDeleted',
'(public) @ember-data/json-api Cache#isDeletionCommitted',
@@ -278,37 +231,47 @@ module.exports = {
'(public) @ember-data/json-api Cache#peekRequest',
'(public) @ember-data/json-api Cache#put',
'(public) @ember-data/json-api Cache#rollbackAttrs',
+ '(public) @ember-data/json-api Cache#rollbackRelationships',
'(public) @ember-data/json-api Cache#setAttr',
'(public) @ember-data/json-api Cache#setIsDeleted',
'(public) @ember-data/json-api Cache#unloadRecord',
'(public) @ember-data/json-api Cache#upsert',
'(public) @ember-data/json-api Cache#version',
'(public) @ember-data/json-api Cache#willCommit',
- '(public) @ember-data/json-api Cache#changedRelationships',
- '(public) @ember-data/json-api Cache#hasChangedRelationships',
- '(public) @ember-data/json-api Cache#rollbackRelationships',
'(public) @ember-data/json-api/request @ember-data/json-api/request#buildQueryParams',
- '(public) @ember-data/json-api/request @ember-data/json-api/request#findRecord',
- '(public) @ember-data/json-api/request @ember-data/json-api/request#query',
- '(public) @ember-data/json-api/request @ember-data/json-api/request#postQuery',
'(public) @ember-data/json-api/request @ember-data/json-api/request#createRecord',
'(public) @ember-data/json-api/request @ember-data/json-api/request#deleteRecord',
- '(public) @ember-data/json-api/request @ember-data/json-api/request#updateRecord',
+ '(public) @ember-data/json-api/request @ember-data/json-api/request#findRecord',
+ '(public) @ember-data/json-api/request @ember-data/json-api/request#postQuery',
+ '(public) @ember-data/json-api/request @ember-data/json-api/request#query',
'(public) @ember-data/json-api/request @ember-data/json-api/request#serializePatch',
'(public) @ember-data/json-api/request @ember-data/json-api/request#serializeResources',
'(public) @ember-data/json-api/request @ember-data/json-api/request#setBuildURLConfig',
+ '(public) @ember-data/json-api/request @ember-data/json-api/request#updateRecord',
'(public) @ember-data/legacy-compat SnapshotRecordArray#adapterOptions',
'(public) @ember-data/legacy-compat SnapshotRecordArray#include',
'(public) @ember-data/legacy-compat SnapshotRecordArray#length',
'(public) @ember-data/legacy-compat SnapshotRecordArray#modelName',
'(public) @ember-data/legacy-compat SnapshotRecordArray#snapshots',
+ '(public) @ember-data/legacy-compat SnapshotRecordArray#type',
+ '(public) @ember-data/legacy-compat/builders @ember-data/legacy-compat/builders#findAll',
+ '(public) @ember-data/legacy-compat/builders @ember-data/legacy-compat/builders#findRecord',
+ '(public) @ember-data/legacy-compat/builders @ember-data/legacy-compat/builders#query',
+ '(public) @ember-data/legacy-compat/builders @ember-data/legacy-compat/builders#queryRecord',
+ '(public) @ember-data/legacy-compat/builders @ember-data/legacy-compat/builders#saveRecord',
+ '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#configureAssertFn',
+ '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#configureMismatchReporter',
+ '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#configureTypeNormalization',
+ '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#formattedId',
+ '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#formattedType',
+ '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#isEquivId',
+ '(public) @ember-data/legacy-compat/utils @ember-data/legacy-compat/utils#isEquivType',
'(public) @ember-data/model @ember-data/model#attr',
'(public) @ember-data/model @ember-data/model#belongsTo',
'(public) @ember-data/model @ember-data/model#hasMany',
'(public) @ember-data/model BelongsToReference#id',
'(public) @ember-data/model BelongsToReference#identifier',
'(public) @ember-data/model BelongsToReference#key',
- '(public) @ember-data/model BelongsToReference#type',
'(public) @ember-data/model BelongsToReference#link',
'(public) @ember-data/model BelongsToReference#links',
'(public) @ember-data/model BelongsToReference#load',
@@ -316,6 +279,7 @@ module.exports = {
'(public) @ember-data/model BelongsToReference#push',
'(public) @ember-data/model BelongsToReference#reload',
'(public) @ember-data/model BelongsToReference#remoteType',
+ '(public) @ember-data/model BelongsToReference#type',
'(public) @ember-data/model BelongsToReference#value',
'(public) @ember-data/model BelongsToReference#value',
'(public) @ember-data/model Errors#add',
@@ -329,7 +293,6 @@ module.exports = {
'(public) @ember-data/model HasManyReference#identifiers',
'(public) @ember-data/model HasManyReference#ids',
'(public) @ember-data/model HasManyReference#key',
- '(public) @ember-data/model HasManyReference#type',
'(public) @ember-data/model HasManyReference#link',
'(public) @ember-data/model HasManyReference#links',
'(public) @ember-data/model HasManyReference#load',
@@ -337,6 +300,7 @@ module.exports = {
'(public) @ember-data/model HasManyReference#push',
'(public) @ember-data/model HasManyReference#reload',
'(public) @ember-data/model HasManyReference#remoteType',
+ '(public) @ember-data/model HasManyReference#type',
'(public) @ember-data/model HasManyReference#value',
'(public) @ember-data/model Model#adapterError',
'(public) @ember-data/model Model#attributes',
@@ -389,16 +353,16 @@ module.exports = {
'(public) @ember-data/model PromiseManyArray#meta',
'(public) @ember-data/model PromiseManyArray#reload',
'(public) @ember-data/model PromiseManyArray#then',
- '(public) @ember-data/request RequestManager#request',
- '(public) @ember-data/request RequestManager#use',
- '(public) @ember-data/request RequestManager#useCache',
'(public) @ember-data/request CacheHandler#request',
'(public) @ember-data/request Handler#request',
'(public) @ember-data/request Future#abort',
'(public) @ember-data/request Future#getStream',
- '(public) @ember-data/request Future#onFinalize',
'(public) @ember-data/request Future#id',
'(public) @ember-data/request Future#lid',
+ '(public) @ember-data/request Future#onFinalize',
+ '(public) @ember-data/request RequestManager#request',
+ '(public) @ember-data/request RequestManager#use',
+ '(public) @ember-data/request RequestManager#useCache',
'(public) @ember-data/request-utils @ember-data/request-utils#buildBaseURL',
'(public) @ember-data/request-utils @ember-data/request-utils#buildQueryParams',
'(public) @ember-data/request-utils @ember-data/request-utils#filterEmpty',
@@ -410,10 +374,10 @@ module.exports = {
'(public) @ember-data/request-utils CachePolicy#invalidateRequestsForType',
'(public) @ember-data/request-utils CachePolicy#isHardExpired',
'(public) @ember-data/request-utils CachePolicy#isSoftExpired',
- '(public) @ember-data/rest/request @ember-data/rest/request#findRecord',
- '(public) @ember-data/rest/request @ember-data/rest/request#query',
'(public) @ember-data/rest/request @ember-data/rest/request#createRecord',
'(public) @ember-data/rest/request @ember-data/rest/request#deleteRecord',
+ '(public) @ember-data/rest/request @ember-data/rest/request#findRecord',
+ '(public) @ember-data/rest/request @ember-data/rest/request#query',
'(public) @ember-data/rest/request @ember-data/rest/request#updateRecord',
'(public) @ember-data/serializer Serializer#normalize',
'(public) @ember-data/serializer Serializer#normalizeResponse',
@@ -477,13 +441,42 @@ module.exports = {
'(public) @ember-data/serializer/rest RESTSerializer#serialize',
'(public) @ember-data/serializer/rest RESTSerializer#serializeIntoHash',
'(public) @ember-data/serializer/rest RESTSerializer#serializePolymorphicType',
+ '(public) @ember-data/store @ember-data/store#normalizeModelName',
'(public) @ember-data/store @ember-data/store#recordIdentifierFor',
'(public) @ember-data/store @ember-data/store#setIdentifierForgetMethod',
'(public) @ember-data/store @ember-data/store#setIdentifierGenerationMethod',
'(public) @ember-data/store @ember-data/store#setIdentifierResetMethod',
'(public) @ember-data/store @ember-data/store#setIdentifierUpdateMethod',
'(public) @ember-data/store @ember-data/store#setKeyInfoForResource',
+ '(public) @ember-data/store CachePolicy#didRequest [Optional]',
+ '(public) @ember-data/store CachePolicy#isHardExpired',
+ '(public) @ember-data/store CachePolicy#isSoftExpired',
+ '(public) @ember-data/store CachePolicy#willRequest [Optional]',
+ '(public) @ember-data/store SchemaService#attributesDefinitionFor',
+ '(public) @ember-data/store SchemaService#derivation',
+ '(public) @ember-data/store SchemaService#doesTypeExist',
+ '(public) @ember-data/store SchemaService#fields',
+ '(public) @ember-data/store SchemaService#hashFn',
+ '(public) @ember-data/store SchemaService#hasResource',
+ '(public) @ember-data/store SchemaService#hasTrait',
+ '(public) @ember-data/store SchemaService#registerDerivations',
+ '(public) @ember-data/store SchemaService#registerHashFn',
+ '(public) @ember-data/store SchemaService#registerResource',
+ '(public) @ember-data/store SchemaService#registerResources',
+ '(public) @ember-data/store