quasardb 3.14.2.dev1__cp310-cp310-win_amd64.whl → 3.14.2.dev4__cp310-cp310-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.
- quasardb/INSTALL.vcxproj +9 -4
- quasardb/__init__.py +33 -4
- quasardb/cmake_install.cmake +6 -0
- quasardb/date/ALL_BUILD.vcxproj +9 -8
- quasardb/date/CMakeFiles/Export/df49adab93b9e0c10c64f72458b31971/dateTargets.cmake +13 -13
- quasardb/date/CMakeFiles/generate.stamp.depend +4 -4
- quasardb/date/INSTALL.vcxproj +9 -4
- quasardb/date/cmake_install.cmake +6 -0
- quasardb/date/dateConfigVersion.cmake +0 -5
- quasardb/date/dateTargets.cmake +4 -8
- quasardb/numpy/__init__.py +58 -10
- quasardb/pandas/__init__.py +58 -102
- quasardb/pybind11/ALL_BUILD.vcxproj +9 -8
- quasardb/pybind11/CMakeFiles/generate.stamp.depend +14 -14
- quasardb/pybind11/INSTALL.vcxproj +9 -4
- quasardb/pybind11/cmake_install.cmake +6 -0
- quasardb/qdb_api.dll +0 -0
- quasardb/quasardb.cp310-win_amd64.pyd +0 -0
- quasardb/range-v3/ALL_BUILD.vcxproj +9 -8
- quasardb/range-v3/CMakeFiles/Export/d94ef200eca10a819b5858b33e808f5b/range-v3-targets.cmake +13 -13
- quasardb/range-v3/CMakeFiles/generate.stamp.depend +11 -11
- quasardb/range-v3/INSTALL.vcxproj +9 -4
- quasardb/range-v3/cmake_install.cmake +42 -0
- quasardb/range-v3/range-v3-config-version.cmake +0 -5
- quasardb/range-v3/range-v3-config.cmake +4 -8
- quasardb/range-v3/range.v3.headers.vcxproj +9 -8
- {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev4.dist-info}/METADATA +15 -10
- quasardb-3.14.2.dev4.dist-info/RECORD +54 -0
- {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev4.dist-info}/WHEEL +1 -1
- quasardb/CMakeLists.txt +0 -510
- quasardb/batch_column.hpp +0 -80
- quasardb/batch_inserter.hpp +0 -248
- quasardb/blob.hpp +0 -150
- quasardb/cluster.cpp +0 -89
- quasardb/cluster.hpp +0 -551
- quasardb/concepts.hpp +0 -278
- quasardb/continuous.cpp +0 -149
- quasardb/continuous.hpp +0 -106
- quasardb/convert/array.hpp +0 -282
- quasardb/convert/point.hpp +0 -330
- quasardb/convert/range.hpp +0 -282
- quasardb/convert/unicode.hpp +0 -598
- quasardb/convert/util.hpp +0 -22
- quasardb/convert/value.hpp +0 -711
- quasardb/convert.hpp +0 -38
- quasardb/detail/qdb_resource.hpp +0 -129
- quasardb/detail/ts_column.hpp +0 -224
- quasardb/direct_blob.hpp +0 -108
- quasardb/direct_handle.hpp +0 -83
- quasardb/direct_integer.hpp +0 -94
- quasardb/dispatch.hpp +0 -157
- quasardb/double.hpp +0 -87
- quasardb/entry.hpp +0 -273
- quasardb/error.hpp +0 -318
- quasardb/handle.cpp +0 -29
- quasardb/handle.hpp +0 -98
- quasardb/integer.hpp +0 -88
- quasardb/logger.cpp +0 -106
- quasardb/logger.hpp +0 -228
- quasardb/masked_array.hpp +0 -651
- quasardb/metrics.cpp +0 -103
- quasardb/metrics.hpp +0 -112
- quasardb/module.cpp +0 -76
- quasardb/module.hpp +0 -24
- quasardb/node.hpp +0 -123
- quasardb/numpy.cpp +0 -6
- quasardb/numpy.hpp +0 -489
- quasardb/object_tracker.hpp +0 -283
- quasardb/options.hpp +0 -244
- quasardb/perf.hpp +0 -336
- quasardb/pytypes.hpp +0 -221
- quasardb/query.cpp +0 -420
- quasardb/query.hpp +0 -92
- quasardb/reader/ts_row.hpp +0 -281
- quasardb/reader/ts_value.hpp +0 -245
- quasardb/remove_cvref.hpp +0 -31
- quasardb/string.hpp +0 -160
- quasardb/table.cpp +0 -289
- quasardb/table.hpp +0 -325
- quasardb/table_reader.hpp +0 -220
- quasardb/tag.hpp +0 -77
- quasardb/timestamp.hpp +0 -97
- quasardb/traits.hpp +0 -619
- quasardb/ts_iterator.hpp +0 -193
- quasardb/utils/blob_deque.hpp +0 -96
- quasardb/utils/ostream.hpp +0 -17
- quasardb/utils/permutation.hpp +0 -50
- quasardb/utils/stable_sort.hpp +0 -25
- quasardb/utils/unzip_view.hpp +0 -89
- quasardb/utils.cpp +0 -28
- quasardb/utils.hpp +0 -174
- quasardb/writer.cpp +0 -534
- quasardb/writer.hpp +0 -396
- quasardb-3.14.2.dev1.dist-info/RECORD +0 -118
- {quasardb-3.14.2.dev1.dist-info → quasardb-3.14.2.dev4.dist-info}/LICENSE.md +0 -0
- {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
|