ember-data-model-fragments 7.0.3 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,190 @@
1
+ function getType(resource) {
2
+ return typeof resource === 'string' ? resource : resource.type;
3
+ }
4
+
5
+ function isFragmentAttribute(meta) {
6
+ return (
7
+ typeof meta === 'object' &&
8
+ meta !== null &&
9
+ 'kind' in meta &&
10
+ meta.isFragment === true &&
11
+ (meta.kind === 'fragment' ||
12
+ meta.kind === 'fragment-array' ||
13
+ meta.kind === 'array')
14
+ );
15
+ }
16
+
17
+ function transformFragmentMeta(name, meta) {
18
+ return {
19
+ name,
20
+ key: name,
21
+ kind: 'attribute',
22
+ type: meta.type,
23
+ options: {
24
+ ...meta.options,
25
+ isFragment: true,
26
+ fragmentKind: meta.kind,
27
+ modelName: meta.modelName,
28
+ },
29
+ isAttribute: true,
30
+ isFragment: true,
31
+ modelName: meta.modelName,
32
+ };
33
+ }
34
+
35
+ function mergedCacheFields(fields) {
36
+ const cacheFields = new Map();
37
+
38
+ fields.forEach((field, key) => {
39
+ if (field.kind === '@id' || field.kind === '@hash') {
40
+ return;
41
+ }
42
+
43
+ cacheFields.set(field.sourceKey || field.name || key, field);
44
+ });
45
+
46
+ return cacheFields;
47
+ }
48
+
49
+ export default class FragmentSchemaService {
50
+ constructor(store, schema) {
51
+ this.store = store;
52
+ this._schema = schema;
53
+ }
54
+
55
+ _fragmentDefinitionsFor(resource) {
56
+ const type = getType(resource);
57
+ const modelClass = this.store.modelFor(type);
58
+ const definitions = Object.create(null);
59
+
60
+ modelClass.eachComputedProperty((name, meta) => {
61
+ if (isFragmentAttribute(meta)) {
62
+ definitions[name] = transformFragmentMeta(name, meta);
63
+ }
64
+ });
65
+
66
+ return definitions;
67
+ }
68
+
69
+ _mergedFields(resource) {
70
+ const fields = new Map(this._schema.fields(resource));
71
+ const fragments = this._fragmentDefinitionsFor(resource);
72
+
73
+ Object.keys(fragments).forEach((name) => {
74
+ fields.set(name, fragments[name]);
75
+ });
76
+
77
+ return fields;
78
+ }
79
+
80
+ resourceTypes() {
81
+ return this._schema.resourceTypes();
82
+ }
83
+
84
+ hasResource(resource) {
85
+ return this._schema.hasResource(resource);
86
+ }
87
+
88
+ hasTrait(type) {
89
+ return this._schema.hasTrait(type);
90
+ }
91
+
92
+ resourceHasTrait(resource, trait) {
93
+ return this._schema.resourceHasTrait(resource, trait);
94
+ }
95
+
96
+ fields(resource) {
97
+ return this._mergedFields(resource);
98
+ }
99
+
100
+ cacheFields(resource) {
101
+ return mergedCacheFields(this._mergedFields(resource));
102
+ }
103
+
104
+ transformation(field) {
105
+ return this._schema.transformation(field);
106
+ }
107
+
108
+ hashFn(field) {
109
+ return this._schema.hashFn(field);
110
+ }
111
+
112
+ derivation(field) {
113
+ return this._schema.derivation(field);
114
+ }
115
+
116
+ resource(resource) {
117
+ const schema = this._schema.resource(resource);
118
+ const fields = this._mergedFields(resource);
119
+
120
+ return {
121
+ ...schema,
122
+ fields: Array.from(fields.values()),
123
+ cacheFields: mergedCacheFields(fields),
124
+ };
125
+ }
126
+
127
+ registerResources(schemas) {
128
+ this._schema.registerResources(schemas);
129
+ }
130
+
131
+ registerResource(schema) {
132
+ this._schema.registerResource(schema);
133
+ }
134
+
135
+ registerTransformation(transform) {
136
+ this._schema.registerTransformation(transform);
137
+ }
138
+
139
+ registerDerivation(derivation) {
140
+ this._schema.registerDerivation(derivation);
141
+ }
142
+
143
+ registerHashFn(hashFn) {
144
+ this._schema.registerHashFn(hashFn);
145
+ }
146
+
147
+ registerTrait(trait) {
148
+ this._schema.registerTrait?.(trait);
149
+ }
150
+
151
+ attributesDefinitionFor(resource) {
152
+ const attributes = this._schema.attributesDefinitionFor
153
+ ? { ...this._schema.attributesDefinitionFor(resource) }
154
+ : Object.create(null);
155
+ const fragments = this._fragmentDefinitionsFor(resource);
156
+
157
+ return Object.assign(attributes, fragments);
158
+ }
159
+
160
+ relationshipsDefinitionFor(resource) {
161
+ return this._schema.relationshipsDefinitionFor?.(resource);
162
+ }
163
+
164
+ doesTypeExist(type) {
165
+ return this._schema.doesTypeExist?.(type) ?? this.hasResource({ type });
166
+ }
167
+
168
+ CAUTION_MEGA_DANGER_ZONE_registerExtension(extension) {
169
+ this._schema.CAUTION_MEGA_DANGER_ZONE_registerExtension?.(extension);
170
+ }
171
+
172
+ CAUTION_MEGA_DANGER_ZONE_resourceExtensions(resource) {
173
+ return this._schema.CAUTION_MEGA_DANGER_ZONE_resourceExtensions?.(resource);
174
+ }
175
+
176
+ CAUTION_MEGA_DANGER_ZONE_objectExtensions(field, resolvedType) {
177
+ return this._schema.CAUTION_MEGA_DANGER_ZONE_objectExtensions?.(
178
+ field,
179
+ resolvedType,
180
+ );
181
+ }
182
+
183
+ CAUTION_MEGA_DANGER_ZONE_arrayExtensions(field) {
184
+ return this._schema.CAUTION_MEGA_DANGER_ZONE_arrayExtensions?.(field);
185
+ }
186
+
187
+ CAUTION_MEGA_DANGER_ZONE_hasExtension(extension) {
188
+ return this._schema.CAUTION_MEGA_DANGER_ZONE_hasExtension?.(extension);
189
+ }
190
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Re-exports for ember-data-model-fragments serializers.
3
+ *
4
+ * Usage:
5
+ *
6
+ * ```js
7
+ * // For JSONSerializer (default)
8
+ * import FragmentSerializer from 'ember-data-model-fragments/serializer';
9
+ *
10
+ * // For RESTSerializer
11
+ * import { FragmentRESTSerializer } from 'ember-data-model-fragments/serializer';
12
+ *
13
+ * // For JSONAPISerializer
14
+ * import { FragmentJSONAPISerializer } from 'ember-data-model-fragments/serializer';
15
+ * ```
16
+ */
17
+
18
+ export { default } from './serializers/fragment';
19
+ export { default as FragmentSerializer } from './serializers/fragment';
20
+ export { default as FragmentRESTSerializer } from './serializers/rest';
21
+ export { default as FragmentJSONAPISerializer } from './serializers/json-api';
@@ -0,0 +1,85 @@
1
+ import JSONSerializer from '@ember-data/serializer/json';
2
+ import {
3
+ fragmentTransformFor,
4
+ fragmentApplyTransforms,
5
+ fragmentExtractAttributes,
6
+ fragmentSerialize,
7
+ } from './utils';
8
+
9
+ /**
10
+ FragmentSerializer is the base serializer class for ember-data-model-fragments.
11
+ Extends JSONSerializer.
12
+
13
+ To use fragment serialization properly, your serializers should extend FragmentSerializer:
14
+
15
+ ```js
16
+ // app/serializers/application.js
17
+ import FragmentSerializer from 'ember-data-model-fragments/serializer';
18
+
19
+ export default class ApplicationSerializer extends FragmentSerializer {}
20
+ ```
21
+
22
+ @class FragmentSerializer
23
+ @extends JSONSerializer
24
+ @public
25
+ */
26
+ export default class FragmentSerializer extends JSONSerializer {
27
+ serialize(snapshot, options) {
28
+ return fragmentSerialize(
29
+ this,
30
+ snapshot,
31
+ super.serialize(snapshot, options),
32
+ );
33
+ }
34
+
35
+ /**
36
+ Enables fragment properties to have custom transforms based on the fragment
37
+ type, so that deserialization does not have to happen on the fly
38
+
39
+ @method transformFor
40
+ @param {String} attributeType - The attribute type to get the transform for
41
+ @return {Transform}
42
+ @public
43
+ */
44
+ transformFor(attributeType) {
45
+ return fragmentTransformFor(
46
+ this,
47
+ attributeType,
48
+ JSONSerializer.prototype.transformFor,
49
+ );
50
+ }
51
+
52
+ /**
53
+ Override applyTransforms to handle polymorphic fragments with a typeKey function
54
+
55
+ @method applyTransforms
56
+ @param {Class} typeClass - The model class
57
+ @param {Object} data - The data to apply transforms to
58
+ @return {Object} The transformed data
59
+ @public
60
+ */
61
+ applyTransforms(typeClass, data) {
62
+ return fragmentApplyTransforms(this, typeClass, data);
63
+ }
64
+
65
+ /**
66
+ Override extractAttributes to include fragment attributes.
67
+ The default implementation only iterates modelClass.eachAttribute which
68
+ doesn't include fragment attributes (they're computed properties with
69
+ isFragment: true metadata).
70
+
71
+ @method extractAttributes
72
+ @param {Class} modelClass - The model class
73
+ @param {Object} resourceHash - The raw resource data from the server
74
+ @return {Object} The extracted attributes
75
+ @public
76
+ */
77
+ extractAttributes(modelClass, resourceHash) {
78
+ return fragmentExtractAttributes(
79
+ this,
80
+ modelClass,
81
+ resourceHash,
82
+ JSONSerializer.prototype.extractAttributes,
83
+ );
84
+ }
85
+ }
@@ -0,0 +1,85 @@
1
+ import JSONAPISerializer from '@ember-data/serializer/json-api';
2
+ import {
3
+ fragmentTransformFor,
4
+ fragmentApplyTransforms,
5
+ fragmentExtractAttributesJSONAPI,
6
+ fragmentSerialize,
7
+ } from './utils';
8
+
9
+ /**
10
+ FragmentJSONAPISerializer is the base serializer class for ember-data-model-fragments
11
+ when using JSONAPISerializer.
12
+
13
+ ```js
14
+ // app/serializers/application.js
15
+ import { FragmentJSONAPISerializer } from 'ember-data-model-fragments/serializer';
16
+
17
+ export default class ApplicationSerializer extends FragmentJSONAPISerializer {}
18
+ ```
19
+
20
+ @class FragmentJSONAPISerializer
21
+ @extends JSONAPISerializer
22
+ @public
23
+ */
24
+ export default class FragmentJSONAPISerializer extends JSONAPISerializer {
25
+ serialize(snapshot, options) {
26
+ return fragmentSerialize(
27
+ this,
28
+ snapshot,
29
+ super.serialize(snapshot, options),
30
+ );
31
+ }
32
+
33
+ /**
34
+ Enables fragment properties to have custom transforms based on the fragment
35
+ type, so that deserialization does not have to happen on the fly
36
+
37
+ @method transformFor
38
+ @param {String} attributeType - The attribute type to get the transform for
39
+ @return {Transform}
40
+ @public
41
+ */
42
+ transformFor(attributeType) {
43
+ return fragmentTransformFor(
44
+ this,
45
+ attributeType,
46
+ JSONAPISerializer.prototype.transformFor,
47
+ );
48
+ }
49
+
50
+ /**
51
+ Override applyTransforms to handle polymorphic fragments with a typeKey function
52
+
53
+ @method applyTransforms
54
+ @param {Class} typeClass - The model class
55
+ @param {Object} data - The data to apply transforms to
56
+ @return {Object} The transformed data
57
+ @public
58
+ */
59
+ applyTransforms(typeClass, data) {
60
+ return fragmentApplyTransforms(this, typeClass, data);
61
+ }
62
+
63
+ /**
64
+ Override extractAttributes to include fragment attributes.
65
+ The default implementation only iterates modelClass.eachAttribute which
66
+ doesn't include fragment attributes (they're computed properties with
67
+ isFragment: true metadata).
68
+
69
+ For JSON:API, attributes are nested under resourceHash.attributes.
70
+
71
+ @method extractAttributes
72
+ @param {Class} modelClass - The model class
73
+ @param {Object} resourceHash - The raw resource data from the server
74
+ @return {Object} The extracted attributes
75
+ @public
76
+ */
77
+ extractAttributes(modelClass, resourceHash) {
78
+ return fragmentExtractAttributesJSONAPI(
79
+ this,
80
+ modelClass,
81
+ resourceHash,
82
+ JSONAPISerializer.prototype.extractAttributes,
83
+ );
84
+ }
85
+ }
@@ -0,0 +1,83 @@
1
+ import RESTSerializer from '@ember-data/serializer/rest';
2
+ import {
3
+ fragmentTransformFor,
4
+ fragmentApplyTransforms,
5
+ fragmentExtractAttributes,
6
+ fragmentSerialize,
7
+ } from './utils';
8
+
9
+ /**
10
+ FragmentRESTSerializer is the base serializer class for ember-data-model-fragments
11
+ when using RESTSerializer.
12
+
13
+ ```js
14
+ // app/serializers/application.js
15
+ import { FragmentRESTSerializer } from 'ember-data-model-fragments/serializer';
16
+
17
+ export default class ApplicationSerializer extends FragmentRESTSerializer {}
18
+ ```
19
+
20
+ @class FragmentRESTSerializer
21
+ @extends RESTSerializer
22
+ @public
23
+ */
24
+ export default class FragmentRESTSerializer extends RESTSerializer {
25
+ serialize(snapshot, options) {
26
+ return fragmentSerialize(
27
+ this,
28
+ snapshot,
29
+ super.serialize(snapshot, options),
30
+ );
31
+ }
32
+
33
+ /**
34
+ Enables fragment properties to have custom transforms based on the fragment
35
+ type, so that deserialization does not have to happen on the fly
36
+
37
+ @method transformFor
38
+ @param {String} attributeType - The attribute type to get the transform for
39
+ @return {Transform}
40
+ @public
41
+ */
42
+ transformFor(attributeType) {
43
+ return fragmentTransformFor(
44
+ this,
45
+ attributeType,
46
+ RESTSerializer.prototype.transformFor,
47
+ );
48
+ }
49
+
50
+ /**
51
+ Override applyTransforms to handle polymorphic fragments with a typeKey function
52
+
53
+ @method applyTransforms
54
+ @param {Class} typeClass - The model class
55
+ @param {Object} data - The data to apply transforms to
56
+ @return {Object} The transformed data
57
+ @public
58
+ */
59
+ applyTransforms(typeClass, data) {
60
+ return fragmentApplyTransforms(this, typeClass, data);
61
+ }
62
+
63
+ /**
64
+ Override extractAttributes to include fragment attributes.
65
+ The default implementation only iterates modelClass.eachAttribute which
66
+ doesn't include fragment attributes (they're computed properties with
67
+ isFragment: true metadata).
68
+
69
+ @method extractAttributes
70
+ @param {Class} modelClass - The model class
71
+ @param {Object} resourceHash - The raw resource data from the server
72
+ @return {Object} The extracted attributes
73
+ @public
74
+ */
75
+ extractAttributes(modelClass, resourceHash) {
76
+ return fragmentExtractAttributes(
77
+ this,
78
+ modelClass,
79
+ resourceHash,
80
+ RESTSerializer.prototype.extractAttributes,
81
+ );
82
+ }
83
+ }