Releases: orbitjs/ember-orbit
v0.17.3
This release improves upon the previous release which allowed source and strategy factories to conditionally return null
or undefined
to signal that they should be ignored by the coordinator factory. This approach was flawed in that the returned value still ends up in the application's container, and non-objects are not handled properly by ember when the container is destroyed. This could cause issues in test teardown for instance.
Instead of returning a custom value from create
, it is now recommended that the default export of the source or strategy module be conditionally changed to a non-factory (e.g. null
or undefined
) to signal that it should be ignored. This avoids the call to lookup and thus prevents nullish values from entering the container.
For example, the following strategy will be conditionally included for all non-production builds:
// app/data-strategies/event-logging.js
import { EventLoggingStrategy } from '@orbit/coordinator';
import config from 'example/config/environment';
const factory = {
create() {
return new EventLoggingStrategy();
}
};
// Conditionally include this strategy
export default config.environment !== 'production' ? factory : null;
Changelog
π Enhancement
Committers: 1
- Dan Gebhardt (@dgeb)
v0.17.2
Changelog
Source and strategy factories can now return null
or undefined
from create()
, in which case they will be ignored by the coordinator factory that typically instantiates them. This allows for conditional creation based upon an env setting or other cue.
π Enhancement
Committers: 1
- Dan Gebhardt (@dgeb)
v0.17.1
Changelog
π Bug Fix
π Documentation
- #393 Add 'Customizing validators' section to README (@dgeb)
- #391 Fix broken doc links in the README (@bmoeskau)
π Internal
- #398 Bump @orbit/memory@^0.17.2 (@dgeb)
- #395 Bump follow-redirects from 1.14.7 to 1.14.8 (@dependabot[bot])
- #394 Bump mout from 1.2.2 to 1.2.3 (@dependabot[bot])
Committers: 2
v0.17.0
This is the first production release of ember-orbit v0.17. Please review the Orbit docs for an overview of what's new in v0.17 of Orbit. In addition to understanding the changes that Orbit itself has undergone, it's important to understand the particular changes made to EO as you upgrade from v0.16.x.
Removal of implicit injections
In order to make EO compatible with Ember 4.0, implicit injections have been removed. Thus, the store
service is no longer automatically injected into all controllers and routes. To access this service, you'll need to declare it explicitly:
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class PlanetsRoute extends Route {
@service store;
async model() {
return this.store.findRecords('planet');
}
}
In addition, the standard injections (schema
, keyMap
, normalizer
, and validatorFor
) that each Orbit source relies upon are no longer injected automatically. As described in #367, you can use the applyStandardSourceInjections
utility in your source factories as follows:
// /app/data-sources/remote.js
import SourceClass from '@orbit/jsonapi';
import { applyStandardSourceInjections } from 'ember-orbit';
export default {
create(injections = {}) {
applyStandardSourceInjections(injections);
injections.name = 'remote';
return new SourceClass(injections);
}
};
This utility method is now used in all sources generated from blueprints with ember g data-source NAME
.
Main bucket service
If you are using one or more buckets to store orbit state in browser storage, please see #382 to understand how to upgrade your bucket initializers for v0.17 compatibility.
Validators enabled by default
Orbit v0.17 now includes validators enabled by default in all sources. Validations are useful to ensure that your data matches its type expectations and that operations and query expressions are well formed. Of course, they also add some extra code and processing, which you may want to eliminate (perhaps always or perhaps only for production environments). You can disable validators across all sources by setting Orbit's skipValidatorService
environment flag to true
in config/environment
:
module.exports = function (environment) {
let ENV = {
// ... other settings here
orbit: {
skipValidatorService: true
}
};
return ENV;
};
If you want to use validators but extend them to include custom validators, you can override the standard validator service by generating your own data-validator
service that passes custom arguments to buildRecordValidatorFor
.
For instance, in order to provide a custom validator for an address
type:
// app/services/data-validator.js
import { buildRecordValidatorFor } from '@orbit/records';
const validators = {
address: (input) => {
if (typeof input?.country !== 'string') {
return [
{
validator: 'address',
validation: 'country',
description: 'is not a string',
ref: input,
},
];
}
},
};
export default {
create() {
return buildRecordValidatorFor({ validators });
},
};
This custom validator service will be injected into all your orbit sources via applyStandardSourceInjections
, as described above.
Model-aware normalizers
A new model-aware normalizer has been introduced to normalize record field and identity data across EO. This normalizer is based on the new StandardRecordNormalizer from @orbit/records
.
With this normalizer, you can now use a number of convenient forms to provide a record's identity:
// type / id
store.query((q) => q.findRecord({ type: 'planet', id: '123' }));
// type / key / value
store.query((q) => q.findRecord({ type: 'planet', key: 'remoteId', value: 'abc' }));
// EO Model
store.query((q) => q.findRecord(earth));
And you can express a record's fields in the standard Orbit expanded form:
let [earth, mars] = await store.update((t) => [
// flattened model-aware fields
t.addRecord({
type: 'planet',
name: 'Earth',
moons: [theMoon]
}),
// expanded form
t.addRecord({
type: 'planet',
attributes: {
name: 'Jupiter'
},
relationships: {
moons: {
data: [io, europa]
}
}
})
]);
Goodbye ArrayProxy
Ember's ArrayProxy
was used in v0.16 to represent "live" resultsets whose contents could update to reflect changes in a source's cache. This has been replaced in v0.17 with an orbit specific concept called a LiveQuery
, which has an extended form in EO that includes Glimmer-based reactivity.
Every LiveQuery
has a value
property that can be used to access the raw result, which will be a native JS array of Model
s (if a collection), a single Model
, or undefined
. LiveQuery
results are also iterable and can be used directly in templates (with no need to reference .value
).
For instance, a component may fetch a LiveQuery
from the store's cache:
this.planets = store.cache.liveQuery((q) => q.findRecords('planet'));
console.log(planets.value) // [earth, mars]
console.log(planets.length) // 2
And its template could use those results just as before:
A model's hasMany
relationships use live queries internally, although accessing the field returns the value
of the LiveQuery
directly. Thus, planet.moons
will now return a native array of Model
s. There's no longer a need to access planet.moons.content
to get this array (as in v0.16).
$-prefixed Model methods and properties
In order to avoid conflicts with standard user-provided Model
fields, all of EO's standard properties and methods on Model
are now prefixed with a $
(see #342). Thus, instead of planet.getData()
, call planet.$getData()
. Instead of planet.identity
, access planet.$identity
.
The old methods and properties will continue to work but have been deprecated.
Updates to Models, Stores, and Caches
There has been a lot of confusion in the past over mutations made to model fields, how and when they apply to their associated cache and store, and how they flow through Orbit sources. Much of this confusion has been due to models reflecting state immediately and synchronously via their fields, but the store requiring async mutations to have data flow through to other sources. With all these factors, the meaning and timing of simply setting planet.name = 'Earth'
becomes very tricky to understand.
In order to simplify both these important issues, some fundamental relationships in EO have been been changed. Models are always now associated only with a Cache
and no longer directly reference a Store
. Any updates applied directly to models are applied to their associated cache. Thus planet.name = 'Earth'
is a synchronous assignment which will immediately be reflected when accessing planet.name
. So how do changes to models ever make it back to the store and flow through to other sources?
Orbit itself has been updated in v0.17 to synchronously track changes in forks. Thus, when changes are made to forked caches, they are tracked and can be merged back to a base source / store.
To enforce this flow, only forked caches are able to be updated directly. This provides protection against data loss, since changes to caches do not articipate in Orbit's data flows. An exception is made for forks because the changes are tracked and applied back to stores via merge
. If you want to override these protections and update a non-forked cache, you can set cache.allowUpdates = true
, but know that those updates will never leave the cache.
Let's wrap this up with some simple rules:
-
If you want to apply a series of synchronous changes, say while handling user input in a form, then fork a base store and then update the fork directly, through its cache or models. Call
merge
to apply those changes back to the base store. -
If you want to apply changes directly to the store and have those changes flow to other orbit sources, call one of the async update methods directly on the store (
addRecord
,updateRecord
,updateRecordFields
,removeRecord
, orupdate
).
More details can be found in the Updating Data
section of the readme.
If you have any questions or problems updating your EO applications, please reach out on gitter.
Changelog (for v0.17.0, since v0.17.0-beta.23)
π Internal
Committers: 1
- Dan Gebhardt (@dgeb)
v0.17.0-beta.23
v0.17.0-beta.22
v0.17.0-beta.21
v0.17.0-beta.20
v0.17.0-beta.19
This release finishes the work started in beta.18 to eliminate implicit injections from ember-orbit. #382 addresses the issue of implicit injections used by buckets. As noted in that PR, please update your bucket initializers to follow the following form:
import BucketFactory from '../data-buckets/main';
export function initialize(application) {
const orbitConfig = application.resolveRegistration('ember-orbit:config');
// Register this bucket as the main bucket service so that it can be injected
// into sources via `applyStandardSourceInjections`.
//
// IMPORTANT: If your app has more than one bucket, only register one as the
// main bucket service.
application.register(`service:${orbitConfig.services.bucket}`, BucketFactory);
}
export default {
name: 'main-bucket-initializer',
after: 'ember-orbit-config',
initialize,
};
Changelog
π₯ Breaking Change
π Internal
Committers: 1
- Dan Gebhardt (@dgeb)
v0.17.0-beta.18
This release includes a couple breaking changes to bring compatibility with ember v4.x:
- Support has been dropped for ember < v3.24 (see #373)
- EO no longer uses implicit injections, which were deprecated by ember prior to v4.
As discussed in #367, a new utility method has been added, applyStandardSourceInjections
, which can be invoked to apply standard injections (schema
, keyMap
, normalizer
, and validatorFor
) to a source during construction. Alternatively, these injections can also be applied on a per-source basis.
This should be considered a breaking change because applyStandardSourceInjections
must now be invoked for previously defined sources other than the store
.
For instance:
// /app/data-sources/remote.js
import SourceClass from '@orbit/jsonapi';
import { applyStandardSourceInjections } from 'ember-orbit';
export default {
create(injections = {}) {
applyStandardSourceInjections(injections);
injections.name = 'remote';
return new SourceClass(injections);
}
};
Please update your existing source factories as shown above!
The new blueprints are structured in this way, which should cover new source factories.
π₯ Breaking Change
- #373 Update ember v3.25.0...v4.1.0 (@dgeb)
- #367 [BREAKING] Replace deprecated implicit injections with explicit injections (@dgeb)
π Enhancement
- #377 Expose store on Cache (@dgeb)
- #372 Use camelize from @orbit/serializers instead of @ember/string (@dgeb)
π Internal
- #365 Bump tmpl from 1.0.4 to 1.0.5 (@dependabot[bot])
- #375 Bump browserslist from 4.16.3 to 4.19.1 (@dependabot[bot])
- #374 Remove stagnant docs dir (@dgeb)
Committers: 1
- Dan Gebhardt (@dgeb)