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