9
9
import copy
10
10
import json
11
11
import requests
12
+ from urllib .parse import quote
12
13
from io import TextIOWrapper , BufferedReader , BufferedIOBase
13
14
14
15
from . import HKTransaction , generate_id , constants
15
16
from ..hklib import hkfy , HKEntity , HKContext
17
+ from ..hklib .fi .fi import FI
18
+ from ..hklib .node import HKDataNode
16
19
from ..oops import HKBError , HKpyError
17
20
from ..utils import response_validator
18
21
from ..common .result_set import ResultSet
@@ -73,29 +76,96 @@ def add_entities(self, entities: Union[HKEntity, List[HKEntity]], transaction: O
73
76
74
77
url = f'{ self .base ._repository_uri } /{ self .name } /entity/'
75
78
79
+ filtered_data_objects = []
80
+
76
81
if not isinstance (entities , (list ,tuple )):
77
82
entities = [entities ]
78
-
83
+
79
84
if isinstance (entities [0 ], HKEntity ):
80
85
entities = [x .to_dict () for x in entities ]
81
86
elif isinstance (entities [0 ], dict ):
82
87
pass
83
- # entities = list(map(hkfy, entities))
84
88
else :
85
89
raise ValueError
86
90
91
+ data_entities , entities = self .filter_data_entities (entities )
92
+ if data_entities :
93
+ self .add_data_entities (data_entities )
94
+
87
95
headers = copy .deepcopy (self ._headers )
88
96
headers ['Content-Type' ] = 'application/json'
89
97
90
98
response = requests .put (url = url , data = json .dumps (entities ), headers = headers )
91
99
response_validator (response = response )
92
100
93
- def filter_entities (self , filter_ : Union [str , Dict ]) -> List [HKEntity ]:
101
+ def filter_data_entities (self , entities : Union [HKEntity , List [HKEntity ]]):
102
+ """ filter the entities with raw data.
103
+ Return two lists:
104
+ dataentities: entities with raw data.
105
+ nondataentites: entities without raw data.
106
+
107
+ Parameters
108
+ ----------
109
+ entities : (Union[HKDataNode, List[HKDataNode]]) entity or list of entities
110
+ transaction : (Optional[HKTransaction]) connection transaction
111
+
112
+ Returns
113
+ -------
114
+ dataentities: (List[HKEntity]) list of entities with raw data
115
+ nondataentites: (List[HKEntity]) list of entities without raw data
116
+ """
117
+
118
+ dataentities = []
119
+ nondataentites = []
120
+ for entity in entities :
121
+ if 'raw_data' in entity :
122
+ dataentities .append (entity )
123
+ else :
124
+ nondataentites .append (entity )
125
+ return dataentities , nondataentites
126
+
127
+ def add_data_entities (self , dataentities : Union [HKDataNode , List [HKDataNode ]], transaction : Optional [HKTransaction ]= None ) -> None :
128
+ """ Add entities with raw data to repository.
129
+
130
+ Parameters
131
+ ----------
132
+ entities : (Union[HKDataNode, List[HKDataNode]]) data node or list of data nodes
133
+ transaction : (Optional[HKTransaction]) connection transaction
134
+ """
135
+
136
+ url = f'{ self .base ._repository_uri } /{ self .name } /entity/'
137
+
138
+ if not dataentities :
139
+ return
140
+
141
+ if not isinstance (dataentities , (list ,tuple )):
142
+ dataentities = [dataentities ]
143
+
144
+ if isinstance (dataentities [0 ], HKEntity ):
145
+ dataentities = [x .to_dict () for x in entities ]
146
+ elif isinstance (dataentities [0 ], dict ):
147
+ pass
148
+ else :
149
+ raise ValueError
150
+
151
+ files = {}
152
+ data = {}
153
+ for entity in dataentities :
154
+ file = entity .pop ('raw_data' )
155
+ files [entity ['id' ]] = (entity ['id' ], file , entity ['properties' ]['mimeType' ])
156
+ data [entity ['id' ]] = json .dumps (entity )
157
+
158
+ response = requests .put (url = url , data = data , files = files )
159
+ response_validator (response = response )
160
+
161
+
162
+ def filter_entities (self , filter_ : Union [str , Dict ], bring_raw_data : Optional [bool ]= False ) -> List [HKEntity ]:
94
163
""" Get entities filtered by a css filter or json filter.
95
164
96
165
Parameters
97
166
----------
98
167
filter_ : (Union[str, Dict]) retrieval filter
168
+ bring_raw_data: Optional[bool] flag to define whether raw data should be fetched or not
99
169
100
170
Returns
101
171
-------
@@ -135,15 +205,20 @@ def check_list(the_filter, depth=0):
135
205
except Exception as err :
136
206
raise HKBError (message = 'Could not retrieve the entities.' , error = err )
137
207
138
- return [hkfy (entity ) for entity in data .values ()]
208
+ entities = [hkfy (entity ) for entity in data .values ()]
209
+ if bring_raw_data :
210
+ entities = self .retrieve_raw_data_from_data_entities (entities )
211
+
212
+ return entities
139
213
140
- def get_entities (self , ids : List [Union [str , Dict ]]) -> List [HKEntity ]:
214
+ def get_entities (self , ids : List [Union [str , Dict ]], bring_raw_data : Optional [ bool ] = False ) -> List [HKEntity ]:
141
215
""" Get entities by an array of ids, where the id can be a string or an object containing remote information of
142
216
virtual entities.
143
217
144
218
Parameters
145
219
----------
146
220
ids : List[Union[str, Dict]] entities identifiers
221
+ bring_raw_data: Optional[bool] flag to define whether raw data should be fetched or not
147
222
148
223
Returns
149
224
-------
@@ -163,7 +238,32 @@ def get_entities(self, ids: List[Union[str, Dict]]) -> List[HKEntity]:
163
238
except Exception as err :
164
239
raise HKBError (message = 'Could not retrieve the entities.' , error = err )
165
240
166
- return [hkfy (entity ) for entity in data .values ()]
241
+ entities = [hkfy (entity ) for entity in data .values ()]
242
+ if bring_raw_data :
243
+ entities = self .retrieve_raw_data_from_data_entities (entities )
244
+
245
+ return entities
246
+
247
+ def retrieve_raw_data_from_data_entities (self , entities : List [HKEntity ]) -> List [HKEntity ]:
248
+ """ Retrive data from storage from data entities
249
+
250
+ Obs.: This is probably temporary. Probably the data will come from hkbase directly
251
+
252
+ Parameters
253
+ ----------
254
+ ids : List[HKEntity] entities
255
+
256
+ Returns
257
+ -------
258
+ (List[HKEntity]) list of data entities filled with their raw data
259
+ """
260
+
261
+ for i in range (len (entities )):
262
+ if 'mimeType' in entities [i ].properties :
263
+ raw_data = self .get_object (entities [i ].id_ )
264
+ entities [i ] = HKDataNode (raw_data , id_ = entities [i ].id_ , parent = entities [i ].parent , properties = entities [i ].properties , metaproperties = entities [i ].metaproperties )
265
+
266
+ return entities
167
267
168
268
def delete_entities (self , ids : Optional [Union [str , List [str ], HKEntity , List [HKEntity ]]] = None , transaction : Optional [HKTransaction ]= None ) -> None :
169
269
""" Delete entities from the repository using their ids.
@@ -175,15 +275,12 @@ def delete_entities(self, ids: Optional[Union[str, List[str], HKEntity, List[HKE
175
275
176
276
url = f'{ self .base ._repository_uri } /{ self .name } /entity/'
177
277
178
- if ids is None or len (ids ) == 0 :
179
- ids = {}
180
- else :
181
- if not isinstance (ids , (list ,tuple )):
182
- ids = [ids ]
183
-
184
- if isinstance (ids [0 ], HKEntity ):
185
- ids = [x .id_ for x in ids ]
186
-
278
+ if not isinstance (ids , (list ,tuple )):
279
+ ids = [ids ]
280
+
281
+ if isinstance (ids [0 ], HKEntity ):
282
+ ids = [x .id_ for x in ids ]
283
+
187
284
response = requests .delete (url = url , data = json .dumps (ids ), headers = self ._headers )
188
285
response_validator (response = response )
189
286
@@ -216,7 +313,9 @@ def import_data(self, fd: Union[str, TextIOWrapper], datatype: constants.Content
216
313
raise HKpyError (message = 'Data formaat not supported.' )
217
314
218
315
if 'as_hk' in options and options ['as_hk' ] == True :
219
- self .add_entities (entities = json .loads (fd ))
316
+ entities = json .loads (fd )
317
+ entities = list (map (hkfy , entities .values ()))
318
+ self .add_entities (list (entities ))
220
319
221
320
else :
222
321
url = f'{ self .base ._repository_uri } /{ self .name } /rdf'
@@ -323,6 +422,10 @@ def add_object(self, object_: [str, TextIOWrapper, BufferedReader, BufferedIOBas
323
422
elif isinstance (object_ , str ) and os .path .isfile (object_ ):
324
423
with open (object_ ,'rb' ) as f :
325
424
object_ = f .read ()
425
+ elif isinstance (object_ , str ):
426
+ pass # do nothing
427
+ elif isinstance (object_ , bytes ):
428
+ pass # do nothing
326
429
else :
327
430
raise HKpyError (message = 'Object not valid.' )
328
431
@@ -475,3 +578,36 @@ def _build_sparql_result(self, data) -> Union[SPARQLResultSet, bool]:
475
578
if not ('results' in data and 'bindings' in data ['results' ] and 'head' in data ):
476
579
raise HKpyError (f'The given data is not of the expected format' )
477
580
return SPARQLResultSet (data )
581
+
582
+ def resolve_fi (self , fi : FI , raw = False ) -> Union [bytes , List [HKEntity ]] :
583
+ """
584
+ Resolve a full FI. Set raw to True in order to get raw output. Otherwise the function will try to
585
+ interpret the response (i.e. into hk objects)
586
+ """
587
+ quoted_fi = quote (fi .__str__ (), safe = "" );
588
+ url = f'{ self .base ._repository_uri } /{ self .name } /fi/{ quoted_fi } '
589
+
590
+ response = requests .get (url = url , headers = self ._headers )
591
+ _ , data = response_validator (response = response , content = '.' )
592
+
593
+ if raw :
594
+ return data
595
+
596
+ # some extra response data converter
597
+ content_type = response .headers ['Content-Type' ]
598
+ if content_type .startswith ('hyperknowledge/graph' ):
599
+ return hkfy (response .json ())
600
+ elif content_type .startswith ('hyperknowledge/node' ):
601
+ return hkfy (response .json ())
602
+ elif content_type .startswith ('text' ):
603
+ return response .content .decode ()
604
+ else :
605
+ return data
606
+
607
+ def persist_fi (self , fi ):
608
+
609
+ quoted_fi = quote (fi .__str__ (), safe = "" );
610
+ url = f'{ self .base ._repository_uri } /{ self .name } /fi/{ quoted_fi } '
611
+
612
+ response = requests .put (url = url , headers = self ._headers )
613
+ response_validator (response = response )
0 commit comments