@@ -4,7 +4,7 @@ import { addToTransaction, createSignal, subscribe } from '@ember-data/tracking/
4
4
import type { StableRecordIdentifier } from '@warp-drive/core-types' ;
5
5
import type { Cache } from '@warp-drive/core-types/cache' ;
6
6
import type { ObjectValue , Value } from '@warp-drive/core-types/json/raw' ;
7
- import type { ObjectField } from '@warp-drive/core-types/schema/fields' ;
7
+ import type { ObjectField , SchemaObjectField } from '@warp-drive/core-types/schema/fields' ;
8
8
9
9
import type { SchemaRecord } from '../record' ;
10
10
import type { SchemaService } from '../schema' ;
@@ -15,7 +15,7 @@ export function notifyObject(obj: ManagedObject) {
15
15
}
16
16
17
17
type KeyType = string | symbol | number ;
18
-
18
+ const ignoredGlobalFields = new Set < string > ( [ 'constructor' , 'setInterval' , 'nodeType' , 'length' ] ) ;
19
19
export interface ManagedObject {
20
20
[ MUTATE ] ?(
21
21
target : unknown [ ] ,
@@ -37,11 +37,12 @@ export class ManagedObject {
37
37
store : Store ,
38
38
schema : SchemaService ,
39
39
cache : Cache ,
40
- field : ObjectField ,
40
+ field : ObjectField | SchemaObjectField ,
41
41
data : object ,
42
42
address : StableRecordIdentifier ,
43
43
key : string ,
44
- owner : SchemaRecord
44
+ owner : SchemaRecord ,
45
+ isSchemaObject : boolean
45
46
) {
46
47
// eslint-disable-next-line @typescript-eslint/no-this-alias
47
48
const self = this ;
@@ -68,20 +69,42 @@ export class ManagedObject {
68
69
if ( prop === 'owner' ) {
69
70
return self . owner ;
70
71
}
72
+ if ( prop === Symbol . toStringTag ) {
73
+ return `ManagedObject<${ address . type } :${ address . id } (${ address . lid } )>` ;
74
+ }
71
75
76
+ if ( prop === 'toString' ) {
77
+ return function ( ) {
78
+ return `ManagedObject<${ address . type } :${ address . id } (${ address . lid } )>` ;
79
+ } ;
80
+ }
81
+
82
+ if ( prop === 'toHTML' ) {
83
+ return function ( ) {
84
+ return '<div>ManagedObject</div>' ;
85
+ } ;
86
+ }
72
87
if ( _SIGNAL . shouldReset ) {
73
88
_SIGNAL . t = false ;
74
89
_SIGNAL . shouldReset = false ;
75
90
let newData = cache . getAttr ( self . address , self . key ) ;
76
91
if ( newData && newData !== self [ SOURCE ] ) {
77
- if ( field . type ) {
92
+ if ( ! isSchemaObject && field . type ) {
78
93
const transform = schema . transformation ( field ) ;
79
94
newData = transform . hydrate ( newData as ObjectValue , field . options ?? null , self . owner ) as ObjectValue ;
80
95
}
81
96
self [ SOURCE ] = { ...( newData as ObjectValue ) } ; // Add type assertion for newData
82
97
}
83
98
}
84
99
100
+ if ( isSchemaObject ) {
101
+ const fields = schema . fields ( { type : field . type ! } ) ;
102
+ // TODO: is there a better way to do this?
103
+ if ( typeof prop === 'string' && ! ignoredGlobalFields . has ( prop ) && ! fields . has ( prop ) ) {
104
+ throw new Error ( `Field ${ prop } does not exist on schema object ${ field . type } ` ) ;
105
+ }
106
+ }
107
+
85
108
if ( prop in self [ SOURCE ] ) {
86
109
if ( ! transaction ) {
87
110
subscribe ( _SIGNAL ) ;
@@ -108,10 +131,16 @@ export class ManagedObject {
108
131
self . owner = value ;
109
132
return true ;
110
133
}
134
+ if ( isSchemaObject ) {
135
+ const fields = schema . fields ( { type : field . type ! } ) ;
136
+ if ( typeof prop === 'string' && ! ignoredGlobalFields . has ( prop ) && ! fields . has ( prop ) ) {
137
+ throw new Error ( `Field ${ prop } does not exist on schema object ${ field . type } ` ) ;
138
+ }
139
+ }
111
140
const reflect = Reflect . set ( target , prop , value , receiver ) ;
112
141
113
142
if ( reflect ) {
114
- if ( ! field . type ) {
143
+ if ( isSchemaObject || ! field . type ) {
115
144
cache . setAttr ( self . address , self . key , self [ SOURCE ] as Value ) ;
116
145
_SIGNAL . shouldReset = true ;
117
146
return true ;
0 commit comments