geobox 2.1.0__py3-none-any.whl → 2.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. geobox/__init__.py +61 -63
  2. geobox/aio/__init__.py +61 -63
  3. geobox/aio/api.py +491 -574
  4. geobox/aio/apikey.py +263 -263
  5. geobox/aio/attachment.py +341 -339
  6. geobox/aio/base.py +261 -262
  7. geobox/aio/basemap.py +196 -196
  8. geobox/aio/dashboard.py +340 -342
  9. geobox/aio/feature.py +35 -35
  10. geobox/aio/field.py +315 -321
  11. geobox/aio/file.py +72 -72
  12. geobox/aio/layout.py +340 -341
  13. geobox/aio/log.py +23 -23
  14. geobox/aio/map.py +1033 -1034
  15. geobox/aio/model3d.py +415 -415
  16. geobox/aio/mosaic.py +696 -696
  17. geobox/aio/plan.py +314 -314
  18. geobox/aio/query.py +693 -693
  19. geobox/aio/raster.py +88 -454
  20. geobox/aio/{analysis.py → raster_analysis.py} +153 -170
  21. geobox/aio/route.py +4 -4
  22. geobox/aio/scene.py +340 -342
  23. geobox/aio/settings.py +18 -18
  24. geobox/aio/task.py +404 -402
  25. geobox/aio/tile3d.py +337 -339
  26. geobox/aio/tileset.py +102 -103
  27. geobox/aio/usage.py +52 -51
  28. geobox/aio/user.py +506 -507
  29. geobox/aio/vector_tool.py +1968 -0
  30. geobox/aio/vectorlayer.py +316 -414
  31. geobox/aio/version.py +272 -273
  32. geobox/aio/view.py +1019 -983
  33. geobox/aio/workflow.py +340 -341
  34. geobox/api.py +14 -98
  35. geobox/apikey.py +262 -262
  36. geobox/attachment.py +336 -337
  37. geobox/base.py +384 -384
  38. geobox/basemap.py +194 -194
  39. geobox/dashboard.py +339 -341
  40. geobox/enums.py +31 -1
  41. geobox/feature.py +31 -10
  42. geobox/field.py +320 -320
  43. geobox/file.py +4 -4
  44. geobox/layout.py +339 -340
  45. geobox/log.py +4 -4
  46. geobox/map.py +1031 -1032
  47. geobox/model3d.py +410 -410
  48. geobox/mosaic.py +696 -696
  49. geobox/plan.py +313 -313
  50. geobox/query.py +691 -691
  51. geobox/raster.py +5 -368
  52. geobox/{analysis.py → raster_analysis.py} +108 -128
  53. geobox/scene.py +341 -342
  54. geobox/settings.py +194 -194
  55. geobox/task.py +399 -400
  56. geobox/tile3d.py +337 -338
  57. geobox/tileset.py +4 -4
  58. geobox/usage.py +3 -3
  59. geobox/user.py +503 -503
  60. geobox/vector_tool.py +1968 -0
  61. geobox/vectorlayer.py +5 -110
  62. geobox/version.py +272 -272
  63. geobox/view.py +981 -981
  64. geobox/workflow.py +338 -339
  65. {geobox-2.1.0.dist-info → geobox-2.2.1.dist-info}/METADATA +15 -1
  66. geobox-2.2.1.dist-info/RECORD +72 -0
  67. geobox-2.1.0.dist-info/RECORD +0 -70
  68. {geobox-2.1.0.dist-info → geobox-2.2.1.dist-info}/WHEEL +0 -0
  69. {geobox-2.1.0.dist-info → geobox-2.2.1.dist-info}/licenses/LICENSE +0 -0
  70. {geobox-2.1.0.dist-info → geobox-2.2.1.dist-info}/top_level.txt +0 -0
geobox/query.py CHANGED
@@ -1,692 +1,692 @@
1
- from urllib.parse import urljoin
2
- from typing import Dict, List, TYPE_CHECKING, Union
3
-
4
- from .utils import clean_data
5
- from .base import Base
6
- from .task import Task
7
- from .enums import QueryResultType, QueryGeometryType, QueryParamType
8
-
9
- if TYPE_CHECKING:
10
- from . import GeoboxClient
11
- from .user import User
12
- from .aio import AsyncGeoboxClient
13
- from .aio.query import Query as AsyncQuery
14
-
15
- class Query(Base):
16
-
17
- BASE_ENDPOINT: str = 'queries/'
18
-
19
- def __init__(self,
20
- api: 'GeoboxClient',
21
- uuid: str = None,
22
- data: Dict = {}):
23
- """
24
- Constructs all the necessary attributes for the Query object.
25
-
26
- Args:
27
- api (Api): The API instance.
28
- uuid (str): The UUID of the query.
29
- data (dict, optional): The data of the query.
30
- """
31
- self.result = {}
32
- self._system_query = False
33
- super().__init__(api, uuid=uuid, data=data)
34
-
35
-
36
- def _check_access(self) -> None:
37
- """
38
- Check if the query is a system query.
39
-
40
- Returns:
41
- None
42
-
43
- Raises:
44
- PermissionError: If the query is a read-only system query.
45
- """
46
- if self._system_query:
47
- raise PermissionError("Cannot modify system queries - they are read-only")
48
-
49
-
50
- @property
51
- def sql(self) -> str:
52
- """
53
- Get the SQL of the query.
54
-
55
- Returns:
56
- str: The SQL of the query.
57
-
58
- Example:
59
- >>> from geobox import GeoboxClient
60
- >>> from geobox.query import Query
61
- >>> client = GeoboxClient()
62
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
63
- >>> query.sql
64
- 'SELECT * FROM some_layer'
65
- """
66
- return self.data['sql']
67
-
68
-
69
- @sql.setter
70
- def sql(self, value: str) -> None:
71
- """
72
- Set the SQL of the query.
73
-
74
- Args:
75
- value (str): The SQL of the query.
76
-
77
- Returns:
78
- None
79
-
80
- Example:
81
- >>> from geobox import GeoboxClient
82
- >>> from geobox.query import Query
83
- >>> client = GeoboxClient()
84
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
85
- >>> query.sql = 'SELECT * FROM some_layer'
86
- >>> query.save()
87
- """
88
- self.data['sql'] = value
89
-
90
-
91
- @property
92
- def params(self) -> List[Dict]:
93
- """
94
- Get the parameters of the query.
95
-
96
- Returns:
97
- List[Dict]: The parameters of the query.
98
-
99
- Example:
100
- >>> from geobox import GeoboxClient
101
- >>> from geobox.query import Query
102
- >>> client = GeoboxClient()
103
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
104
- >>> query.params
105
- [{'name': 'layer', 'value': '12345678-1234-5678-1234-567812345678', 'type': 'Layer'}]
106
- """
107
- if not isinstance(self.data.get('params'), list):
108
- self.data['params'] = []
109
-
110
- return self.data['params']
111
-
112
-
113
- @params.setter
114
- def params(self, value: Dict) -> None:
115
- """
116
- Set the parameters of the query.
117
-
118
- Args:
119
- value (Dict): The parameters of the query.
120
-
121
- Returns:
122
- None
123
-
124
- Example:
125
- >>> from geobox import GeoboxClient
126
- >>> from geobox.query import Query
127
- >>> client = GeoboxClient()
128
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
129
- >>> query.params = [{'name': 'layer', 'value': '12345678-1234-5678-1234-567812345678', 'type': 'Layer'}]
130
- >>> query.save()
131
- """
132
- if not isinstance(self.data.get('params'), list):
133
- self.data['params'] = []
134
-
135
- self.data['params'] = value
136
-
137
-
138
- @classmethod
139
- def get_queries(cls, api: 'GeoboxClient', **kwargs) -> Union[List['Query'], int]:
140
- """
141
- Get Queries
142
-
143
- Args:
144
- api (GeoboxClient): The GeoboxClient instance for making requests.
145
-
146
- Keyword Args:
147
- q (str): query filter based on OGC CQL standard. e.g. "field1 LIKE '%GIS%' AND created_at > '2021-01-01'"
148
- search (str): search term for keyword-based searching among search_fields or all textual fields if search_fields does not have value. NOTE: if q param is defined this param will be ignored.
149
- search_fields (str): comma separated list of fields for searching
150
- order_by (str): comma separated list of fields for sorting results [field1 A|D, field2 A|D, …]. e.g. name A, type D. NOTE: "A" denotes ascending order and "D" denotes descending order.
151
- return_count (bool): Whether to return total count. default is False.
152
- skip (int): Number of queries to skip. default is 0.
153
- limit(int): Maximum number of queries to return. default is 10.
154
- user_id (int): Specific user. privileges required.
155
- shared (bool): Whether to return shared queries. default is False.
156
-
157
- Returns:
158
- List[Query] | int: list of queries or the number of queries.
159
-
160
- Example:
161
- >>> from geobox import GeoboxClient
162
- >>> from geobox.query import Query
163
- >>> client = GeoboxClient()
164
- >>> queries = Query.get_queries(client)
165
- or
166
- >>> queries = client.get_queries()
167
- """
168
- params = {
169
- 'f': 'json',
170
- 'q': kwargs.get('q'),
171
- 'search': kwargs.get('search'),
172
- 'search_field': kwargs.get('search_field'),
173
- 'order_by': kwargs.get('order_by'),
174
- 'return_count': kwargs.get('return_count', False),
175
- 'skip': kwargs.get('skip', 0),
176
- 'limit': kwargs.get('limit', 10),
177
- 'user_id': kwargs.get('user_id'),
178
- 'shared': kwargs.get('shared', False)
179
- }
180
- return super()._get_list(api, cls.BASE_ENDPOINT, params, factory_func=lambda api, item: Query(api, item['uuid'], item))
181
-
182
-
183
- @classmethod
184
- def create_query(cls, api: 'GeoboxClient', name: str, display_name: str = None, description:str = None, sql: str = None, params: List = None) -> 'Query':
185
- """
186
- Creates a new query.
187
-
188
- Args:
189
- api (Api): The GeoboxClient instance for making requests.
190
- name (str): The name of the query.
191
- display_name (str, optional): The display name of the query.
192
- description (str, optional): The description of the query.
193
- sql (str, optional): The SQL statement for the query.
194
- params (list, optional): The parameters for the SQL statement.
195
-
196
- Returns:
197
- Query: The created query instance.
198
-
199
- Example:
200
- >>> from geobox import GeoboxClient
201
- >>> from geobox.query import Query
202
- >>> client = GeoboxClient()
203
- >>> query = Query.create_query(client, name='query_name', display_name='Query Name', sql='SELECT * FROM some_layer')
204
- or
205
- >>> query = client.create_query(name='query_name', display_name='Query Name', sql='SELECT * FROM some_layer')
206
- """
207
- data = {
208
- "name": name,
209
- "display_name": display_name,
210
- "description": description,
211
- "sql": sql,
212
- "params": params
213
- }
214
- return super()._create(api, cls.BASE_ENDPOINT, data, factory_func=lambda api, item: Query(api, item['uuid'], item))
215
-
216
-
217
- @classmethod
218
- def get_query(cls, api: 'GeoboxClient', uuid: str, user_id: int = None) -> 'Query':
219
- """
220
- Retrieves a query by its UUID.
221
-
222
- Args:
223
- api (Api): The GeoboxClient instance for making requests.
224
- uuid (str): The UUID of the query.
225
- user_id (int, optional): specific user ID. privileges required.
226
-
227
- Returns:
228
- Query: The retrieved query instance.
229
-
230
- Example:
231
- >>> from geobox import GeoboxClient
232
- >>> from geobox.query import Query
233
- >>> client = GeoboxClient()
234
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
235
- or
236
- >>> query = client.get_query(uuid="12345678-1234-5678-1234-567812345678")
237
- """
238
- params = {
239
- 'f': 'json',
240
- 'user_id': user_id
241
- }
242
- return super()._get_detail(api, cls.BASE_ENDPOINT, uuid, params, factory_func=lambda api, item: Query(api, item['uuid'], item))
243
-
244
-
245
- @classmethod
246
- def get_query_by_name(cls, api: 'GeoboxClient', name: str, user_id: int = None) -> Union['Query', None]:
247
- """
248
- Get a query by name
249
-
250
- Args:
251
- api (GeoboxClient): The GeoboxClient instance for making requests.
252
- name (str): the name of the query to get
253
- user_id (int, optional): specific user. privileges required.
254
-
255
- Returns:
256
- Query | None: returns the query if a query matches the given name, else None
257
-
258
- Example:
259
- >>> from geobox import GeoboxClient
260
- >>> from geobox.query import Query
261
- >>> client = GeoboxClient()
262
- >>> query = Query.get_query_by_name(client, name='test')
263
- or
264
- >>> query = client.get_query_by_name(name='test')
265
- """
266
- queries = cls.get_queries(api, q=f"name = '{name}'", user_id=user_id)
267
- if queries and queries[0].name == name:
268
- return queries[0]
269
- else:
270
- return None
271
-
272
-
273
- @classmethod
274
- def get_system_queries(cls, api: 'GeoboxClient', **kwargs) -> List['Query']:
275
- """
276
- Returns the system queries as a list of Query objects.
277
-
278
- Args:
279
- api (GeoboxClient): The GeoboxClient instance for making requests.
280
-
281
- Keyword Args:
282
- q (str): query filter based on OGC CQL standard. e.g. "field1 LIKE '%GIS%' AND created_at > '2021-01-01'".
283
- search (str): search term for keyword-based searching among search_fields or all textual fields if search_fields does not have value. NOTE: if q param is defined this param will be ignored.
284
- search_fields (str): comma separated list of fields for searching.
285
- order_by (str): comma separated list of fields for sorting results [field1 A|D, field2 A|D, …]. e.g. name A, type D. NOTE: "A" denotes ascending order and "D" denotes descending order.
286
- return_count (bool): whether to return the total count of queries. default is False.
287
- skip (int): number of queries to skip. minimum is 0. default is 0.
288
- limit (int): number of queries to return. minimum is 1. default is 100.
289
- user_id (int): specific user. privileges required.
290
- shared (bool): whether to return shared queries. default is False.
291
-
292
- Returns:
293
- List[Query]: list of system queries.
294
-
295
- Example:
296
- >>> from geobox import GeoboxClient
297
- >>> from geobox.query import Query
298
- >>> client = GeoboxClient()
299
- >>> queries = Query.get_system_queries(client)
300
- or
301
- >>> queries = client.get_system_queries()
302
- """
303
- params = {
304
- 'f': 'json',
305
- 'q': kwargs.get('q'),
306
- 'search': kwargs.get('search'),
307
- 'search_fields': kwargs.get('search_fields'),
308
- 'order_by': kwargs.get('order_by'),
309
- 'return_count': kwargs.get('return_count', False),
310
- 'skip': kwargs.get('skip', 0),
311
- 'limit': kwargs.get('limit', 100),
312
- 'user_id': kwargs.get('user_id'),
313
- 'shared': kwargs.get('shared', False)
314
- }
315
- endpoint = urljoin(cls.BASE_ENDPOINT, 'systemQueries/')
316
- def factory_func(api, item):
317
- query = Query(api, item['uuid'], item)
318
- query._system_query = True
319
- return query
320
-
321
- return super()._get_list(api, endpoint, params, factory_func=factory_func)
322
-
323
-
324
- def add_param(self, name: str, value: str, type: 'QueryParamType', default_value: str = None, Domain: Dict = None) -> None:
325
- """
326
- Add a parameter to the query parameters.
327
-
328
- Args:
329
- name (str): The name of the parameter.
330
- value (str): The value of the parameter.
331
- type (str): The type of the parameter (default: 'Layer').
332
- default_value (str, optional): The default value for the parameter.
333
- Domain (Dict, optional): Domain information for the parameter.
334
-
335
- Returns:
336
- None
337
-
338
- Raises:
339
- PermissionError: If the query is a read-only system query.
340
-
341
- Example:
342
- >>> from geobox import GeoboxClient
343
- >>> from geobox.query import Query
344
- >>> client = GeoboxClient()
345
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
346
- or
347
- >>> query = client.get_query(uuid="12345678-1234-5678-1234-567812345678")
348
- >>> query.add_param(name='param_name', value='param_value', type=QueryParamType.LAYER)
349
- >>> query.save()
350
- """
351
- self.params.append({
352
- 'name': name,
353
- 'value': value,
354
- 'type': type.value,
355
- 'default_value': default_value,
356
- 'Domain': Domain
357
- })
358
-
359
-
360
- def remove_param(self, name: str) -> None:
361
- """
362
- Remove a parameter from the query parameters by name.
363
-
364
- Args:
365
- name (str): The name of the parameter to remove.
366
-
367
- Returns:
368
- None
369
-
370
- Raises:
371
- ValueError: If the parameter is not found in query parameters.
372
- PermissionError: If the query is a read-only system query.
373
-
374
- Example:
375
- >>> from geobox import GeoboxClient
376
- >>> from geobox.query import Query
377
- >>> client = GeoboxClient()
378
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
379
- or
380
- >>> query = client.get_query(uuid="12345678-1234-5678-1234-567812345678")
381
- >>> query.remove_param(name='param_name')
382
- >>> query.save()
383
- """
384
- for i, param in enumerate(self.params):
385
- if param.get('name') == name:
386
- self.params.pop(i)
387
- return
388
-
389
- raise ValueError(f"Parameter with name '{name}' not found in query parameters")
390
-
391
-
392
- def execute(self,
393
- f: str = "json",
394
- result_type: QueryResultType = QueryResultType.both,
395
- return_count: bool = None,
396
- out_srid: int = None,
397
- quant_factor: int = 1000000,
398
- bbox_srid: int = None,
399
- skip: int = None,
400
- limit: int = None,
401
- skip_geometry: bool = False) -> Union[Dict, int]:
402
- """
403
- Executes a query with the given SQL statement and parameters.
404
-
405
- Args:
406
- f (str): the output format of the executed query. options are: json, topojson. default is json.
407
- result_type (QueryResultType, optional): The type of result to return (default is "both").
408
- return_count (bool, optional): Whether to return the count of results.
409
- out_srid (int, optional): The output spatial reference ID.
410
- quant_factor (int, optional): The quantization factor (default is 1000000).
411
- bbox_srid (int, optional): The bounding box spatial reference ID.
412
- skip (int, optional): The number of results to skip.
413
- limit (int, optional): The maximum number of results to return.
414
- skip_geometry (bool): Whether to skip the geometry part of the features or not. default is False.
415
-
416
- Returns:
417
- Dict | int: The result of the query execution or the count number of the result
418
-
419
- Example:
420
- >>> from geobox import GeoboxClient
421
- >>> from geobox.query import Query
422
- >>> client = GeoboxClient()
423
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
424
- or
425
- >>> query = client.get_query(uuid="12345678-1234-5678-1234-567812345678")
426
- >>> query.execute(f='json')
427
- """
428
- if not self.sql:
429
- raise ValueError('"sql" parameter is required for this action!')
430
- if not self.params:
431
- raise ValueError('"params" parameter is required for this action!')
432
-
433
- data = clean_data({
434
- "f": f if f in ['json', 'topojson'] else None,
435
- "sql": self.sql,
436
- "params": self.params,
437
- "result_type": result_type.value,
438
- "return_count": return_count,
439
- "out_srid": out_srid,
440
- "quant_factor": quant_factor,
441
- "bbox_srid": bbox_srid,
442
- "skip": skip,
443
- "limit": limit,
444
- "skip_geometry": skip_geometry
445
- })
446
-
447
- endpoint = urljoin(self.BASE_ENDPOINT, 'exec/')
448
- self.result = self.api.post(endpoint, data)
449
- return self.result
450
-
451
-
452
- def update(self, **kwargs) -> Dict:
453
- """
454
- Updates the query with new data.
455
-
456
- Keyword Args:
457
- name (str): The new name of the query.
458
- display_name (str): The new display name of the query.
459
- sql (str): The new SQL statement for the query.
460
- params (list): The new parameters for the SQL statement.
461
-
462
- Returns:
463
- Dict: The updated query data.
464
-
465
- Raises:
466
- PermissionError: If the query is a read-only system query.
467
-
468
- Example:
469
- >>> from geobox import GeoboxClient
470
- >>> from geobox.query import Query
471
- >>> client = GeoboxClient()
472
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
473
- or
474
- >>> query = client.get_query(uuid="12345678-1234-5678-1234-567812345678")
475
- >>> query.update(name='new_name')
476
- """
477
- self._check_access()
478
-
479
- data = {
480
- "name": kwargs.get('name'),
481
- "display_name": kwargs.get('display_name'),
482
- "sql": kwargs.get('sql'),
483
- "params": kwargs.get('params')
484
- }
485
- super()._update(self.endpoint, data)
486
-
487
-
488
- def save(self) -> None:
489
- """
490
- Save the query. Creates a new query if query uuid is None, updates existing query otherwise.
491
-
492
- Returns:
493
- None
494
-
495
- Example:
496
- >>> from geobox import GeoboxClient
497
- >>> from geobox.query import Query
498
- >>> client = GeoboxClient()
499
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
500
- >>> query.save()
501
- """
502
- self.params = [item for item in self.params if item.get('value')]
503
-
504
- try:
505
- if self.__getattr__('uuid'):
506
- self.update(name=self.data['name'], display_name=self.data['display_name'], sql=self.sql, params=self.params)
507
- except AttributeError:
508
- response = self.api.post(self.BASE_ENDPOINT, self.data)
509
- self.endpoint = urljoin(self.BASE_ENDPOINT, f'{response["uuid"]}/')
510
- self.data.update(response)
511
-
512
-
513
- def delete(self) -> str:
514
- """
515
- Deletes a query.
516
-
517
- Returns:
518
- str: The response from the API.
519
-
520
- Raises:
521
- PermissionError: If the query is a read-only system query
522
-
523
- Example:
524
- >>> from geobox import GeoboxClient
525
- >>> from geobox.query import Query
526
- >>> client = GeoboxClient()
527
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
528
- >>> query.delete()
529
- """
530
- self._check_access()
531
- super().delete(self.endpoint)
532
-
533
-
534
- def share(self, users: List['User']) -> None:
535
- """
536
- Shares the query with specified users.
537
-
538
- Args:
539
- users (List[User]): The list of user objects to share the query with.
540
-
541
- Returns:
542
- None
543
-
544
- Raises:
545
- PermissionError: If the query is a read-only system query.
546
-
547
- Example:
548
- >>> from geobox import GeoboxClient
549
- >>> from geobox.query import Query
550
- >>> client = GeoboxClient()
551
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
552
- >>> users = client.search_users(search="John")
553
- >>> query.share(users=users)
554
- """
555
- self._check_access()
556
- super()._share(self.endpoint, users)
557
-
558
-
559
- def unshare(self, users: List['User']) -> None:
560
- """
561
- Unshares the query with specified users.
562
-
563
- Args:
564
- users (List[User]): The list of user objects to unshare the query with.
565
-
566
- Returns:
567
- None
568
-
569
- Raises:
570
- PermissionError: If the query is a read-only system query.
571
-
572
- Example:
573
- >>> from geobox import GeoboxClient
574
- >>> from geobox.query import Query
575
- >>> client = GeoboxClient()
576
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
577
- >>> users = client.search_users(search="John")
578
- >>> query.unshare(users=users)
579
- """
580
- self._check_access()
581
- super()._unshare(self.endpoint, users)
582
-
583
-
584
- def get_shared_users(self, search: str = None, skip: int = 0, limit: int = 10) -> List['User']:
585
- """
586
- Retrieves the list of users the query is shared with.
587
-
588
- Args:
589
- search (str, optional): the search query.
590
- skip (int, optional): The number of users to skip.
591
- limit (int, optional): The maximum number of users to retrieve.
592
-
593
- Returns:
594
- List[User]: The list of shared users.
595
-
596
- Example:
597
- >>> from geobox import GeoboxClient
598
- >>> from geobox.query import Query
599
- >>> client = GeoboxClient()
600
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
601
- >>> users = client.search_users(search="John")
602
- >>> query.get_shared_users(search='John', skip=0, limit=10)
603
- """
604
- self._check_access()
605
- params = {
606
- 'search': search,
607
- 'skip': skip,
608
- 'limit': limit
609
- }
610
- return super()._get_shared_users(self.endpoint, params)
611
-
612
-
613
- @property
614
- def thumbnail(self) -> str:
615
- """
616
- Retrieves the thumbnail URL for the query.
617
-
618
- Returns:
619
- str: The thumbnail URL.
620
-
621
- Example:
622
- >>> from geobox import GeoboxClient
623
- >>> from geobox.query import Query
624
- >>> client = GeoboxClient()
625
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
626
- >>> query.thumbnail
627
- """
628
- return super().thumbnail()
629
-
630
-
631
- def save_as_layer(self, layer_name: str, layer_type: 'QueryGeometryType' = None) -> Task:
632
- """
633
- Saves the query as a new layer.
634
-
635
- Args:
636
- layer_name (str): The name of the new layer.
637
- layer_type (QueryGeometryType, optional): The type of the new layer.
638
-
639
- Returns:
640
- Task: The response task object.
641
-
642
- Raises:
643
- PermissionError: If the query is a read-only system query.
644
-
645
- Example:
646
- >>> from geobox import GeoboxClient
647
- >>> from geobox.query import Query
648
- >>> client = GeoboxClient()
649
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
650
- >>> query.save_as_layer(layer_name='test')
651
- """
652
- params = [{
653
- "name": item.get('name'),
654
- "type": item.get('type'),
655
- "value": item.get('default_value') if not item.get('value') else item.get('value')
656
- } for item in self.params]
657
-
658
- data = clean_data({
659
- "sql": self.sql,
660
- "params": params,
661
- "layer_name": layer_name,
662
- "layer_type": layer_type.value if layer_type else None
663
- })
664
-
665
- endpoint = urljoin(self.BASE_ENDPOINT, 'saveAsLayer/')
666
- response = self.api.post(endpoint, data)
667
- task = Task.get_task(self.api, response.get('task_id'))
668
- return task
669
-
670
-
671
- def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncQuery':
672
- """
673
- Switch to async version of the query instance to have access to the async methods
674
-
675
- Args:
676
- async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
677
-
678
- Returns:
679
- geobox.aio.query.Query: the async instance of the query.
680
-
681
- Example:
682
- >>> from geobox import Geoboxclient
683
- >>> from geobox.aio import AsyncGeoboxClient
684
- >>> from geobox.query import Query
685
- >>> client = GeoboxClient()
686
- >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
687
- >>> async with AsyncGeoboxClient() as async_client:
688
- >>> async_query = query.to_async(async_client)
689
- """
690
- from .aio.query import Query as AsyncQuery
691
-
1
+ from urllib.parse import urljoin
2
+ from typing import Dict, List, TYPE_CHECKING, Union
3
+
4
+ from .utils import clean_data
5
+ from .base import Base
6
+ from .task import Task
7
+ from .enums import QueryResultType, QueryGeometryType, QueryParamType
8
+
9
+ if TYPE_CHECKING:
10
+ from . import GeoboxClient
11
+ from .user import User
12
+ from .aio import AsyncGeoboxClient
13
+ from .aio.query import AsyncQuery
14
+
15
+ class Query(Base):
16
+
17
+ BASE_ENDPOINT: str = 'queries/'
18
+
19
+ def __init__(self,
20
+ api: 'GeoboxClient',
21
+ uuid: str = None,
22
+ data: Dict = {}):
23
+ """
24
+ Constructs all the necessary attributes for the Query object.
25
+
26
+ Args:
27
+ api (Api): The API instance.
28
+ uuid (str): The UUID of the query.
29
+ data (dict, optional): The data of the query.
30
+ """
31
+ self.result = {}
32
+ self._system_query = False
33
+ super().__init__(api, uuid=uuid, data=data)
34
+
35
+
36
+ def _check_access(self) -> None:
37
+ """
38
+ Check if the query is a system query.
39
+
40
+ Returns:
41
+ None
42
+
43
+ Raises:
44
+ PermissionError: If the query is a read-only system query.
45
+ """
46
+ if self._system_query:
47
+ raise PermissionError("Cannot modify system queries - they are read-only")
48
+
49
+
50
+ @property
51
+ def sql(self) -> str:
52
+ """
53
+ Get the SQL of the query.
54
+
55
+ Returns:
56
+ str: The SQL of the query.
57
+
58
+ Example:
59
+ >>> from geobox import GeoboxClient
60
+ >>> from geobox.query import Query
61
+ >>> client = GeoboxClient()
62
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
63
+ >>> query.sql
64
+ 'SELECT * FROM some_layer'
65
+ """
66
+ return self.data['sql']
67
+
68
+
69
+ @sql.setter
70
+ def sql(self, value: str) -> None:
71
+ """
72
+ Set the SQL of the query.
73
+
74
+ Args:
75
+ value (str): The SQL of the query.
76
+
77
+ Returns:
78
+ None
79
+
80
+ Example:
81
+ >>> from geobox import GeoboxClient
82
+ >>> from geobox.query import Query
83
+ >>> client = GeoboxClient()
84
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
85
+ >>> query.sql = 'SELECT * FROM some_layer'
86
+ >>> query.save()
87
+ """
88
+ self.data['sql'] = value
89
+
90
+
91
+ @property
92
+ def params(self) -> List[Dict]:
93
+ """
94
+ Get the parameters of the query.
95
+
96
+ Returns:
97
+ List[Dict]: The parameters of the query.
98
+
99
+ Example:
100
+ >>> from geobox import GeoboxClient
101
+ >>> from geobox.query import Query
102
+ >>> client = GeoboxClient()
103
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
104
+ >>> query.params
105
+ [{'name': 'layer', 'value': '12345678-1234-5678-1234-567812345678', 'type': 'Layer'}]
106
+ """
107
+ if not isinstance(self.data.get('params'), list):
108
+ self.data['params'] = []
109
+
110
+ return self.data['params']
111
+
112
+
113
+ @params.setter
114
+ def params(self, value: Dict) -> None:
115
+ """
116
+ Set the parameters of the query.
117
+
118
+ Args:
119
+ value (Dict): The parameters of the query.
120
+
121
+ Returns:
122
+ None
123
+
124
+ Example:
125
+ >>> from geobox import GeoboxClient
126
+ >>> from geobox.query import Query
127
+ >>> client = GeoboxClient()
128
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
129
+ >>> query.params = [{'name': 'layer', 'value': '12345678-1234-5678-1234-567812345678', 'type': 'Layer'}]
130
+ >>> query.save()
131
+ """
132
+ if not isinstance(self.data.get('params'), list):
133
+ self.data['params'] = []
134
+
135
+ self.data['params'] = value
136
+
137
+
138
+ @classmethod
139
+ def get_queries(cls, api: 'GeoboxClient', **kwargs) -> Union[List['Query'], int]:
140
+ """
141
+ Get Queries
142
+
143
+ Args:
144
+ api (GeoboxClient): The GeoboxClient instance for making requests.
145
+
146
+ Keyword Args:
147
+ q (str): query filter based on OGC CQL standard. e.g. "field1 LIKE '%GIS%' AND created_at > '2021-01-01'"
148
+ search (str): search term for keyword-based searching among search_fields or all textual fields if search_fields does not have value. NOTE: if q param is defined this param will be ignored.
149
+ search_fields (str): comma separated list of fields for searching
150
+ order_by (str): comma separated list of fields for sorting results [field1 A|D, field2 A|D, …]. e.g. name A, type D. NOTE: "A" denotes ascending order and "D" denotes descending order.
151
+ return_count (bool): Whether to return total count. default is False.
152
+ skip (int): Number of queries to skip. default is 0.
153
+ limit(int): Maximum number of queries to return. default is 10.
154
+ user_id (int): Specific user. privileges required.
155
+ shared (bool): Whether to return shared queries. default is False.
156
+
157
+ Returns:
158
+ List[Query] | int: list of queries or the number of queries.
159
+
160
+ Example:
161
+ >>> from geobox import GeoboxClient
162
+ >>> from geobox.query import Query
163
+ >>> client = GeoboxClient()
164
+ >>> queries = Query.get_queries(client)
165
+ or
166
+ >>> queries = client.get_queries()
167
+ """
168
+ params = {
169
+ 'f': 'json',
170
+ 'q': kwargs.get('q'),
171
+ 'search': kwargs.get('search'),
172
+ 'search_field': kwargs.get('search_field'),
173
+ 'order_by': kwargs.get('order_by'),
174
+ 'return_count': kwargs.get('return_count', False),
175
+ 'skip': kwargs.get('skip', 0),
176
+ 'limit': kwargs.get('limit', 10),
177
+ 'user_id': kwargs.get('user_id'),
178
+ 'shared': kwargs.get('shared', False)
179
+ }
180
+ return super()._get_list(api, cls.BASE_ENDPOINT, params, factory_func=lambda api, item: Query(api, item['uuid'], item))
181
+
182
+
183
+ @classmethod
184
+ def create_query(cls, api: 'GeoboxClient', name: str, display_name: str = None, description:str = None, sql: str = None, params: List = None) -> 'Query':
185
+ """
186
+ Creates a new query.
187
+
188
+ Args:
189
+ api (Api): The GeoboxClient instance for making requests.
190
+ name (str): The name of the query.
191
+ display_name (str, optional): The display name of the query.
192
+ description (str, optional): The description of the query.
193
+ sql (str, optional): The SQL statement for the query.
194
+ params (list, optional): The parameters for the SQL statement.
195
+
196
+ Returns:
197
+ Query: The created query instance.
198
+
199
+ Example:
200
+ >>> from geobox import GeoboxClient
201
+ >>> from geobox.query import Query
202
+ >>> client = GeoboxClient()
203
+ >>> query = Query.create_query(client, name='query_name', display_name='Query Name', sql='SELECT * FROM some_layer')
204
+ or
205
+ >>> query = client.create_query(name='query_name', display_name='Query Name', sql='SELECT * FROM some_layer')
206
+ """
207
+ data = {
208
+ "name": name,
209
+ "display_name": display_name,
210
+ "description": description,
211
+ "sql": sql,
212
+ "params": params
213
+ }
214
+ return super()._create(api, cls.BASE_ENDPOINT, data, factory_func=lambda api, item: Query(api, item['uuid'], item))
215
+
216
+
217
+ @classmethod
218
+ def get_query(cls, api: 'GeoboxClient', uuid: str, user_id: int = None) -> 'Query':
219
+ """
220
+ Retrieves a query by its UUID.
221
+
222
+ Args:
223
+ api (Api): The GeoboxClient instance for making requests.
224
+ uuid (str): The UUID of the query.
225
+ user_id (int, optional): specific user ID. privileges required.
226
+
227
+ Returns:
228
+ Query: The retrieved query instance.
229
+
230
+ Example:
231
+ >>> from geobox import GeoboxClient
232
+ >>> from geobox.query import Query
233
+ >>> client = GeoboxClient()
234
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
235
+ or
236
+ >>> query = client.get_query(uuid="12345678-1234-5678-1234-567812345678")
237
+ """
238
+ params = {
239
+ 'f': 'json',
240
+ 'user_id': user_id
241
+ }
242
+ return super()._get_detail(api, cls.BASE_ENDPOINT, uuid, params, factory_func=lambda api, item: Query(api, item['uuid'], item))
243
+
244
+
245
+ @classmethod
246
+ def get_query_by_name(cls, api: 'GeoboxClient', name: str, user_id: int = None) -> Union['Query', None]:
247
+ """
248
+ Get a query by name
249
+
250
+ Args:
251
+ api (GeoboxClient): The GeoboxClient instance for making requests.
252
+ name (str): the name of the query to get
253
+ user_id (int, optional): specific user. privileges required.
254
+
255
+ Returns:
256
+ Query | None: returns the query if a query matches the given name, else None
257
+
258
+ Example:
259
+ >>> from geobox import GeoboxClient
260
+ >>> from geobox.query import Query
261
+ >>> client = GeoboxClient()
262
+ >>> query = Query.get_query_by_name(client, name='test')
263
+ or
264
+ >>> query = client.get_query_by_name(name='test')
265
+ """
266
+ queries = cls.get_queries(api, q=f"name = '{name}'", user_id=user_id)
267
+ if queries and queries[0].name == name:
268
+ return queries[0]
269
+ else:
270
+ return None
271
+
272
+
273
+ @classmethod
274
+ def get_system_queries(cls, api: 'GeoboxClient', **kwargs) -> List['Query']:
275
+ """
276
+ Returns the system queries as a list of Query objects.
277
+
278
+ Args:
279
+ api (GeoboxClient): The GeoboxClient instance for making requests.
280
+
281
+ Keyword Args:
282
+ q (str): query filter based on OGC CQL standard. e.g. "field1 LIKE '%GIS%' AND created_at > '2021-01-01'".
283
+ search (str): search term for keyword-based searching among search_fields or all textual fields if search_fields does not have value. NOTE: if q param is defined this param will be ignored.
284
+ search_fields (str): comma separated list of fields for searching.
285
+ order_by (str): comma separated list of fields for sorting results [field1 A|D, field2 A|D, …]. e.g. name A, type D. NOTE: "A" denotes ascending order and "D" denotes descending order.
286
+ return_count (bool): whether to return the total count of queries. default is False.
287
+ skip (int): number of queries to skip. minimum is 0. default is 0.
288
+ limit (int): number of queries to return. minimum is 1. default is 100.
289
+ user_id (int): specific user. privileges required.
290
+ shared (bool): whether to return shared queries. default is False.
291
+
292
+ Returns:
293
+ List[Query]: list of system queries.
294
+
295
+ Example:
296
+ >>> from geobox import GeoboxClient
297
+ >>> from geobox.query import Query
298
+ >>> client = GeoboxClient()
299
+ >>> queries = Query.get_system_queries(client)
300
+ or
301
+ >>> queries = client.get_system_queries()
302
+ """
303
+ params = {
304
+ 'f': 'json',
305
+ 'q': kwargs.get('q'),
306
+ 'search': kwargs.get('search'),
307
+ 'search_fields': kwargs.get('search_fields'),
308
+ 'order_by': kwargs.get('order_by'),
309
+ 'return_count': kwargs.get('return_count', False),
310
+ 'skip': kwargs.get('skip', 0),
311
+ 'limit': kwargs.get('limit', 100),
312
+ 'user_id': kwargs.get('user_id'),
313
+ 'shared': kwargs.get('shared', False)
314
+ }
315
+ endpoint = urljoin(cls.BASE_ENDPOINT, 'systemQueries/')
316
+ def factory_func(api, item):
317
+ query = Query(api, item['uuid'], item)
318
+ query._system_query = True
319
+ return query
320
+
321
+ return super()._get_list(api, endpoint, params, factory_func=factory_func)
322
+
323
+
324
+ def add_param(self, name: str, value: str, type: 'QueryParamType', default_value: str = None, Domain: Dict = None) -> None:
325
+ """
326
+ Add a parameter to the query parameters.
327
+
328
+ Args:
329
+ name (str): The name of the parameter.
330
+ value (str): The value of the parameter.
331
+ type (str): The type of the parameter (default: 'Layer').
332
+ default_value (str, optional): The default value for the parameter.
333
+ Domain (Dict, optional): Domain information for the parameter.
334
+
335
+ Returns:
336
+ None
337
+
338
+ Raises:
339
+ PermissionError: If the query is a read-only system query.
340
+
341
+ Example:
342
+ >>> from geobox import GeoboxClient
343
+ >>> from geobox.query import Query
344
+ >>> client = GeoboxClient()
345
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
346
+ or
347
+ >>> query = client.get_query(uuid="12345678-1234-5678-1234-567812345678")
348
+ >>> query.add_param(name='param_name', value='param_value', type=QueryParamType.LAYER)
349
+ >>> query.save()
350
+ """
351
+ self.params.append({
352
+ 'name': name,
353
+ 'value': value,
354
+ 'type': type.value,
355
+ 'default_value': default_value,
356
+ 'Domain': Domain
357
+ })
358
+
359
+
360
+ def remove_param(self, name: str) -> None:
361
+ """
362
+ Remove a parameter from the query parameters by name.
363
+
364
+ Args:
365
+ name (str): The name of the parameter to remove.
366
+
367
+ Returns:
368
+ None
369
+
370
+ Raises:
371
+ ValueError: If the parameter is not found in query parameters.
372
+ PermissionError: If the query is a read-only system query.
373
+
374
+ Example:
375
+ >>> from geobox import GeoboxClient
376
+ >>> from geobox.query import Query
377
+ >>> client = GeoboxClient()
378
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
379
+ or
380
+ >>> query = client.get_query(uuid="12345678-1234-5678-1234-567812345678")
381
+ >>> query.remove_param(name='param_name')
382
+ >>> query.save()
383
+ """
384
+ for i, param in enumerate(self.params):
385
+ if param.get('name') == name:
386
+ self.params.pop(i)
387
+ return
388
+
389
+ raise ValueError(f"Parameter with name '{name}' not found in query parameters")
390
+
391
+
392
+ def execute(self,
393
+ f: str = "json",
394
+ result_type: QueryResultType = QueryResultType.both,
395
+ return_count: bool = None,
396
+ out_srid: int = None,
397
+ quant_factor: int = 1000000,
398
+ bbox_srid: int = None,
399
+ skip: int = None,
400
+ limit: int = None,
401
+ skip_geometry: bool = False) -> Union[Dict, int]:
402
+ """
403
+ Executes a query with the given SQL statement and parameters.
404
+
405
+ Args:
406
+ f (str): the output format of the executed query. options are: json, topojson. default is json.
407
+ result_type (QueryResultType, optional): The type of result to return (default is "both").
408
+ return_count (bool, optional): Whether to return the count of results.
409
+ out_srid (int, optional): The output spatial reference ID.
410
+ quant_factor (int, optional): The quantization factor (default is 1000000).
411
+ bbox_srid (int, optional): The bounding box spatial reference ID.
412
+ skip (int, optional): The number of results to skip.
413
+ limit (int, optional): The maximum number of results to return.
414
+ skip_geometry (bool): Whether to skip the geometry part of the features or not. default is False.
415
+
416
+ Returns:
417
+ Dict | int: The result of the query execution or the count number of the result
418
+
419
+ Example:
420
+ >>> from geobox import GeoboxClient
421
+ >>> from geobox.query import Query
422
+ >>> client = GeoboxClient()
423
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
424
+ or
425
+ >>> query = client.get_query(uuid="12345678-1234-5678-1234-567812345678")
426
+ >>> query.execute(f='json')
427
+ """
428
+ if not self.sql:
429
+ raise ValueError('"sql" parameter is required for this action!')
430
+ if not self.params:
431
+ raise ValueError('"params" parameter is required for this action!')
432
+
433
+ data = clean_data({
434
+ "f": f if f in ['json', 'topojson'] else None,
435
+ "sql": self.sql,
436
+ "params": self.params,
437
+ "result_type": result_type.value,
438
+ "return_count": return_count,
439
+ "out_srid": out_srid,
440
+ "quant_factor": quant_factor,
441
+ "bbox_srid": bbox_srid,
442
+ "skip": skip,
443
+ "limit": limit,
444
+ "skip_geometry": skip_geometry
445
+ })
446
+
447
+ endpoint = urljoin(self.BASE_ENDPOINT, 'exec/')
448
+ self.result = self.api.post(endpoint, data)
449
+ return self.result
450
+
451
+
452
+ def update(self, **kwargs) -> Dict:
453
+ """
454
+ Updates the query with new data.
455
+
456
+ Keyword Args:
457
+ name (str): The new name of the query.
458
+ display_name (str): The new display name of the query.
459
+ sql (str): The new SQL statement for the query.
460
+ params (list): The new parameters for the SQL statement.
461
+
462
+ Returns:
463
+ Dict: The updated query data.
464
+
465
+ Raises:
466
+ PermissionError: If the query is a read-only system query.
467
+
468
+ Example:
469
+ >>> from geobox import GeoboxClient
470
+ >>> from geobox.query import Query
471
+ >>> client = GeoboxClient()
472
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
473
+ or
474
+ >>> query = client.get_query(uuid="12345678-1234-5678-1234-567812345678")
475
+ >>> query.update(name='new_name')
476
+ """
477
+ self._check_access()
478
+
479
+ data = {
480
+ "name": kwargs.get('name'),
481
+ "display_name": kwargs.get('display_name'),
482
+ "sql": kwargs.get('sql'),
483
+ "params": kwargs.get('params')
484
+ }
485
+ super()._update(self.endpoint, data)
486
+
487
+
488
+ def save(self) -> None:
489
+ """
490
+ Save the query. Creates a new query if query uuid is None, updates existing query otherwise.
491
+
492
+ Returns:
493
+ None
494
+
495
+ Example:
496
+ >>> from geobox import GeoboxClient
497
+ >>> from geobox.query import Query
498
+ >>> client = GeoboxClient()
499
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
500
+ >>> query.save()
501
+ """
502
+ self.params = [item for item in self.params if item.get('value')]
503
+
504
+ try:
505
+ if self.__getattr__('uuid'):
506
+ self.update(name=self.data['name'], display_name=self.data['display_name'], sql=self.sql, params=self.params)
507
+ except AttributeError:
508
+ response = self.api.post(self.BASE_ENDPOINT, self.data)
509
+ self.endpoint = urljoin(self.BASE_ENDPOINT, f'{response["uuid"]}/')
510
+ self.data.update(response)
511
+
512
+
513
+ def delete(self) -> str:
514
+ """
515
+ Deletes a query.
516
+
517
+ Returns:
518
+ str: The response from the API.
519
+
520
+ Raises:
521
+ PermissionError: If the query is a read-only system query
522
+
523
+ Example:
524
+ >>> from geobox import GeoboxClient
525
+ >>> from geobox.query import Query
526
+ >>> client = GeoboxClient()
527
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
528
+ >>> query.delete()
529
+ """
530
+ self._check_access()
531
+ super()._delete(self.endpoint)
532
+
533
+
534
+ def share(self, users: List['User']) -> None:
535
+ """
536
+ Shares the query with specified users.
537
+
538
+ Args:
539
+ users (List[User]): The list of user objects to share the query with.
540
+
541
+ Returns:
542
+ None
543
+
544
+ Raises:
545
+ PermissionError: If the query is a read-only system query.
546
+
547
+ Example:
548
+ >>> from geobox import GeoboxClient
549
+ >>> from geobox.query import Query
550
+ >>> client = GeoboxClient()
551
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
552
+ >>> users = client.search_users(search="John")
553
+ >>> query.share(users=users)
554
+ """
555
+ self._check_access()
556
+ super()._share(self.endpoint, users)
557
+
558
+
559
+ def unshare(self, users: List['User']) -> None:
560
+ """
561
+ Unshares the query with specified users.
562
+
563
+ Args:
564
+ users (List[User]): The list of user objects to unshare the query with.
565
+
566
+ Returns:
567
+ None
568
+
569
+ Raises:
570
+ PermissionError: If the query is a read-only system query.
571
+
572
+ Example:
573
+ >>> from geobox import GeoboxClient
574
+ >>> from geobox.query import Query
575
+ >>> client = GeoboxClient()
576
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
577
+ >>> users = client.search_users(search="John")
578
+ >>> query.unshare(users=users)
579
+ """
580
+ self._check_access()
581
+ super()._unshare(self.endpoint, users)
582
+
583
+
584
+ def get_shared_users(self, search: str = None, skip: int = 0, limit: int = 10) -> List['User']:
585
+ """
586
+ Retrieves the list of users the query is shared with.
587
+
588
+ Args:
589
+ search (str, optional): the search query.
590
+ skip (int, optional): The number of users to skip.
591
+ limit (int, optional): The maximum number of users to retrieve.
592
+
593
+ Returns:
594
+ List[User]: The list of shared users.
595
+
596
+ Example:
597
+ >>> from geobox import GeoboxClient
598
+ >>> from geobox.query import Query
599
+ >>> client = GeoboxClient()
600
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
601
+ >>> users = client.search_users(search="John")
602
+ >>> query.get_shared_users(search='John', skip=0, limit=10)
603
+ """
604
+ self._check_access()
605
+ params = {
606
+ 'search': search,
607
+ 'skip': skip,
608
+ 'limit': limit
609
+ }
610
+ return super()._get_shared_users(self.endpoint, params)
611
+
612
+
613
+ @property
614
+ def thumbnail(self) -> str:
615
+ """
616
+ Retrieves the thumbnail URL for the query.
617
+
618
+ Returns:
619
+ str: The thumbnail URL.
620
+
621
+ Example:
622
+ >>> from geobox import GeoboxClient
623
+ >>> from geobox.query import Query
624
+ >>> client = GeoboxClient()
625
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
626
+ >>> query.thumbnail
627
+ """
628
+ return super()._thumbnail()
629
+
630
+
631
+ def save_as_layer(self, layer_name: str, layer_type: 'QueryGeometryType' = None) -> Task:
632
+ """
633
+ Saves the query as a new layer.
634
+
635
+ Args:
636
+ layer_name (str): The name of the new layer.
637
+ layer_type (QueryGeometryType, optional): The type of the new layer.
638
+
639
+ Returns:
640
+ Task: The response task object.
641
+
642
+ Raises:
643
+ PermissionError: If the query is a read-only system query.
644
+
645
+ Example:
646
+ >>> from geobox import GeoboxClient
647
+ >>> from geobox.query import Query
648
+ >>> client = GeoboxClient()
649
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
650
+ >>> query.save_as_layer(layer_name='test')
651
+ """
652
+ params = [{
653
+ "name": item.get('name'),
654
+ "type": item.get('type'),
655
+ "value": item.get('default_value') if not item.get('value') else item.get('value')
656
+ } for item in self.params]
657
+
658
+ data = clean_data({
659
+ "sql": self.sql,
660
+ "params": params,
661
+ "layer_name": layer_name,
662
+ "layer_type": layer_type.value if layer_type else None
663
+ })
664
+
665
+ endpoint = urljoin(self.BASE_ENDPOINT, 'saveAsLayer/')
666
+ response = self.api.post(endpoint, data)
667
+ task = Task.get_task(self.api, response.get('task_id'))
668
+ return task
669
+
670
+
671
+ def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncQuery':
672
+ """
673
+ Switch to async version of the query instance to have access to the async methods
674
+
675
+ Args:
676
+ async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
677
+
678
+ Returns:
679
+ AsyncQuery: the async instance of the query.
680
+
681
+ Example:
682
+ >>> from geobox import Geoboxclient
683
+ >>> from geobox.aio import AsyncGeoboxClient
684
+ >>> from geobox.query import Query
685
+ >>> client = GeoboxClient()
686
+ >>> query = Query.get_query(client, uuid="12345678-1234-5678-1234-567812345678")
687
+ >>> async with AsyncGeoboxClient() as async_client:
688
+ >>> async_query = query.to_async(async_client)
689
+ """
690
+ from .aio.query import AsyncQuery
691
+
692
692
  return AsyncQuery(api=async_client, uuid=self.uuid, data=self.data)