quasardb 3.14.2.dev1__cp39-cp39-macosx_11_0_arm64.whl → 3.14.2.dev2__cp39-cp39-macosx_11_0_arm64.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.

Potentially problematic release.


This version of quasardb might be problematic. Click here for more details.

Files changed (57) hide show
  1. quasardb/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  2. quasardb/CMakeLists.txt +19 -12
  3. quasardb/Makefile +10 -10
  4. quasardb/__init__.py +33 -4
  5. quasardb/cluster.cpp +7 -1
  6. quasardb/cluster.hpp +111 -72
  7. quasardb/concepts.hpp +56 -12
  8. quasardb/continuous.cpp +84 -34
  9. quasardb/continuous.hpp +10 -7
  10. quasardb/convert/array.hpp +23 -6
  11. quasardb/convert/value.hpp +78 -7
  12. quasardb/date/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  13. quasardb/date/CMakeFiles/Export/a52b05f964b070ee926bcad51d3288af/dateTargets.cmake +12 -12
  14. quasardb/date/Makefile +10 -10
  15. quasardb/date/dateConfigVersion.cmake +9 -2
  16. quasardb/date/dateTargets.cmake +3 -7
  17. quasardb/detail/invoke.hpp +0 -0
  18. quasardb/detail/retry.cpp +30 -0
  19. quasardb/detail/retry.hpp +147 -0
  20. quasardb/detail/sleep.hpp +53 -0
  21. quasardb/{writer.cpp → detail/writer.cpp} +68 -162
  22. quasardb/detail/writer.hpp +550 -0
  23. quasardb/error.hpp +76 -1
  24. quasardb/libqdb_api.dylib +0 -0
  25. quasardb/masked_array.hpp +9 -2
  26. quasardb/module.cpp +20 -4
  27. quasardb/numpy/__init__.py +58 -10
  28. quasardb/object_tracker.hpp +2 -3
  29. quasardb/options.hpp +32 -3
  30. quasardb/pandas/__init__.py +59 -102
  31. quasardb/properties.cpp +41 -0
  32. quasardb/properties.hpp +85 -0
  33. quasardb/pybind11/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  34. quasardb/pybind11/Makefile +10 -10
  35. quasardb/quasardb.cpython-39-darwin.so +0 -0
  36. quasardb/range-v3/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  37. quasardb/range-v3/CMakeFiles/Export/d94ef200eca10a819b5858b33e808f5b/range-v3-targets.cmake +12 -12
  38. quasardb/range-v3/CMakeFiles/range.v3.headers.dir/DependInfo.cmake +6 -2
  39. quasardb/range-v3/CMakeFiles/range.v3.headers.dir/build.make +2 -2
  40. quasardb/range-v3/Makefile +10 -10
  41. quasardb/range-v3/cmake_install.cmake +12 -0
  42. quasardb/range-v3/range-v3-config-version.cmake +9 -2
  43. quasardb/range-v3/range-v3-config.cmake +3 -7
  44. quasardb/reader.cpp +282 -0
  45. quasardb/reader.hpp +256 -0
  46. quasardb/table.cpp +4 -36
  47. quasardb/table.hpp +69 -28
  48. quasardb/traits.hpp +23 -0
  49. quasardb/writer.hpp +245 -287
  50. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev2.dist-info}/METADATA +7 -7
  51. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev2.dist-info}/RECORD +54 -48
  52. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev2.dist-info}/WHEEL +1 -1
  53. quasardb/reader/ts_row.hpp +0 -281
  54. quasardb/reader/ts_value.hpp +0 -245
  55. quasardb/table_reader.hpp +0 -220
  56. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev2.dist-info}/LICENSE.md +0 -0
  57. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,550 @@
1
+ /*
2
+ *
3
+ * Official Python API
4
+ *
5
+ * Copyright (c) 2009-2021, quasardb SAS. All rights reserved.
6
+ * All rights reserved.
7
+ *
8
+ * Redistribution and use in source and binary forms, with or without
9
+ * modification, are permitted provided that the following conditions are met:
10
+ *
11
+ * * Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * * Redistributions in binary form must reproduce the above copyright
14
+ * notice, this list of conditions and the following disclaimer in the
15
+ * documentation and/or other materials provided with the distribution.
16
+ * * Neither the name of quasardb nor the names of its contributors may
17
+ * be used to endorse or promote products derived from this software
18
+ * without specific prior written permission.
19
+ *
20
+ * THIS SOFTWARE IS PROVIDED BY QUASARDB AND CONTRIBUTORS ``AS IS'' AND ANY
21
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
24
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ */
31
+ #pragma once
32
+
33
+ #include "../concepts.hpp"
34
+ #include "../convert/value.hpp"
35
+ #include "../dispatch.hpp"
36
+ #include "../error.hpp"
37
+ #include "../logger.hpp"
38
+ #include "../table.hpp"
39
+ #include "retry.hpp"
40
+ #include <variant>
41
+ #include <vector>
42
+
43
+ namespace qdb::detail
44
+ {
45
+
46
+ using deduplicate = std::variant<std::vector<std::string>, bool>;
47
+
48
+ enum deduplication_mode_t
49
+ {
50
+ deduplication_mode_drop,
51
+ deduplication_mode_upsert
52
+
53
+ };
54
+
55
+ constexpr inline qdb_exp_batch_deduplication_mode_t to_qdb(enum detail::deduplication_mode_t mode)
56
+ {
57
+ switch (mode)
58
+ {
59
+ case deduplication_mode_drop:
60
+ return qdb_exp_batch_deduplication_mode_drop;
61
+ case deduplication_mode_upsert:
62
+ return qdb_exp_batch_deduplication_mode_upsert;
63
+ default:
64
+ return qdb_exp_batch_deduplication_mode_disabled;
65
+ }
66
+ }
67
+
68
+ struct deduplicate_options
69
+ {
70
+ detail::deduplicate columns_;
71
+ deduplication_mode_t mode_;
72
+
73
+ deduplicate_options()
74
+ {
75
+ columns_ = false;
76
+ mode_ = deduplication_mode_drop;
77
+ };
78
+
79
+ deduplicate_options(deduplication_mode_t mode, detail::deduplicate columns)
80
+ : columns_{columns}
81
+ , mode_{mode} {};
82
+
83
+ static detail::deduplicate_options from_kwargs(py::kwargs args);
84
+ };
85
+
86
+ using int64_column = std::vector<qdb_int_t>;
87
+ using double_column = std::vector<double>;
88
+ using timestamp_column = std::vector<qdb_timespec_t>;
89
+ using blob_column = std::vector<qdb_blob_t>;
90
+ using string_column = std::vector<qdb_string_t>;
91
+
92
+ using any_column =
93
+ std::variant<int64_column, double_column, timestamp_column, blob_column, string_column>;
94
+
95
+ template <qdb_ts_column_type_t T>
96
+ struct column_of_type;
97
+
98
+ template <qdb_ts_column_type_t T>
99
+ struct make_column;
100
+
101
+ #define COLUMN_OF_TYPE_DECL(TYPE, COLUMN) \
102
+ template <> \
103
+ struct column_of_type<TYPE> \
104
+ { \
105
+ using value_type = COLUMN; \
106
+ }; \
107
+ \
108
+ template <> \
109
+ struct make_column<TYPE> \
110
+ { \
111
+ any_column inline operator()() \
112
+ { \
113
+ return COLUMN{}; \
114
+ }; \
115
+ };
116
+
117
+ COLUMN_OF_TYPE_DECL(qdb_ts_column_int64, int64_column);
118
+ COLUMN_OF_TYPE_DECL(qdb_ts_column_double, double_column);
119
+ COLUMN_OF_TYPE_DECL(qdb_ts_column_timestamp, timestamp_column);
120
+ COLUMN_OF_TYPE_DECL(qdb_ts_column_blob, blob_column);
121
+ COLUMN_OF_TYPE_DECL(qdb_ts_column_string, string_column);
122
+ COLUMN_OF_TYPE_DECL(qdb_ts_column_symbol, string_column);
123
+
124
+ #undef COLUMN_OF_TYPE_DECL
125
+
126
+ template <qdb_ts_column_type_t T>
127
+ std::vector<typename traits::qdb_column<T>::value_type> & access_column(
128
+ std::vector<any_column> & columns, size_t index)
129
+ {
130
+ using column_type = typename column_of_type<T>::value_type;
131
+ try
132
+ {
133
+ return std::get<column_type>(columns[index]);
134
+ }
135
+ catch (std::bad_variant_access const & /*e*/)
136
+ {
137
+ throw qdb::incompatible_type_exception{};
138
+ }
139
+ }
140
+
141
+ template <qdb_ts_column_type_t T>
142
+ std::size_t column_size(std::vector<any_column> & columns, size_t index)
143
+ {
144
+ return access_column<T>(columns, index).size();
145
+ }
146
+
147
+ template <qdb_ts_column_type_t T>
148
+ struct clear_column
149
+ {
150
+ void operator()(any_column & xs)
151
+ {
152
+ using value_type = typename detail::column_of_type<T>::value_type;
153
+ std::get<value_type>(xs).clear();
154
+ }
155
+ };
156
+
157
+ class staged_table
158
+ {
159
+ public:
160
+ staged_table(qdb::table const & table)
161
+ : _logger("quasardb.writer")
162
+ , _table_name(table.get_name())
163
+ {
164
+ _column_infos = table.list_columns();
165
+
166
+ std::transform(std::cbegin(_column_infos), std::cend(_column_infos),
167
+ std::back_inserter(_columns),
168
+
169
+ [](auto const & col) { return dispatch::by_column_type<detail::make_column>(col.type); });
170
+ }
171
+
172
+ ~staged_table()
173
+ {
174
+ clear();
175
+ }
176
+
177
+ void set_index(py::array const & timestamps);
178
+ void set_blob_column(std::size_t index, const masked_array & xs);
179
+ void set_string_column(std::size_t index, const masked_array & xs);
180
+ void set_double_column(std::size_t index, masked_array_t<traits::float64_dtype> const & xs);
181
+ void set_int64_column(std::size_t index, masked_array_t<traits::int64_dtype> const & xs);
182
+ void set_timestamp_column(
183
+ std::size_t index, masked_array_t<traits::datetime64_ns_dtype> const & xs);
184
+
185
+ std::vector<qdb_exp_batch_push_column_t> const & prepare_columns();
186
+
187
+ void prepare_table_data(qdb_exp_batch_push_table_data_t & table_data);
188
+
189
+ void prepare_batch(qdb_exp_batch_push_mode_t mode,
190
+ detail::deduplicate_options const & deduplicate_options,
191
+ qdb_ts_range_t * ranges,
192
+ qdb_exp_batch_push_table_t & batch);
193
+
194
+ static inline void _set_deduplication_mode(
195
+ enum detail::deduplication_mode_t mode, bool columns, qdb_exp_batch_push_table_t & out)
196
+ {
197
+ // Set deduplication mode only when `columns` is true, in which we will deduplicate based on
198
+ // *all* columns.
199
+ out.deduplication_mode =
200
+ (columns == true ? detail::to_qdb(mode) : qdb_exp_batch_deduplication_mode_disabled);
201
+ }
202
+
203
+ static inline void _set_deduplication_mode(enum detail::deduplication_mode_t mode,
204
+ std::vector<std::string> const & columns,
205
+ qdb_exp_batch_push_table_t & out)
206
+ {
207
+ // A specific set of columns to deduplicate has been provided, in which case
208
+ // we'll need to do a small transformation of the column names.
209
+ auto where_duplicate = std::make_unique<char const *[]>(columns.size());
210
+
211
+ std::transform(std::cbegin(columns), std::cend(columns), where_duplicate.get(),
212
+ [](std::string const & column) -> char const * { return column.c_str(); });
213
+
214
+ out.deduplication_mode = detail::to_qdb(mode);
215
+ out.where_duplicate = where_duplicate.release();
216
+ out.where_duplicate_count = columns.size();
217
+ }
218
+
219
+ inline void clear()
220
+ {
221
+ _index.clear();
222
+ for (size_t index = 0; index < _columns.size(); ++index)
223
+ {
224
+ dispatch::by_column_type<detail::clear_column>(_column_infos[index].type, _columns[index]);
225
+ }
226
+
227
+ _table_name.clear();
228
+ _column_infos.clear();
229
+ _columns_data.clear();
230
+ }
231
+
232
+ inline qdb_ts_range_t time_range() const
233
+ {
234
+ qdb_ts_range_t tr{_index.front(), _index.back()};
235
+ // our range is end-exclusive, so let's move the pointer one nanosecond
236
+ // *after* the last element in this batch.
237
+ //
238
+ // XXX(leon): this overflows if we're at exactly the last nanosecond of a second
239
+ tr.end.tv_nsec++;
240
+
241
+ return tr;
242
+ }
243
+
244
+ inline bool empty() const
245
+ {
246
+ return _index.empty();
247
+ }
248
+
249
+ private:
250
+ private:
251
+ qdb::logger _logger;
252
+
253
+ std::string _table_name;
254
+ std::vector<detail::column_info> _column_infos;
255
+ std::vector<qdb_timespec_t> _index;
256
+ std::vector<any_column> _columns;
257
+
258
+ std::vector<qdb_exp_batch_push_column_t> _columns_data;
259
+ };
260
+
261
+ /**
262
+ * Convenience class that holds data that can be pushed to the writer. Makes it
263
+ * easier for the end-user to provide the data in the correct format, in a single
264
+ * function call, if they decide to use the low-level writer API themselves.
265
+ */
266
+ class writer_data
267
+ {
268
+ public:
269
+ struct value_type
270
+ {
271
+ qdb::table table;
272
+ py::array index;
273
+ py::list column_data;
274
+ };
275
+
276
+ public:
277
+ void append(qdb::table const & table, py::handle const & index, py::list const & column_data)
278
+ {
279
+ py::array index_ = numpy::array::ensure<traits::datetime64_ns_dtype>(index);
280
+
281
+ /**
282
+ * Additional check that all the data is actually of the same length, and data has been
283
+ * provided for each and every column.
284
+ */
285
+ if (column_data.size() != table.list_columns().size())
286
+ {
287
+ throw qdb::invalid_argument_exception{"data must be provided for every table column"};
288
+ }
289
+
290
+ for (py::handle const & data : column_data)
291
+ {
292
+ qdb::masked_array data_ = data.cast<qdb::masked_array>();
293
+ if (data_.size() != static_cast<std::size_t>(index_.size()))
294
+ {
295
+ throw qdb::invalid_argument_exception{
296
+ "every data array should be exactly the same length as the index array"};
297
+ }
298
+ }
299
+
300
+ xs_.push_back(value_type{table, index_, column_data});
301
+ }
302
+
303
+ inline bool empty() const noexcept
304
+ {
305
+ return xs_.empty();
306
+ }
307
+
308
+ inline value_type const & front() const noexcept
309
+ {
310
+ assert(empty() == false);
311
+
312
+ return xs_.front();
313
+ }
314
+
315
+ inline value_type const & back() const noexcept
316
+ {
317
+ assert(empty() == false);
318
+
319
+ return xs_.back();
320
+ }
321
+
322
+ std::vector<value_type> xs() const
323
+ {
324
+ return xs_;
325
+ }
326
+
327
+ private:
328
+ std::vector<value_type> xs_;
329
+ };
330
+
331
+ /**
332
+ * Wraps an index to staged tables. Provides functionality for indexing writer
333
+ * data into staged tables as well.
334
+ */
335
+ class staged_tables
336
+ {
337
+ public:
338
+ using key_type = std::string;
339
+ using value_type = staged_table;
340
+ using container_type = std::map<key_type, staged_table>;
341
+ using iterator = container_type::iterator;
342
+ using const_iterator = container_type::const_iterator;
343
+
344
+ public:
345
+ /**
346
+ * Free function that takes indexes all writer data into a staged_table object.
347
+ */
348
+ static staged_tables index(writer_data const & data);
349
+
350
+ public:
351
+ inline container_type::size_type size() const
352
+ {
353
+ return idx_.size();
354
+ }
355
+
356
+ inline bool empty() const
357
+ {
358
+ return idx_.empty();
359
+ }
360
+
361
+ inline iterator begin()
362
+ {
363
+ return idx_.begin();
364
+ }
365
+
366
+ inline iterator end()
367
+ {
368
+ return idx_.end();
369
+ }
370
+
371
+ inline const_iterator begin() const
372
+ {
373
+ return idx_.cbegin();
374
+ }
375
+
376
+ inline const_iterator cend() const
377
+ {
378
+ return idx_.cend();
379
+ }
380
+
381
+ /**
382
+ * Returns the first staged table. Useful in scenarios where we are only working with a single
383
+ * table.
384
+ */
385
+ inline value_type & first()
386
+ {
387
+ assert(size() == 1);
388
+
389
+ return idx_.begin()->second;
390
+ }
391
+
392
+ /**
393
+ * Returns the first staged table. Useful in scenarios where we are only working with a single
394
+ * table.
395
+ */
396
+ inline value_type const & first() const
397
+ {
398
+ assert(size() == 1);
399
+
400
+ return idx_.cbegin()->second;
401
+ }
402
+
403
+ /**
404
+ * Retrieves table by table object, or creates a new empty entry.
405
+ */
406
+ inline value_type & get_or_create(qdb::table const & table)
407
+ {
408
+ std::string const & table_name = table.get_name();
409
+ auto pos = idx_.lower_bound(table_name);
410
+
411
+ if (pos == idx_.end() || pos->first != table_name) [[unlikely]]
412
+ {
413
+ // The table was not yet found
414
+ pos = idx_.emplace_hint(pos, table_name, table);
415
+ assert(pos->second.empty());
416
+ }
417
+
418
+ assert(pos != idx_.end());
419
+ assert(pos->first == table_name);
420
+
421
+ return pos->second;
422
+ }
423
+
424
+ private:
425
+ container_type idx_;
426
+ };
427
+
428
+ struct batch_push_flags
429
+ {
430
+ static constexpr char const * kw_write_through = "write_through";
431
+ static constexpr bool default_write_through = true;
432
+
433
+ /**
434
+ * Ensures all options are always explicitly set, according to the defaults above.
435
+ */
436
+ static py::kwargs ensure(py::kwargs kwargs);
437
+
438
+ /**
439
+ * Returns the push mode, throws error if push mode is not set.
440
+ */
441
+ static qdb_uint_t from_kwargs(py::kwargs const & kwargs);
442
+ };
443
+
444
+ struct batch_push_mode
445
+ {
446
+ static constexpr char const * kw_push_mode = "push_mode";
447
+ static constexpr qdb_exp_batch_push_mode_t default_push_mode = qdb_exp_batch_push_transactional;
448
+
449
+ /**
450
+ * Ensures push mode is always set in the kwargs, and uses the `default_push_mode` if not found.
451
+ */
452
+ static py::kwargs ensure(py::kwargs kwargs);
453
+
454
+ /**
455
+ * Sets the push mode to a certain value.
456
+ */
457
+ static py::kwargs set(py::kwargs kwargs, qdb_exp_batch_push_mode_t push_mode);
458
+
459
+ /**
460
+ * Returns the push mode, throws error if push mode is not set.
461
+ */
462
+ static qdb_exp_batch_push_mode_t from_kwargs(py::kwargs const & kwargs);
463
+ };
464
+
465
+ struct batch_options
466
+ {
467
+ static qdb_exp_batch_options_t from_kwargs(py::kwargs const & kwargs);
468
+ };
469
+
470
+ struct batch_truncate_ranges
471
+ {
472
+
473
+ static constexpr char const * kw_range = "range";
474
+
475
+ /**
476
+ * Ensures a range is set. If not set, derives it from the range of the provided
477
+ * tables.
478
+ */
479
+ static py::kwargs ensure(py::kwargs kwargs, detail::staged_tables const & idx)
480
+ {
481
+ if (kwargs.contains(kw_range) == false)
482
+ {
483
+ if (idx.size() != 1) [[unlikely]]
484
+ {
485
+ throw qdb::invalid_argument_exception{"Writer push truncate only supports a single "
486
+ "table unless an explicit range is provided: "
487
+ "you provided more than one table without "
488
+ " an explicit range."};
489
+ }
490
+
491
+ detail::staged_table const & staged_table = idx.first();
492
+
493
+ auto range_ = staged_table.time_range();
494
+
495
+ py::print("1 before");
496
+ py::tuple x = convert::value<qdb_ts_range_t, py::tuple>(range_);
497
+ py::print("2 middle");
498
+ kwargs[kw_range] = x;
499
+ py::print("3 after");
500
+ }
501
+
502
+ return kwargs;
503
+ }
504
+
505
+ /**
506
+ * Returns the truncate ranges based on the kwargs.
507
+ */
508
+ static std::vector<qdb_ts_range_t> from_kwargs(py::kwargs kwargs)
509
+ {
510
+ // This function *could* be invoked, but doesn't make sense to be invoked, when we're not
511
+ // doing a push truncate.
512
+ //
513
+ // Strictly speaking this assertion is not necessary, but it doesn't hurt to have it.
514
+ assert(qdb::detail::batch_push_mode::from_kwargs(kwargs) == qdb_exp_batch_push_truncate);
515
+
516
+ // We also always assume a range is provided, i.e. `ensure` is called beforehand.
517
+ assert(kwargs.contains(detail::batch_truncate_ranges::kw_range) == true);
518
+ std::vector<qdb_ts_range_t> ret{};
519
+
520
+ py::tuple range_ = py::cast<py::tuple>(kwargs[detail::batch_truncate_ranges::kw_range]);
521
+ ret.push_back(convert::value<py::tuple, qdb_ts_range_t>(range_));
522
+
523
+ return ret;
524
+ }
525
+ };
526
+
527
+ /**
528
+ * Default batch push strategy, just invokes the regular function and returns the result.
529
+ */
530
+ struct default_writer_push_strategy
531
+ {
532
+
533
+ static default_writer_push_strategy from_kwargs(py::kwargs const & /* kwargs */)
534
+ {
535
+ return {};
536
+ }
537
+
538
+ inline qdb_error_t operator()(qdb_handle_t handle,
539
+ qdb_exp_batch_options_t const * options,
540
+ qdb_exp_batch_push_table_t const * tables,
541
+ qdb_exp_batch_push_table_schema_t const ** table_schemas,
542
+ qdb_size_t table_count) const noexcept
543
+ {
544
+ return qdb_exp_batch_push_with_options(handle, options, tables, table_schemas, table_count);
545
+ }
546
+ };
547
+
548
+ static_assert(concepts::writer_push_strategy<default_writer_push_strategy>);
549
+
550
+ } // namespace qdb::detail
quasardb/error.hpp CHANGED
@@ -89,6 +89,31 @@ public:
89
89
  {}
90
90
  };
91
91
 
92
+ class out_of_bounds_exception : public exception
93
+ {
94
+ public:
95
+ out_of_bounds_exception() noexcept
96
+ : exception(qdb_e_out_of_bounds, std::string("The requested operation is out of bounds"))
97
+ {}
98
+
99
+ out_of_bounds_exception(std::string const & what) noexcept
100
+ : exception(qdb_e_out_of_bounds, what)
101
+ {}
102
+ };
103
+
104
+ class uninitialized_exception : public exception
105
+ {
106
+ public:
107
+ uninitialized_exception() noexcept
108
+ : exception(qdb_e_uninitialized,
109
+ std::string("The requested operation is unavailable because the resource is uninitialized"))
110
+ {}
111
+
112
+ uninitialized_exception(std::string const & what) noexcept
113
+ : exception(qdb_e_uninitialized, what)
114
+ {}
115
+ };
116
+
92
117
  class incompatible_type_exception : public exception
93
118
  {
94
119
  public:
@@ -173,6 +198,33 @@ public:
173
198
  {}
174
199
  };
175
200
 
201
+ class try_again_exception : public exception
202
+ {
203
+ public:
204
+ try_again_exception() noexcept
205
+ : exception(qdb_e_try_again,
206
+ std::string("The operation could not be completed at this time, please try again"))
207
+ {}
208
+
209
+ try_again_exception(std::string const & what) noexcept
210
+ : exception(qdb_e_try_again, what)
211
+ {}
212
+ };
213
+
214
+ class async_pipeline_full_exception : public exception
215
+ {
216
+ public:
217
+ async_pipeline_full_exception() noexcept
218
+ : exception(qdb_e_async_pipe_full,
219
+ std::string("The async pipelines are currently full, please try again later or slow down "
220
+ "your ingestion speed."))
221
+ {}
222
+
223
+ async_pipeline_full_exception(std::string const & what) noexcept
224
+ : exception(qdb_e_async_pipe_full, what)
225
+ {}
226
+ };
227
+
176
228
  class invalid_datetime_exception : public exception
177
229
  {
178
230
  public:
@@ -225,7 +277,7 @@ inline void qdb_throw_if_error(
225
277
  qdb_error_t err_;
226
278
  qdb_get_last_error(h, &err_, &msg_);
227
279
 
228
- if (err_ != err)
280
+ if (err_ != err) [[unlikely]]
229
281
  {
230
282
  // Error context returned is not the same, which means this thread already made
231
283
  // another call to the QDB API, or the QDB API itself
@@ -235,6 +287,16 @@ inline void qdb_throw_if_error(
235
287
  case qdb_e_not_connected:
236
288
  case qdb_e_invalid_handle:
237
289
  throw qdb::invalid_handle_exception{};
290
+
291
+ case qdb_e_invalid_argument:
292
+ throw qdb::invalid_argument_exception{};
293
+
294
+ case qdb_e_try_again:
295
+ throw qdb::try_again_exception{};
296
+
297
+ case qdb_e_async_pipe_full:
298
+ throw qdb::async_pipeline_full_exception{};
299
+
238
300
  default:
239
301
  throw qdb::exception{err, qdb_error(err)};
240
302
  }
@@ -252,6 +314,9 @@ inline void qdb_throw_if_error(
252
314
  case qdb_e_invalid_query:
253
315
  throw qdb::invalid_query_exception{msg_data_};
254
316
 
317
+ case qdb_e_out_of_bounds:
318
+ throw qdb::out_of_bounds_exception{msg_data_};
319
+
255
320
  case qdb_e_not_connected:
256
321
  case qdb_e_invalid_handle:
257
322
  throw qdb::invalid_handle_exception{};
@@ -277,6 +342,12 @@ inline void qdb_throw_if_error(
277
342
  case qdb_e_invalid_argument:
278
343
  throw qdb::invalid_argument_exception{msg_data_};
279
344
 
345
+ case qdb_e_try_again:
346
+ throw qdb::try_again_exception{msg_data_};
347
+
348
+ case qdb_e_async_pipe_full:
349
+ throw qdb::async_pipeline_full_exception{msg_data_};
350
+
280
351
  default:
281
352
  throw qdb::exception{err_, msg_data_};
282
353
  };
@@ -306,6 +377,7 @@ static inline void register_errors(Module & m)
306
377
  py::register_exception<qdb::alias_already_exists_exception>(
307
378
  m, "AliasAlreadyExistsError", base_class);
308
379
  py::register_exception<qdb::alias_not_found_exception>(m, "AliasNotFoundError", base_class);
380
+ py::register_exception<qdb::uninitialized_exception>(m, "UninitializedError", base_class);
309
381
  py::register_exception<qdb::invalid_datetime_exception>(m, "InvalidDatetimeError", base_class);
310
382
  py::register_exception<qdb::incompatible_type_exception>(m, "IncompatibleTypeError", base_class);
311
383
  py::register_exception<qdb::not_implemented_exception>(m, "NotImplementedError", base_class);
@@ -313,6 +385,9 @@ static inline void register_errors(Module & m)
313
385
  py::register_exception<qdb::invalid_argument_exception>(m, "InvalidArgumentError", base_class);
314
386
  py::register_exception<qdb::invalid_query_exception>(m, "InvalidQueryError", base_class);
315
387
  py::register_exception<qdb::invalid_handle_exception>(m, "InvalidHandleError", base_class);
388
+ py::register_exception<qdb::try_again_exception>(m, "TryAgainError", base_class);
389
+ py::register_exception<qdb::async_pipeline_full_exception>(m, "AsyncPipelineFullError", base_class);
390
+ py::register_exception<qdb::out_of_bounds_exception>(m, "OutOfBoundsError", base_class);
316
391
  }
317
392
 
318
393
  } // namespace qdb
quasardb/libqdb_api.dylib CHANGED
Binary file
quasardb/masked_array.hpp CHANGED
@@ -318,7 +318,11 @@ public:
318
318
  ~masked_array()
319
319
  {}
320
320
 
321
- py::handle cast(py::return_value_policy /* policy */) const
321
+ /**
322
+ * Cast this masked array to an actual numpy.ma.MaskedArray. This invokes
323
+ * a python function and can be slow.
324
+ */
325
+ py::handle cast(py::return_value_policy policy) const
322
326
  {
323
327
  py::module numpy_ma = py::module::import("numpy.ma");
324
328
  py::object init = numpy_ma.attr("masked_array");
@@ -410,6 +414,9 @@ public:
410
414
  return arr_.dtype();
411
415
  }
412
416
 
417
+ /**
418
+ * Returns size of array. Includes "masked" items, i.e. those that are not visible.
419
+ */
413
420
  inline std::size_t size() const noexcept
414
421
  {
415
422
  assert(arr_.size() == mask_.size());
@@ -640,7 +647,7 @@ public:
640
647
  /**
641
648
  * C++->Python
642
649
  */
643
- static py::handle cast(type && src, return_value_policy policy, handle /* parent */)
650
+ static py::object cast(type && src, return_value_policy policy, handle /* parent */)
644
651
  {
645
652
  return src.cast(policy);
646
653
  }