@@ -193,6 +193,7 @@ def __init__(
193193 self ._branch = None
194194 self ._ref = None
195195 self ._repo = None
196+ self ._references = {}
196197
197198 # Default headers
198199 self ._default_headers = {"user-agent" : user_agent }
@@ -1140,7 +1141,10 @@ def _conv_to_dict(self, obj):
11401141 if hasattr (obj , "_isinstance" ) and obj ._isinstance :
11411142 if hasattr (obj .__class__ , "_subdocument" ):
11421143 raise ValueError ("Subdocument cannot be added directly" )
1143- return obj ._obj_to_dict ()
1144+ (d , refs ) = obj ._obj_to_dict ()
1145+ # merge all refs
1146+ self ._references = {** self ._references , ** refs }
1147+ return d
11441148 else :
11451149 return obj ._to_dict ()
11461150 else :
@@ -1157,45 +1161,44 @@ def _ref_extract(self, target_key, search_item):
11571161 for item in value :
11581162 yield from self ._ref_extract (target_key , item )
11591163
1164+ def _unseen (self , seen ):
1165+ unseen = []
1166+ for key in self ._references :
1167+ if key not in seen :
1168+ unseen .append (self ._references [key ])
1169+ return unseen
1170+
11601171 def _convert_document (self , document , graph_type ):
1161- if isinstance (document , list ):
1162- new_doc = []
1163- captured = []
1164- referenced = []
1172+ if not isinstance (document , list ):
1173+ document = [document ]
11651174
1175+ seen = {}
1176+ objects = []
1177+ while document != []:
11661178 for item in document :
1179+ if hasattr (item , "to_dict" ) and graph_type != "schema" :
1180+ raise InterfaceError (
1181+ "Inserting WOQLSchema object into non-schema graph."
1182+ )
11671183 item_dict = self ._conv_to_dict (item )
1168- new_doc .append (item_dict )
1169- item_capture = item_dict .get ("@capture" )
1170- if item_capture :
1171- captured .append (item_capture )
1172- referenced += list (self ._ref_extract ("@ref" , item_dict ))
1184+ if hasattr (item , "_capture" ):
1185+ seen [item ._capture ] = item_dict
1186+ else :
1187+ if isinstance (item_dict , list ):
1188+ objects += item_dict
1189+ else :
1190+ objects .append (item_dict )
11731191
1174- referenced = list ( set ( referenced ) )
1192+ document = self . _unseen ( seen )
11751193
1176- for item in referenced :
1177- if item not in captured :
1178- raise ValueError (
1179- f"{ item } is referenced but not captured. Seems you forgot to submit one or more object(s)."
1180- )
1181- else :
1182- if hasattr (document , "to_dict" ) and graph_type != "schema" :
1183- raise InterfaceError (
1184- "Inserting WOQLSchema object into non-schema graph."
1185- )
1186- new_doc = self ._conv_to_dict (document )
1187- if isinstance (new_doc , dict ) and list (self ._ref_extract ("@ref" , new_doc )):
1188- raise ValueError (
1189- "There are uncaptured references. Seems you forgot to submit one or more object(s)."
1190- )
1191- return new_doc
1194+ return list (seen .values ()) + objects
11921195
11931196 def insert_document (
11941197 self ,
11951198 document : Union [
11961199 dict ,
11971200 List [dict ],
1198- "WOQLSchema " , # noqa:F821
1201+ "Schema " , # noqa:F821
11991202 "DocumentTemplate" , # noqa:F821
12001203 List ["DocumentTemplate" ], # noqa:F821
12011204 ],
@@ -1249,12 +1252,14 @@ def insert_document(
12491252 if last_data_version is not None :
12501253 headers ["TerminusDB-Data-Version" ] = last_data_version
12511254
1255+ # make sure we track only internal references
1256+ self ._references = {}
12521257 new_doc = self ._convert_document (document , graph_type )
1258+ all_docs = list (self ._references .values ())
1259+ self ._references = {}
12531260
12541261 if len (new_doc ) == 0 :
12551262 return
1256- elif not isinstance (new_doc , list ):
1257- new_doc = [new_doc ]
12581263
12591264 if full_replace :
12601265 if new_doc [0 ].get ("@type" ) != "@context" :
@@ -1289,18 +1294,18 @@ def insert_document(
12891294 auth = self ._auth (),
12901295 )
12911296 result = json .loads (_finish_response (result ))
1292- if isinstance (document , list ):
1293- for idx , item in enumerate (document ):
1297+ if isinstance (all_docs , list ):
1298+ for idx , item in enumerate (all_docs ):
12941299 if hasattr (item , "_obj_to_dict" ) and not hasattr (item , "_backend_id" ):
1295- item ._backend_id = result [idx ][ len ( "terminusdb:///data/" ) :]
1300+ item ._backend_id = result [idx ]
12961301 return result
12971302
12981303 def replace_document (
12991304 self ,
13001305 document : Union [
13011306 dict ,
13021307 List [dict ],
1303- "WOQLSchema " , # noqa:F821
1308+ "Schema " , # noqa:F821
13041309 "DocumentTemplate" , # noqa:F821
13051310 List ["DocumentTemplate" ], # noqa:F821
13061311 ],
@@ -1346,7 +1351,10 @@ def replace_document(
13461351 if last_data_version is not None :
13471352 headers ["TerminusDB-Data-Version" ] = last_data_version
13481353
1354+ self ._references = {}
13491355 new_doc = self ._convert_document (document , graph_type )
1356+ all_docs = list (self ._references .values ())
1357+ self ._references = {}
13501358
13511359 json_string = json .dumps (new_doc ).encode ("utf-8" )
13521360 if compress != "never" and len (json_string ) > compress :
@@ -1369,8 +1377,8 @@ def replace_document(
13691377 auth = self ._auth (),
13701378 )
13711379 result = json .loads (_finish_response (result ))
1372- if isinstance (document , list ):
1373- for idx , item in enumerate (document ):
1380+ if isinstance (all_docs , list ):
1381+ for idx , item in enumerate (all_docs ):
13741382 if hasattr (item , "_obj_to_dict" ) and not hasattr (item , "_backend_id" ):
13751383 item ._backend_id = result [idx ][len ("terminusdb:///data/" ) :]
13761384 return result
@@ -1380,7 +1388,7 @@ def update_document(
13801388 document : Union [
13811389 dict ,
13821390 List [dict ],
1383- "WOQLSchema " , # noqa:F821
1391+ "Schema " , # noqa:F821
13841392 "DocumentTemplate" , # noqa:F821
13851393 List ["DocumentTemplate" ], # noqa:F821
13861394 ],
@@ -1449,7 +1457,7 @@ def delete_document(
14491457 document = [document ]
14501458 for doc in document :
14511459 if hasattr (doc , "_obj_to_dict" ):
1452- doc = doc ._obj_to_dict ()
1460+ ( doc , refs ) = doc ._obj_to_dict ()
14531461 if isinstance (doc , dict ) and doc .get ("@id" ):
14541462 doc_id .append (doc .get ("@id" ))
14551463 elif isinstance (doc , str ):
@@ -1996,7 +2004,7 @@ def squash(
19962004 self .reset (commit_id )
19972005 return commit_id
19982006
1999- def _convert_diff_dcoument (self , document ):
2007+ def _convert_diff_document (self , document ):
20002008 if isinstance (document , list ):
20012009 new_doc = []
20022010 for item in document :
@@ -2012,15 +2020,15 @@ def diff(
20122020 str ,
20132021 dict ,
20142022 List [dict ],
2015- "WOQLSchema " , # noqa:F821
2023+ "Schema " , # noqa:F821
20162024 "DocumentTemplate" , # noqa:F821
20172025 List ["DocumentTemplate" ], # noqa:F821
20182026 ],
20192027 after : Union [
20202028 str ,
20212029 dict ,
20222030 List [dict ],
2023- "WOQLSchema " , # noqa:F821
2031+ "Schema " , # noqa:F821
20242032 "DocumentTemplate" , # noqa:F821
20252033 List ["DocumentTemplate" ], # noqa:F821
20262034 ],
@@ -2047,7 +2055,7 @@ def diff(
20472055 if isinstance (item , str ):
20482056 request_dict [f"{ key } _data_version" ] = item
20492057 else :
2050- request_dict [key ] = self ._convert_diff_dcoument (item )
2058+ request_dict [key ] = self ._convert_diff_document (item )
20512059 if document_id is not None :
20522060 if "before_data_version" in request_dict :
20532061 if document_id [: len ("terminusdb:///data" )] == "terminusdb:///data" :
@@ -2084,7 +2092,7 @@ def patch(
20842092 before : Union [
20852093 dict ,
20862094 List [dict ],
2087- "WOQLSchema " , # noqa:F821
2095+ "Schema " , # noqa:F821
20882096 "DocumentTemplate" , # noqa:F821
20892097 List ["DocumentTemplate" ], # noqa:F821
20902098 ],
@@ -2109,7 +2117,7 @@ def patch(
21092117 '{ "@id" : "Person/Jane", "@type" : Person", "name" : "Janine"}'"""
21102118
21112119 request_dict = {
2112- "before" : self ._convert_diff_dcoument (before ),
2120+ "before" : self ._convert_diff_document (before ),
21132121 "patch" : patch .content ,
21142122 }
21152123
0 commit comments