quasardb 3.14.2.dev1__cp39-cp39-win_amd64.whl → 3.14.2.dev4__cp39-cp39-win_amd64.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 (96) hide show
  1. quasardb/INSTALL.vcxproj +9 -4
  2. quasardb/__init__.py +33 -4
  3. quasardb/cmake_install.cmake +6 -0
  4. quasardb/date/ALL_BUILD.vcxproj +9 -8
  5. quasardb/date/CMakeFiles/Export/df49adab93b9e0c10c64f72458b31971/dateTargets.cmake +13 -13
  6. quasardb/date/CMakeFiles/generate.stamp.depend +4 -4
  7. quasardb/date/INSTALL.vcxproj +9 -4
  8. quasardb/date/cmake_install.cmake +6 -0
  9. quasardb/date/dateConfigVersion.cmake +0 -5
  10. quasardb/date/dateTargets.cmake +4 -8
  11. quasardb/numpy/__init__.py +58 -10
  12. quasardb/pandas/__init__.py +58 -102
  13. quasardb/pybind11/ALL_BUILD.vcxproj +9 -8
  14. quasardb/pybind11/CMakeFiles/generate.stamp.depend +14 -14
  15. quasardb/pybind11/INSTALL.vcxproj +9 -4
  16. quasardb/pybind11/cmake_install.cmake +6 -0
  17. quasardb/qdb_api.dll +0 -0
  18. quasardb/quasardb.cp39-win_amd64.pyd +0 -0
  19. quasardb/range-v3/ALL_BUILD.vcxproj +9 -8
  20. quasardb/range-v3/CMakeFiles/Export/d94ef200eca10a819b5858b33e808f5b/range-v3-targets.cmake +13 -13
  21. quasardb/range-v3/CMakeFiles/generate.stamp.depend +11 -11
  22. quasardb/range-v3/INSTALL.vcxproj +9 -4
  23. quasardb/range-v3/cmake_install.cmake +42 -0
  24. quasardb/range-v3/range-v3-config-version.cmake +0 -5
  25. quasardb/range-v3/range-v3-config.cmake +4 -8
  26. quasardb/range-v3/range.v3.headers.vcxproj +9 -8
  27. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev4.dist-info}/METADATA +15 -10
  28. quasardb-3.14.2.dev4.dist-info/RECORD +54 -0
  29. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev4.dist-info}/WHEEL +1 -1
  30. quasardb/CMakeLists.txt +0 -510
  31. quasardb/batch_column.hpp +0 -80
  32. quasardb/batch_inserter.hpp +0 -248
  33. quasardb/blob.hpp +0 -150
  34. quasardb/cluster.cpp +0 -89
  35. quasardb/cluster.hpp +0 -551
  36. quasardb/concepts.hpp +0 -278
  37. quasardb/continuous.cpp +0 -149
  38. quasardb/continuous.hpp +0 -106
  39. quasardb/convert/array.hpp +0 -282
  40. quasardb/convert/point.hpp +0 -330
  41. quasardb/convert/range.hpp +0 -282
  42. quasardb/convert/unicode.hpp +0 -598
  43. quasardb/convert/util.hpp +0 -22
  44. quasardb/convert/value.hpp +0 -711
  45. quasardb/convert.hpp +0 -38
  46. quasardb/detail/qdb_resource.hpp +0 -129
  47. quasardb/detail/ts_column.hpp +0 -224
  48. quasardb/direct_blob.hpp +0 -108
  49. quasardb/direct_handle.hpp +0 -83
  50. quasardb/direct_integer.hpp +0 -94
  51. quasardb/dispatch.hpp +0 -157
  52. quasardb/double.hpp +0 -87
  53. quasardb/entry.hpp +0 -273
  54. quasardb/error.hpp +0 -318
  55. quasardb/handle.cpp +0 -29
  56. quasardb/handle.hpp +0 -98
  57. quasardb/integer.hpp +0 -88
  58. quasardb/logger.cpp +0 -106
  59. quasardb/logger.hpp +0 -228
  60. quasardb/masked_array.hpp +0 -651
  61. quasardb/metrics.cpp +0 -103
  62. quasardb/metrics.hpp +0 -112
  63. quasardb/module.cpp +0 -76
  64. quasardb/module.hpp +0 -24
  65. quasardb/node.hpp +0 -123
  66. quasardb/numpy.cpp +0 -6
  67. quasardb/numpy.hpp +0 -489
  68. quasardb/object_tracker.hpp +0 -283
  69. quasardb/options.hpp +0 -244
  70. quasardb/perf.hpp +0 -336
  71. quasardb/pytypes.hpp +0 -221
  72. quasardb/query.cpp +0 -420
  73. quasardb/query.hpp +0 -92
  74. quasardb/reader/ts_row.hpp +0 -281
  75. quasardb/reader/ts_value.hpp +0 -245
  76. quasardb/remove_cvref.hpp +0 -31
  77. quasardb/string.hpp +0 -160
  78. quasardb/table.cpp +0 -289
  79. quasardb/table.hpp +0 -325
  80. quasardb/table_reader.hpp +0 -220
  81. quasardb/tag.hpp +0 -77
  82. quasardb/timestamp.hpp +0 -97
  83. quasardb/traits.hpp +0 -619
  84. quasardb/ts_iterator.hpp +0 -193
  85. quasardb/utils/blob_deque.hpp +0 -96
  86. quasardb/utils/ostream.hpp +0 -17
  87. quasardb/utils/permutation.hpp +0 -50
  88. quasardb/utils/stable_sort.hpp +0 -25
  89. quasardb/utils/unzip_view.hpp +0 -89
  90. quasardb/utils.cpp +0 -28
  91. quasardb/utils.hpp +0 -174
  92. quasardb/writer.cpp +0 -534
  93. quasardb/writer.hpp +0 -396
  94. quasardb-3.14.2.dev1.dist-info/RECORD +0 -118
  95. {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev4.dist-info}/LICENSE.md +0 -0
  96. {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