Skip to content

Commit 1135d40

Browse files
Update schema-service.js
1 parent 93011c7 commit 1135d40

File tree

1 file changed

+92
-76
lines changed

1 file changed

+92
-76
lines changed

addon/schema-service.js

Lines changed: 92 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { ModelSchemaProvider } from '@ember-data/model';
1+
import {
2+
macroCondition,
3+
dependencySatisfies,
4+
importSync,
5+
} from '@embroider/macros';
26

37
/**
48
* FragmentSchemaService extends ModelSchemaProvider to add support for fragment attributes.
@@ -13,91 +17,103 @@ import { ModelSchemaProvider } from '@ember-data/model';
1317
* 3. Transform fragment metadata to be recognized by the schema service
1418
* 4. Add transformed fragments to the schema
1519
*
20+
* NOTE: This class only exists in ember-data 4.13+. For 4.12, this module exports null.
21+
*
1622
* @class FragmentSchemaService
1723
* @extends ModelSchemaProvider
1824
* @public
1925
*/
20-
export default class FragmentSchemaService extends ModelSchemaProvider {
21-
/**
22-
* Override _loadModelSchema to include fragment attributes in the schema.
23-
*
24-
* The parent implementation only includes attributes where `meta.kind === 'attribute'`.
25-
* We need to also include fragment attributes and transform them to be compatible.
26-
*
27-
* @method _loadModelSchema
28-
* @param {String} type - The model type name
29-
* @return {Object} internalSchema - The schema with attributes, relationships, and fields
30-
* @private
31-
*/
32-
_loadModelSchema(type) {
33-
// Call parent implementation to get standard schema (attributes + relationships)
34-
const internalSchema = super._loadModelSchema(type);
26+
let FragmentSchemaService = null;
27+
28+
if (macroCondition(dependencySatisfies('ember-data', '>=4.13.0-alpha.0'))) {
29+
const { ModelSchemaProvider } = importSync('@ember-data/model');
3530

36-
// Get the model class to scan for fragment attributes
37-
const modelClass = this.store.modelFor(type);
31+
FragmentSchemaService = class FragmentSchemaService extends (
32+
ModelSchemaProvider
33+
) {
34+
/**
35+
* Override _loadModelSchema to include fragment attributes in the schema.
36+
*
37+
* The parent implementation only includes attributes where `meta.kind === 'attribute'`.
38+
* We need to also include fragment attributes and transform them to be compatible.
39+
*
40+
* @method _loadModelSchema
41+
* @param {String} type - The model type name
42+
* @return {Object} internalSchema - The schema with attributes, relationships, and fields
43+
* @private
44+
*/
45+
_loadModelSchema(type) {
46+
// Call parent implementation to get standard schema (attributes + relationships)
47+
const internalSchema = super._loadModelSchema(type);
3848

39-
// Scan computed properties for fragment attributes
40-
modelClass.eachComputedProperty((name, meta) => {
41-
if (this._isFragmentAttribute(meta)) {
42-
// Transform fragment metadata to be recognized as an attribute
43-
// while preserving fragment-specific information
44-
const transformedMeta = {
45-
name,
46-
key: name, // ember-data expects this
47-
kind: 'attribute', // Change to 'attribute' so schema service recognizes it
48-
// Keep the original type for transform lookup
49-
type: meta.type,
50-
options: {
51-
...meta.options,
52-
isFragment: true, // Mark as fragment in options
53-
fragmentKind: meta.kind, // Preserve original kind
54-
modelName: meta.modelName,
55-
},
56-
isAttribute: true, // Required by ember-data
57-
isFragment: true, // Preserve for our code
58-
modelName: meta.modelName, // Preserve model name at top level
59-
};
49+
// Get the model class to scan for fragment attributes
50+
const modelClass = this.store.modelFor(type);
6051

61-
// Add to all three schema structures:
62-
// 1. attributes object (used by attributesDefinitionFor - legacy API)
63-
internalSchema.attributes[name] = transformedMeta;
52+
// Scan computed properties for fragment attributes
53+
modelClass.eachComputedProperty((name, meta) => {
54+
if (this._isFragmentAttribute(meta)) {
55+
// Transform fragment metadata to be recognized as an attribute
56+
// while preserving fragment-specific information
57+
const transformedMeta = {
58+
name,
59+
key: name, // ember-data expects this
60+
kind: 'attribute', // Change to 'attribute' so schema service recognizes it
61+
// Keep the original type for transform lookup
62+
type: meta.type,
63+
options: {
64+
...meta.options,
65+
isFragment: true, // Mark as fragment in options
66+
fragmentKind: meta.kind, // Preserve original kind
67+
modelName: meta.modelName,
68+
},
69+
isAttribute: true, // Required by ember-data
70+
isFragment: true, // Preserve for our code
71+
modelName: meta.modelName, // Preserve model name at top level
72+
};
6473

65-
// 2. fields Map (used by fields() - new API)
66-
internalSchema.fields.set(name, transformedMeta);
74+
// Add to all three schema structures:
75+
// 1. attributes object (used by attributesDefinitionFor - legacy API)
76+
internalSchema.attributes[name] = transformedMeta;
6777

68-
// 3. schema.fields array (used by resource() - new API)
69-
// Note: We'll rebuild this array after the loop to avoid duplicates
70-
}
71-
});
78+
// 2. fields Map (used by fields() - new API)
79+
internalSchema.fields.set(name, transformedMeta);
7280

73-
// Rebuild schema.fields array from the fields Map
74-
// This ensures it includes all attributes, relationships, AND fragments
75-
internalSchema.schema.fields = Array.from(internalSchema.fields.values());
81+
// 3. schema.fields array (used by resource() - new API)
82+
// Note: We'll rebuild this array after the loop to avoid duplicates
83+
}
84+
});
7685

77-
return internalSchema;
78-
}
86+
// Rebuild schema.fields array from the fields Map
87+
// This ensures it includes all attributes, relationships, AND fragments
88+
internalSchema.schema.fields = Array.from(internalSchema.fields.values());
7989

80-
/**
81-
* Check if a computed property metadata object represents a fragment attribute.
82-
*
83-
* Fragment attributes have:
84-
* - isFragment: true
85-
* - kind: 'fragment', 'fragment-array', or 'array'
86-
*
87-
* @method _isFragmentAttribute
88-
* @param {Object} meta - The computed property metadata
89-
* @return {Boolean}
90-
* @private
91-
*/
92-
_isFragmentAttribute(meta) {
93-
return (
94-
typeof meta === 'object' &&
95-
meta !== null &&
96-
'kind' in meta &&
97-
meta.isFragment === true &&
98-
(meta.kind === 'fragment' ||
99-
meta.kind === 'fragment-array' ||
100-
meta.kind === 'array')
101-
);
102-
}
90+
return internalSchema;
91+
}
92+
93+
/**
94+
* Check if a computed property metadata object represents a fragment attribute.
95+
*
96+
* Fragment attributes have:
97+
* - isFragment: true
98+
* - kind: 'fragment', 'fragment-array', or 'array'
99+
*
100+
* @method _isFragmentAttribute
101+
* @param {Object} meta - The computed property metadata
102+
* @return {Boolean}
103+
* @private
104+
*/
105+
_isFragmentAttribute(meta) {
106+
return (
107+
typeof meta === 'object' &&
108+
meta !== null &&
109+
'kind' in meta &&
110+
meta.isFragment === true &&
111+
(meta.kind === 'fragment' ||
112+
meta.kind === 'fragment-array' ||
113+
meta.kind === 'array')
114+
);
115+
}
116+
};
103117
}
118+
119+
export default FragmentSchemaService;

0 commit comments

Comments
 (0)