quasardb 3.14.2.dev1__cp39-cp39-macosx_11_0_arm64.whl → 3.14.2.dev4__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 (95) hide show
  1. quasardb/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  2. quasardb/Makefile +20 -20
  3. quasardb/__init__.py +33 -4
  4. quasardb/cmake_install.cmake +7 -1
  5. quasardb/date/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  6. quasardb/date/CMakeFiles/Export/a52b05f964b070ee926bcad51d3288af/dateTargets.cmake +13 -13
  7. quasardb/date/Makefile +20 -20
  8. quasardb/date/cmake_install.cmake +7 -1
  9. quasardb/date/dateConfigVersion.cmake +9 -2
  10. quasardb/date/dateTargets.cmake +4 -8
  11. quasardb/libqdb_api.dylib +0 -0
  12. quasardb/numpy/__init__.py +58 -10
  13. quasardb/pandas/__init__.py +58 -102
  14. quasardb/pybind11/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  15. quasardb/pybind11/Makefile +20 -20
  16. quasardb/pybind11/cmake_install.cmake +7 -1
  17. quasardb/quasardb.cpython-39-darwin.so +0 -0
  18. quasardb/range-v3/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  19. quasardb/range-v3/CMakeFiles/Export/d94ef200eca10a819b5858b33e808f5b/range-v3-targets.cmake +13 -13
  20. quasardb/range-v3/CMakeFiles/range.v3.headers.dir/DependInfo.cmake +6 -2
  21. quasardb/range-v3/CMakeFiles/range.v3.headers.dir/build.make +7 -4
  22. quasardb/range-v3/Makefile +20 -20
  23. quasardb/range-v3/cmake_install.cmake +19 -1
  24. quasardb/range-v3/range-v3-config-version.cmake +9 -2
  25. quasardb/range-v3/range-v3-config.cmake +4 -8
  26. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev4.dist-info}/METADATA +15 -10
  27. quasardb-3.14.2.dev4.dist-info/RECORD +45 -0
  28. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev4.dist-info}/WHEEL +1 -1
  29. quasardb/CMakeLists.txt +0 -510
  30. quasardb/batch_column.hpp +0 -80
  31. quasardb/batch_inserter.hpp +0 -248
  32. quasardb/blob.hpp +0 -150
  33. quasardb/cluster.cpp +0 -89
  34. quasardb/cluster.hpp +0 -551
  35. quasardb/concepts.hpp +0 -278
  36. quasardb/continuous.cpp +0 -149
  37. quasardb/continuous.hpp +0 -106
  38. quasardb/convert/array.hpp +0 -282
  39. quasardb/convert/point.hpp +0 -330
  40. quasardb/convert/range.hpp +0 -282
  41. quasardb/convert/unicode.hpp +0 -598
  42. quasardb/convert/util.hpp +0 -22
  43. quasardb/convert/value.hpp +0 -711
  44. quasardb/convert.hpp +0 -38
  45. quasardb/detail/qdb_resource.hpp +0 -129
  46. quasardb/detail/ts_column.hpp +0 -224
  47. quasardb/direct_blob.hpp +0 -108
  48. quasardb/direct_handle.hpp +0 -83
  49. quasardb/direct_integer.hpp +0 -94
  50. quasardb/dispatch.hpp +0 -157
  51. quasardb/double.hpp +0 -87
  52. quasardb/entry.hpp +0 -273
  53. quasardb/error.hpp +0 -318
  54. quasardb/handle.cpp +0 -29
  55. quasardb/handle.hpp +0 -98
  56. quasardb/integer.hpp +0 -88
  57. quasardb/logger.cpp +0 -106
  58. quasardb/logger.hpp +0 -228
  59. quasardb/masked_array.hpp +0 -651
  60. quasardb/metrics.cpp +0 -103
  61. quasardb/metrics.hpp +0 -112
  62. quasardb/module.cpp +0 -76
  63. quasardb/module.hpp +0 -24
  64. quasardb/node.hpp +0 -123
  65. quasardb/numpy.cpp +0 -6
  66. quasardb/numpy.hpp +0 -489
  67. quasardb/object_tracker.hpp +0 -283
  68. quasardb/options.hpp +0 -244
  69. quasardb/perf.hpp +0 -336
  70. quasardb/pytypes.hpp +0 -221
  71. quasardb/query.cpp +0 -420
  72. quasardb/query.hpp +0 -92
  73. quasardb/reader/ts_row.hpp +0 -281
  74. quasardb/reader/ts_value.hpp +0 -245
  75. quasardb/remove_cvref.hpp +0 -31
  76. quasardb/string.hpp +0 -160
  77. quasardb/table.cpp +0 -289
  78. quasardb/table.hpp +0 -325
  79. quasardb/table_reader.hpp +0 -220
  80. quasardb/tag.hpp +0 -77
  81. quasardb/timestamp.hpp +0 -97
  82. quasardb/traits.hpp +0 -619
  83. quasardb/ts_iterator.hpp +0 -193
  84. quasardb/utils/blob_deque.hpp +0 -96
  85. quasardb/utils/ostream.hpp +0 -17
  86. quasardb/utils/permutation.hpp +0 -50
  87. quasardb/utils/stable_sort.hpp +0 -25
  88. quasardb/utils/unzip_view.hpp +0 -89
  89. quasardb/utils.cpp +0 -28
  90. quasardb/utils.hpp +0 -174
  91. quasardb/writer.cpp +0 -534
  92. quasardb/writer.hpp +0 -396
  93. quasardb-3.14.2.dev1.dist-info/RECORD +0 -109
  94. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev4.dist-info}/LICENSE.md +0 -0
  95. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev4.dist-info}/top_level.txt +0 -0
quasardb/writer.cpp DELETED
@@ -1,534 +0,0 @@
1
- #include "writer.hpp"
2
- #include "concepts.hpp"
3
- #include "dispatch.hpp"
4
- #include "metrics.hpp"
5
- #include "numpy.hpp"
6
- #include "traits.hpp"
7
- #include "convert/array.hpp"
8
-
9
- namespace qdb::detail
10
- {
11
-
12
- ////////////////////////////////////////////////////////////////////////////////
13
- //
14
- // COLUMN SETTERS
15
- //
16
- // Effectively we delegate these to the appropriate convert:: function. Add an
17
- // additional converter here if you're adding additional column types, *or* wish
18
- // to support additional dtypes for existing column types (e.g. to also support
19
- // py::str objects for string columns).
20
- //
21
- ///////////////////
22
-
23
- template <qdb_ts_column_type_t ColumnType, concepts::dtype Dtype>
24
- struct column_setter;
25
-
26
- #define COLUMN_SETTER_DECL(CTYPE, DTYPE, VALUE_TYPE) \
27
- template <> \
28
- struct column_setter<CTYPE, DTYPE> \
29
- { \
30
- inline void operator()(qdb::masked_array const & xs, std::vector<VALUE_TYPE> & dst) \
31
- { \
32
- convert::masked_array<DTYPE, VALUE_TYPE>(xs, dst); \
33
- } \
34
- };
35
-
36
- // np.dtype('int64') -> qdb_int_t column
37
- COLUMN_SETTER_DECL(qdb_ts_column_int64, traits::int64_dtype, qdb_int_t);
38
-
39
- // np.dtype('int32') -> qdb_int_t column
40
- COLUMN_SETTER_DECL(qdb_ts_column_int64, traits::int32_dtype, qdb_int_t);
41
- // np.dtype('int16') -> qdb_int_t column
42
- COLUMN_SETTER_DECL(qdb_ts_column_int64, traits::int16_dtype, qdb_int_t);
43
-
44
- // np.dtype('float64') -> double column
45
- COLUMN_SETTER_DECL(qdb_ts_column_double, traits::float64_dtype, double);
46
- // np.dtype('float32') -> double column
47
- COLUMN_SETTER_DECL(qdb_ts_column_double, traits::float32_dtype, double);
48
-
49
- // np.dtype('datetime64[ns]') -> qdb_timespec_t column
50
- COLUMN_SETTER_DECL(qdb_ts_column_timestamp, traits::datetime64_ns_dtype, qdb_timespec_t);
51
-
52
- // np.dtype('unicode') -> qdb_string_T column
53
- COLUMN_SETTER_DECL(qdb_ts_column_string, traits::unicode_dtype, qdb_string_t);
54
-
55
- // np.dtype('object') -> qdb_blob_t column
56
- COLUMN_SETTER_DECL(qdb_ts_column_blob, traits::pyobject_dtype, qdb_blob_t);
57
-
58
- // np.dtype('S') -> qdb_blob_t column
59
- COLUMN_SETTER_DECL(qdb_ts_column_blob, traits::bytestring_dtype, qdb_blob_t);
60
-
61
- #undef COLUMN_SETTER_DECL
62
-
63
- template <qdb_ts_column_type_t ColumnType>
64
- inline void set_column_dispatch(
65
- std::size_t index, qdb::masked_array const & xs, std::vector<any_column> & columns)
66
- {
67
- dispatch::by_dtype<detail::column_setter, ColumnType>(
68
- xs.dtype(), xs, detail::access_column<ColumnType>(columns, index));
69
- };
70
-
71
- template <qdb_ts_column_type_t T, typename AnyColumnType>
72
- inline void prepare_column_of_type(AnyColumnType const & in, qdb_exp_batch_push_column_t & out);
73
-
74
- template <>
75
- inline void prepare_column_of_type<qdb_ts_column_int64>(
76
- int64_column const & in, qdb_exp_batch_push_column_t & out)
77
- {
78
- out.data.ints = in.data();
79
- };
80
-
81
- template <>
82
- inline void prepare_column_of_type<qdb_ts_column_double>(
83
- double_column const & in, qdb_exp_batch_push_column_t & out)
84
- {
85
- out.data.doubles = in.data();
86
- };
87
-
88
- template <>
89
- inline void prepare_column_of_type<qdb_ts_column_timestamp>(
90
- timestamp_column const & in, qdb_exp_batch_push_column_t & out)
91
- {
92
- out.data.timestamps = in.data();
93
- };
94
-
95
- template <>
96
- inline void prepare_column_of_type<qdb_ts_column_blob>(
97
- blob_column const & in, qdb_exp_batch_push_column_t & out)
98
- {
99
- out.data.blobs = in.data();
100
- };
101
-
102
- template <>
103
- inline void prepare_column_of_type<qdb_ts_column_string>(
104
- string_column const & in, qdb_exp_batch_push_column_t & out)
105
- {
106
- out.data.strings = in.data();
107
- };
108
-
109
- template <>
110
- inline void prepare_column_of_type<qdb_ts_column_symbol>(
111
- string_column const & in, qdb_exp_batch_push_column_t & out)
112
- {
113
- prepare_column_of_type<qdb_ts_column_string>(in, out);
114
- };
115
-
116
- template <qdb_ts_column_type_t ctype>
117
- struct fill_column_dispatch
118
- {
119
- using value_type = typename traits::qdb_column<ctype>::value_type;
120
- using column_type = typename column_of_type<ctype>::value_type;
121
-
122
- inline qdb_exp_batch_push_column_t operator()(any_column const & input)
123
- {
124
- qdb_exp_batch_push_column_t ret{};
125
-
126
- ret.name = traits::null_value<qdb_string_t>();
127
- ret.data_type = ctype;
128
-
129
- // We swap the pointer inside the `qdb_exp_batch_push_column__t` with the pointer
130
- // to the data as it is inside the `any_column`.
131
- //
132
- // This works, because all these `any_column`'s lifecycle is scoped to the
133
- // writer class, and as such will survive for a long time.
134
- prepare_column_of_type<ctype>(std::get<column_type>(input), ret);
135
-
136
- return ret;
137
- };
138
- };
139
-
140
- // Handle symbols as if they are strings. Data should never be provided using a "symbol" type
141
- // anyway, but it's good to handle
142
- template <>
143
- struct fill_column_dispatch<qdb_ts_column_symbol> : fill_column_dispatch<qdb_ts_column_string>
144
- {};
145
-
146
- void staged_table::set_index(py::array const & xs)
147
- {
148
- convert::array<traits::datetime64_ns_dtype, qdb_timespec_t>(
149
- numpy::array::ensure<traits::datetime64_ns_dtype>(xs), _index);
150
- }
151
-
152
- void staged_table::set_blob_column(std::size_t index, const masked_array & xs)
153
- {
154
- detail::set_column_dispatch<qdb_ts_column_blob>(index, xs, _columns);
155
- }
156
-
157
- void staged_table::set_string_column(std::size_t index, const masked_array & xs)
158
- {
159
- detail::set_column_dispatch<qdb_ts_column_string>(index, xs, _columns);
160
- }
161
-
162
- void staged_table::set_int64_column(std::size_t index, const masked_array_t<traits::int64_dtype> & xs)
163
- {
164
- detail::set_column_dispatch<qdb_ts_column_int64>(index, xs, _columns);
165
- }
166
-
167
- void staged_table::set_double_column(
168
- std::size_t index, const masked_array_t<traits::float64_dtype> & xs)
169
- {
170
- detail::set_column_dispatch<qdb_ts_column_double>(index, xs, _columns);
171
- }
172
-
173
- void staged_table::set_timestamp_column(
174
- std::size_t index, const masked_array_t<traits::datetime64_ns_dtype> & xs)
175
- {
176
- detail::set_column_dispatch<qdb_ts_column_timestamp>(index, xs, _columns);
177
- }
178
-
179
- std::vector<qdb_exp_batch_push_column_t> const & staged_table::prepare_columns()
180
- {
181
- _columns_data.clear();
182
- _columns_data.reserve(_columns.size());
183
-
184
- for (size_t index = 0; index < _columns.size(); ++index)
185
- {
186
- qdb_exp_batch_push_column_t column = dispatch::by_column_type<detail::fill_column_dispatch>(
187
- _column_infos[index].type, _columns.at(index));
188
-
189
- assert(traits::is_null(column.name));
190
-
191
- // XXX(leon): reuses lifecycle of _column_infos[index], which *should* be fine,
192
- // but ensuring we take a reference is super important here!
193
- std::string const & column_name = _column_infos[index].name;
194
- column.name = qdb_string_t{column_name.data(), column_name.size()};
195
-
196
- #ifndef NDEBUG
197
- // Symbol column is actually string data
198
- qdb_ts_column_type_t expected_data_type =
199
- (_column_infos[index].type == qdb_ts_column_symbol ? qdb_ts_column_string
200
- : _column_infos[index].type);
201
- assert(column.data_type == expected_data_type);
202
- #endif
203
-
204
- _columns_data.push_back(column);
205
- }
206
-
207
- return _columns_data;
208
- }
209
-
210
- void staged_table::prepare_table_data(qdb_exp_batch_push_table_data_t & table_data)
211
- {
212
- table_data.row_count = _index.size();
213
- table_data.timestamps = _index.data();
214
-
215
- const auto & columns = prepare_columns();
216
- table_data.columns = columns.data();
217
- table_data.column_count = columns.size();
218
- }
219
-
220
- void staged_table::prepare_batch(qdb_exp_batch_push_mode_t mode,
221
- detail::deduplicate_options const & deduplicate_options,
222
- qdb_ts_range_t * ranges,
223
- qdb_exp_batch_push_table_t & batch)
224
- {
225
- batch.name = qdb_string_t{_table_name.data(), _table_name.size()};
226
-
227
- prepare_table_data(batch.data);
228
- if (mode == qdb_exp_batch_push_truncate)
229
- {
230
- batch.truncate_ranges = ranges;
231
- batch.truncate_range_count = ranges == nullptr ? 0u : 1u;
232
- }
233
-
234
- // Zero-initialize these
235
- batch.where_duplicate = nullptr;
236
- batch.where_duplicate_count = 0;
237
- batch.options = qdb_exp_batch_option_standard;
238
-
239
- enum detail::deduplication_mode_t mode_ = deduplicate_options.mode_;
240
-
241
- std::visit([&mode_, &batch](auto const & columns) { _set_push_options(mode_, columns, batch); },
242
- deduplicate_options.columns_);
243
- }
244
-
245
- }; // namespace qdb::detail
246
-
247
- namespace qdb
248
- {
249
-
250
- void writer::data::append(
251
- qdb::table const & table, py::handle const & index, py::list const & column_data)
252
- {
253
- py::array index_ = numpy::array::ensure<traits::datetime64_ns_dtype>(index);
254
-
255
- /**
256
- * Additional check that all the data is actually of the same length, and data has been
257
- * provided for each and every column.
258
- */
259
- if (column_data.size() != table.list_columns().size())
260
- {
261
- throw qdb::invalid_argument_exception{"data must be provided for every table column"};
262
- }
263
-
264
- for (py::handle const & data : column_data)
265
- {
266
- qdb::masked_array data_ = data.cast<qdb::masked_array>();
267
- if (data_.size() != static_cast<std::size_t>(index_.size()))
268
- {
269
- throw qdb::invalid_argument_exception{
270
- "every data array should be exactly the same length as the index array"};
271
- }
272
- }
273
-
274
- xs_.push_back(value_type{table, index_, column_data});
275
- }
276
-
277
- void writer::push(writer::data const & data, py::kwargs args)
278
- {
279
- qdb::object_tracker::scoped_capture capture{_object_tracker};
280
- staged_tables_t staged_tables = _stage_tables(data);
281
-
282
- _push_impl(staged_tables, qdb_exp_batch_push_transactional, _deduplicate_from_args(args));
283
- }
284
-
285
- void writer::push_async(writer::data const & data, py::kwargs args)
286
- {
287
- qdb::object_tracker::scoped_capture capture{_object_tracker};
288
- staged_tables_t staged_tables = _stage_tables(data);
289
-
290
- _push_impl(staged_tables, qdb_exp_batch_push_async, _deduplicate_from_args(args));
291
- }
292
-
293
- void writer::push_fast(writer::data const & data, py::kwargs args)
294
- {
295
- qdb::object_tracker::scoped_capture capture{_object_tracker};
296
- staged_tables_t staged_tables = _stage_tables(data);
297
-
298
- _push_impl(staged_tables, qdb_exp_batch_push_fast, _deduplicate_from_args(args));
299
- }
300
-
301
- void writer::push_truncate(writer::data const & data, py::kwargs args)
302
- {
303
- qdb::object_tracker::scoped_capture capture{_object_tracker};
304
- staged_tables_t staged_tables = _stage_tables(data);
305
-
306
- auto deduplicate = _deduplicate_from_args(args);
307
-
308
- // Sanity check, this should be checked for in the python-side of things as well,
309
- // but people can invoke this manually if they want.
310
- if (!std::holds_alternative<bool>(deduplicate.columns_)
311
- || std::get<bool>(deduplicate.columns_) != false) [[unlikely]]
312
- {
313
- throw qdb::invalid_argument_exception{"Cannot set `deduplicate` for push_truncate."};
314
- };
315
-
316
- // As we are actively removing data, let's add an additional check to ensure the user
317
- // doesn't accidentally truncate his whole database without inserting anything.
318
- if (data.empty()) [[unlikely]]
319
- {
320
- throw qdb::invalid_argument_exception{"Writer is empty: you did not provide any rows to push."};
321
- }
322
-
323
- qdb_ts_range_t tr;
324
-
325
- if (args.contains("range"))
326
- {
327
- tr = convert::value<py::tuple, qdb_ts_range_t>(py::cast<py::tuple>(args["range"]));
328
- }
329
- else
330
- {
331
- // TODO(leon): support multiple tables for push truncate
332
- if (staged_tables.size() != 1) [[unlikely]]
333
- {
334
- throw qdb::invalid_argument_exception{
335
- "Writer push truncate only supports a single "
336
- "table unless an explicit range is provided: you provided more than one table without"
337
- " an explicit range."};
338
- }
339
-
340
- detail::staged_table const & staged_table = staged_tables.cbegin()->second;
341
- tr = staged_table.time_range();
342
- }
343
-
344
- _push_impl(staged_tables, qdb_exp_batch_push_truncate, deduplicate, &tr);
345
- }
346
-
347
- detail::deduplicate_options writer::_deduplicate_from_args(py::kwargs args)
348
- {
349
- if (!args.contains("deduplicate") || !args.contains("deduplication_mode"))
350
- {
351
- return {};
352
- }
353
-
354
- std::string deduplication_mode = args["deduplication_mode"].cast<std::string>();
355
-
356
- enum detail::deduplication_mode_t deduplication_mode_;
357
- if (deduplication_mode == "drop")
358
- {
359
- deduplication_mode_ = detail::deduplication_mode_drop;
360
- }
361
- else if (deduplication_mode == "upsert")
362
- {
363
- deduplication_mode_ = detail::deduplication_mode_upsert;
364
- }
365
- else
366
- {
367
- std::string error_msg = "Invalid argument provided for `deduplication_mode`: expected "
368
- "'drop' or 'upsert', got: ";
369
- error_msg += deduplication_mode;
370
-
371
- throw qdb::invalid_argument_exception{error_msg};
372
- }
373
-
374
- auto deduplicate = args["deduplicate"];
375
-
376
- if (py::isinstance<py::list>(deduplicate))
377
- {
378
- return detail::deduplicate_options{
379
- deduplication_mode_, py::cast<std::vector<std::string>>(deduplicate)};
380
- }
381
- else if (py::isinstance<py::bool_>(deduplicate))
382
- {
383
- return detail::deduplicate_options{deduplication_mode_, py::cast<bool>(deduplicate)};
384
- }
385
-
386
- std::string error_msg = "Invalid argument provided for `deduplicate`: expected bool, list or "
387
- "str('$timestamp'), got: ";
388
- error_msg += deduplicate.cast<py::str>();
389
-
390
- throw qdb::invalid_argument_exception{error_msg};
391
- };
392
-
393
- /* static */ writer::staged_tables_t writer::_stage_tables(writer::data const & data)
394
- {
395
- staged_tables_t staged_tables;
396
-
397
- for (writer::data::value_type const & table_data : data.xs())
398
- {
399
- qdb::table table = table_data.table;
400
- py::array index = table_data.index;
401
- py::list column_data = table_data.column_data;
402
-
403
- auto column_infos = table.list_columns();
404
-
405
- if (column_infos.size() != column_data.size()) [[unlikely]]
406
- {
407
- throw qdb::invalid_argument_exception{
408
- "data must be provided for every column of the table."};
409
- }
410
-
411
- detail::staged_table & staged_table = writer::_get_staged_table(table, staged_tables);
412
-
413
- staged_table.set_index(index);
414
-
415
- for (std::size_t i = 0; i < column_data.size(); ++i)
416
- {
417
- py::object x = column_data[i];
418
-
419
- if (!x.is_none()) [[likely]]
420
- {
421
- switch (column_infos.at(i).type)
422
- {
423
- case qdb_ts_column_double:
424
- staged_table.set_double_column(
425
- i, x.cast<qdb::masked_array_t<traits::float64_dtype>>());
426
- break;
427
- case qdb_ts_column_blob:
428
- staged_table.set_blob_column(i, x.cast<qdb::masked_array>());
429
- break;
430
- case qdb_ts_column_int64:
431
- staged_table.set_int64_column(
432
- i, x.cast<qdb::masked_array_t<traits::int64_dtype>>());
433
- break;
434
- case qdb_ts_column_timestamp:
435
- staged_table.set_timestamp_column(
436
- i, x.cast<qdb::masked_array_t<traits::datetime64_ns_dtype>>());
437
- break;
438
- case qdb_ts_column_string:
439
- /* FALLTHROUGH */
440
- case qdb_ts_column_symbol:
441
- staged_table.set_string_column(i, x.cast<qdb::masked_array>());
442
- break;
443
- case qdb_ts_column_uninitialized:
444
- // Likely a corruption
445
- throw qdb::invalid_argument_exception{"Uninitialized column."};
446
-
447
- break;
448
- // Likely a corruption
449
- default:
450
- throw qdb::invalid_argument_exception{"Unrecognized column type."};
451
- }
452
- }
453
- }
454
- }
455
-
456
- return staged_tables;
457
- }
458
-
459
- void writer::_push_impl(writer::staged_tables_t & staged_tables,
460
- qdb_exp_batch_push_mode_t mode,
461
- detail::deduplicate_options deduplicate_options,
462
- qdb_ts_range_t * ranges)
463
- {
464
- _handle->check_open();
465
-
466
- if (staged_tables.empty())
467
- {
468
- throw qdb::invalid_argument_exception{"No data written to batch writer."};
469
- }
470
-
471
- std::vector<qdb_exp_batch_push_table_t> batch;
472
- batch.assign(staged_tables.size(), qdb_exp_batch_push_table_t());
473
-
474
- int cur = 0;
475
- _logger.debug("writer::_push_impl");
476
-
477
- for (auto pos = staged_tables.begin(); pos != staged_tables.end(); ++pos)
478
- {
479
- std::string const & table_name = pos->first;
480
- detail::staged_table & staged_table = pos->second;
481
- auto & batch_table = batch.at(cur++);
482
-
483
- staged_table.prepare_batch(mode, deduplicate_options, ranges, batch_table);
484
-
485
- if (batch_table.data.column_count == 0) [[unlikely]]
486
- {
487
- throw qdb::invalid_argument_exception{
488
- "Writer is empty: you did not provide any columns to push."};
489
- }
490
-
491
- _logger.debug("Pushing %d rows with %d columns in %s", batch_table.data.row_count,
492
- batch_table.data.column_count, table_name);
493
- }
494
-
495
- // Make sure to measure the time it takes to do the actual push
496
- qdb::metrics::scoped_capture capture{"qdb_batch_push"};
497
-
498
- qdb::qdb_throw_if_error(
499
- *_handle, qdb_exp_batch_push(*_handle, mode, batch.data(), nullptr, batch.size()));
500
- }
501
-
502
- void register_writer(py::module_ & m)
503
- {
504
- namespace py = pybind11;
505
-
506
- // Writer data
507
- auto writer_data_c = py::class_<qdb::writer::data>{m, "WriterData"};
508
- writer_data_c.def(py::init())
509
- .def("append", &qdb::writer::data::append, py::arg("table"), py::arg("index"),
510
- py::arg("column_data"), "Append new data")
511
- .def("empty", &qdb::writer::data::empty, "Returns true if underlying data is empty");
512
-
513
- // And the actual pinned writer
514
- auto writer_c = py::class_<qdb::writer>{m, "Writer"};
515
-
516
- // basic interface
517
- writer_c.def(py::init<qdb::handle_ptr>()); //
518
-
519
- writer_c.def_readwrite("_legacy_state", &qdb::writer::legacy_state_);
520
-
521
- // push functions
522
- writer_c
523
- .def("push", &qdb::writer::push, "Regular batch push") //
524
- .def("push_async", &qdb::writer::push_async,
525
- "Asynchronous batch push that buffers data inside the QuasarDB daemon") //
526
- .def("push_fast", &qdb::writer::push_fast,
527
- "Fast, in-place batch push that is efficient when doing lots of small, incremental "
528
- "pushes.") //
529
- .def("push_truncate", &qdb::writer::push_truncate,
530
- "Before inserting data, truncates any existing data. This is useful when you want your "
531
- "insertions to be idempotent, e.g. in "
532
- "case of a retry.");
533
- }
534
- }; // namespace qdb