@@ -79,17 +79,19 @@ def _to_scim(
7979 if value is not None :
8080 Path [model ](column .binding .urn ).set (resource , value ) # type: ignore[valid-type]
8181
82+ read : dict [str , tuple [bool , list [dict [str , Any ]]]] = {}
8283 for collection in collections :
8384 endpoint = None
8485 if Path [model ](f"{ collection .binding .urn } .$ref" ).resolve () is not None : # type: ignore[valid-type]
8586 endpoint = endpoints .get (collection .resource_type ) # type: ignore[arg-type]
86- entries = [
87+ _ , entries = read .setdefault (collection .binding .urn , (collection .single , []))
88+ entries .extend (
8789 _read_entry (collection , entry , endpoint )
8890 for entry in _related (collection , record )
89- ]
91+ )
92+ for urn , (single , entries ) in read .items ():
9093 if entries :
91- value = entries [0 ] if collection .single else entries
92- Path [model ](collection .binding .urn ).set (resource , value ) # type: ignore[valid-type]
94+ Path [model ](urn ).set (resource , entries [0 ] if single else entries ) # type: ignore[valid-type]
9395
9496 resource .id = str (_read (mapping ._id , record ))
9597 resource .meta = Meta (
@@ -132,6 +134,8 @@ def _read_entry(
132134 if endpoint is not None :
133135 values ["$ref" ] = f"{ endpoint } /{ value } "
134136 values [column .binding .urn .rsplit ("." , 1 )[- 1 ]] = value
137+ if collection .link_type is not None :
138+ values ["type" ] = collection .link_type
135139 return values
136140
137141
@@ -158,7 +162,7 @@ def _from_scim(
158162 continue
159163 setattr (record , column .key , None if value is None else _as_stored (value ))
160164
161- for collection in mapping ._collections . values ():
165+ for collection in mapping ._all_collections ():
162166 if not collection .writable :
163167 continue
164168 if collection .owned :
@@ -182,24 +186,25 @@ def _write_entry(collection: _Collection, entry: Any) -> Any:
182186 return record
183187
184188
185- def _link_ids (
189+ def _link_entries (
186190 mapping : ResourceMapping , resource : Resource [Any ]
187- ) -> dict [ _Collection , list [str ]]:
188- """Return the identifiers each writable Link of a resource links to.
191+ ) -> list [ tuple [ list [ _Collection ] , list [Any ] ]]:
192+ """Return the entries of each written attribute of a resource linking to other resources, with the collections of its Links .
189193
190194 A link is stored by its value, so an entry without one, such as an entry
191195 with a $ref only, raises InvalidValueException rather than being lost.
192196 """
193- links = {}
194- for collection in mapping ._collections .values ():
197+ links = []
198+ for collections in mapping ._collections .values ():
199+ collection = collections [0 ]
195200 if collection .owned or not collection .writable :
196201 continue
197202 entries = _entries (collection , resource )
198203 if any (entry .value is None for entry in entries ):
199204 raise InvalidValueException (
200205 detail = f"'{ collection .binding .urn } ' holds an entry without value"
201206 )
202- links [ collection ] = [ entry . value for entry in entries ]
207+ links . append (( collections , entries ))
203208 return links
204209
205210
@@ -247,7 +252,10 @@ def _check_storable(
247252 detail = f"'{ binding .urn } ' cannot be removed on this server" ,
248253 )
249254 continue
250- if storage in (_Storage .derived , _Storage .ref ) or value in (None , current ):
255+ if storage in (_Storage .derived , _Storage .ref , _Storage .link_type ) or value in (
256+ None ,
257+ current ,
258+ ):
251259 continue
252260 if storage == _Storage .read_only :
253261 raise MutabilityException (
@@ -264,7 +272,7 @@ def _check_enumerated(
264272 mapping : ResourceMapping , binding : AttributeBinding , value : Any
265273) -> None :
266274 """Refuse a string that an Enum column does not store, rather than failing in the database."""
267- _ , column = mapping ._lookup (binding )
275+ _ , column = mapping ._lookup (binding )[ 0 ]
268276 if column is None or column .enumeration is None :
269277 return
270278 stored = column .enumeration .enums
0 commit comments