Closed ef4 closed 3 years ago
@ef4 You are indeed very close. Here's a similar snippet I've shared on gitter:
import { buildSerializerSettingsFor, buildInflector } from '@orbit/serializers';
let JSONAPISettings = {
serializerSettingsFor: buildSerializerSettingsFor({
sharedSettings: {
inflectors: {
pluralize: buildInflector(
{ cow: 'kine', person: 'people' }, // custom mappings
(input) => `${input}s` // naive pluralizer, specified as a fallback
),
singularize: buildInflector(
{ kine: 'cow', people: 'person' }, // custom mappings
(arg) => arg.substr(0, arg.length - 1) // naive singularizer, specified as a fallback
)
}
},
settingsByType: {
[JSONAPISerializers.ResourceField]: {
serializationOptions: { inflectors: ['dasherize'] }
},
[JSONAPISerializers.ResourceFieldParam]: {
serializationOptions: { inflectors: ['dasherize'] }
},
[JSONAPISerializers.ResourceFieldPath]: {
serializationOptions: { inflectors: ['dasherize'] }
},
[JSONAPISerializers.ResourceType]: {
serializationOptions: { inflectors: ['pluralize', 'dasherize'] }
},
[JSONAPISerializers.ResourceTypePath]: {
serializationOptions: { inflectors: ['pluralize', 'dasherize'] }
}
}
})
};
The key here is that standard serializers know about certain inverse inflectors that are identified by name. The string serializer knows that the inverse of pluralize
is singularize
for instance.
By defining our custom inflector by name in sharedSettings
, these can be shared across all serializers. And you can continue to reference those inflectors by name in your serializaitonOptions
.
IMO one awkward piece here is the manual inversion of the custom mappings, which certainly could be handled in a more DRY and clever way.
To follow up, something along these lines keeps the custom mappings more DRY:
import { buildSerializerSettingsFor, buildInflector } from '@orbit/serializers';
const pluralizations = { cow: 'kine', person: 'people' };
const singularizations = Object.keys(pluralizations).reduce((inverse, k) => { inverse[pluralizations[k]] = k; return inverse; }, {});
let JSONAPISettings = {
serializerSettingsFor: buildSerializerSettingsFor({
sharedSettings: {
inflectors: {
pluralize: buildInflector(
pluralizations,
(input) => `${input}s` // naive pluralizer, specified as a fallback
),
singularize: buildInflector(
singularizations,
(arg) => arg.substr(0, arg.length - 1) // naive singularizer, specified as a fallback
)
}
},
settingsByType: {
[JSONAPISerializers.ResourceField]: {
serializationOptions: { inflectors: ['dasherize'] }
},
[JSONAPISerializers.ResourceFieldParam]: {
serializationOptions: { inflectors: ['dasherize'] }
},
[JSONAPISerializers.ResourceFieldPath]: {
serializationOptions: { inflectors: ['dasherize'] }
},
[JSONAPISerializers.ResourceType]: {
serializationOptions: { inflectors: ['pluralize', 'dasherize'] }
},
[JSONAPISerializers.ResourceTypePath]: {
serializationOptions: { inflectors: ['pluralize', 'dasherize'] }
}
}
})
};
Thanks. This looks like it will solve my problem.
Totally as an aside, one of my favorite little new ES feature is how Object.fromEntries
can make this clearer:
const singularizations = Object.fromEntries(Object.entries(pluralizations).map(([k,v]) => [v,k]))
Ah yes, that is sooo much clearer!
Upgrading to 0.17.beta, I need to reproduce the pluralization I had in 0.16 for (I think)
JSONAPISerializers.ResourceTypePath
andJSONAPISerializers.ResourceType
. This nearly works:But the pluralization is naive, so I need to use
buildInflector
to extend it:And this works in the forward direction, but I lose inverse inflection that was working when I only had the default
pluralize
. Specifically, URLs and request bodies get pluralized, but then when deserializing the response I get "Model is not defined" errors because the JSON:APItype
in the response has not been singularized.How can I get both custom pluralization and inversion?