@@ -10,8 +10,9 @@ namespace {
10
10
11
11
class TCsvToYdbConverter {
12
12
public:
13
- explicit TCsvToYdbConverter (TTypeParser& parser)
13
+ explicit TCsvToYdbConverter (TTypeParser& parser, const std::optional<TString>& nullValue )
14
14
: Parser(parser)
15
+ , NullValue(nullValue)
15
16
{
16
17
}
17
18
@@ -40,12 +41,12 @@ class TCsvToYdbConverter {
40
41
size_t cnt;
41
42
try {
42
43
auto value = StringToArithmetic<T>(token, cnt);
43
- if (cnt != token.Size () || value < std::numeric_limits<T>::min () || value > std::numeric_limits<T>::max ()) {
44
+ if (cnt != token.Size () || value < std::numeric_limits<T>::lowest () || value > std::numeric_limits<T>::max ()) {
44
45
throw yexception ();
45
46
}
46
47
return static_cast <T>(value);
47
48
} catch (std::exception & e) {
48
- throw TMisuseException () << " Expected " << Parser.GetPrimitive () << " value, recieved: \" " << token << " \" ." ;
49
+ throw TMisuseException () << " Expected " << Parser.GetPrimitive () << " value, recieved: \" " << token << " \" ." ;
49
50
}
50
51
}
51
52
@@ -105,15 +106,30 @@ class TCsvToYdbConverter {
105
106
case EPrimitiveType::DyNumber:
106
107
Builder.DyNumber (token);
107
108
break ;
108
- case EPrimitiveType::Date:
109
- Builder.Date (TInstant::Days (GetArithmetic<ui16>(token)));
109
+ case EPrimitiveType::Date: {
110
+ TInstant date;
111
+ if (!TInstant::TryParseIso8601 (token, date)) {
112
+ date = TInstant::Days (GetArithmetic<ui16>(token));
113
+ }
114
+ Builder.Date (date);
110
115
break ;
111
- case EPrimitiveType::Datetime:
112
- Builder.Datetime (TInstant::Seconds (GetArithmetic<ui32>(token)));
116
+ }
117
+ case EPrimitiveType::Datetime: {
118
+ TInstant datetime;
119
+ if (!TInstant::TryParseIso8601 (token, datetime)) {
120
+ datetime = TInstant::Seconds (GetArithmetic<ui32>(token));
121
+ }
122
+ Builder.Datetime (datetime);
113
123
break ;
114
- case EPrimitiveType::Timestamp:
115
- Builder.Timestamp (TInstant::MicroSeconds (GetArithmetic<ui64>(token)));
124
+ }
125
+ case EPrimitiveType::Timestamp: {
126
+ TInstant timestamp;
127
+ if (!TInstant::TryParseIso8601 (token, timestamp)) {
128
+ timestamp = TInstant::MicroSeconds (GetArithmetic<ui64>(token));
129
+ }
130
+ Builder.Timestamp (timestamp);
116
131
break ;
132
+ }
117
133
case EPrimitiveType::Interval:
118
134
Builder.Interval (GetArithmetic<i64>(token));
119
135
break ;
@@ -133,17 +149,17 @@ class TCsvToYdbConverter {
133
149
134
150
void BuildValue (TStringBuf token) {
135
151
switch (Parser.GetKind ()) {
136
- case TTypeParser::ETypeKind::Primitive:
152
+ case TTypeParser::ETypeKind::Primitive: {
137
153
BuildPrimitive (TString (token));
138
154
break ;
139
-
140
- case TTypeParser::ETypeKind::Decimal:
155
+ }
156
+ case TTypeParser::ETypeKind::Decimal: {
141
157
Builder.Decimal (TString (token));
142
158
break ;
143
-
144
- case TTypeParser::ETypeKind::Optional:
159
+ }
160
+ case TTypeParser::ETypeKind::Optional: {
145
161
Parser.OpenOptional ();
146
- if (token == NullValue) {
162
+ if (NullValue && token == NullValue) {
147
163
Builder.EmptyOptional (GetType ());
148
164
} else {
149
165
Builder.BeginOptional ();
@@ -152,23 +168,31 @@ class TCsvToYdbConverter {
152
168
}
153
169
Parser.CloseOptional ();
154
170
break ;
155
-
156
- case TTypeParser::ETypeKind::Null:
171
+ }
172
+ case TTypeParser::ETypeKind::Null: {
157
173
EnsureNull (token);
158
174
break ;
159
-
160
- case TTypeParser::ETypeKind::Void:
175
+ }
176
+ case TTypeParser::ETypeKind::Void: {
161
177
EnsureNull (token);
162
178
break ;
163
-
164
- case TTypeParser::ETypeKind::Tagged:
179
+ }
180
+ case TTypeParser::ETypeKind::Tagged: {
165
181
Parser.OpenTagged ();
166
182
Builder.BeginTagged (Parser.GetTag ());
167
183
BuildValue (token);
168
184
Builder.EndTagged ();
169
185
Parser.CloseTagged ();
170
186
break ;
171
-
187
+ }
188
+ case TTypeParser::ETypeKind::Pg: {
189
+ if (NullValue && token == NullValue) {
190
+ Builder.Pg (TPgValue (TPgValue::VK_NULL, {}, Parser.GetPg ()));
191
+ } else {
192
+ Builder.Pg (TPgValue (TPgValue::VK_TEXT, TString (token), Parser.GetPg ()));
193
+ }
194
+ break ;
195
+ }
172
196
default :
173
197
throw TMisuseException () << " Unsupported type kind: " << Parser.GetKind ();
174
198
}
@@ -200,6 +224,10 @@ class TCsvToYdbConverter {
200
224
Parser.CloseTagged ();
201
225
break ;
202
226
227
+ case TTypeParser::ETypeKind::Pg:
228
+ typeBuilder.Pg (Parser.GetPg ());
229
+ break ;
230
+
203
231
default :
204
232
throw TMisuseException () << " Unsupported type kind: " << Parser.GetKind ();
205
233
}
@@ -222,6 +250,9 @@ class TCsvToYdbConverter {
222
250
}
223
251
224
252
void EnsureNull (TStringBuf token) const {
253
+ if (!NullValue) {
254
+ throw TMisuseException () << " Expected null value instead of \" " << token << " \" , but null value is not set." ;
255
+ }
225
256
if (token != NullValue) {
226
257
throw TMisuseException () << " Expected null value: \" " << NullValue << " \" , recieved: \" " << token << " \" ." ;
227
258
}
@@ -234,28 +265,42 @@ class TCsvToYdbConverter {
234
265
235
266
private:
236
267
TTypeParser& Parser;
237
- const TString NullValue = " " ;
268
+ const std::optional< TString> NullValue = " " ;
238
269
TValueBuilder Builder;
239
270
};
240
271
241
272
}
242
273
243
- TCsvParser::TCsvParser (TString&& headerRow, const char delimeter, const std::map<TString, TType>& paramTypes, const std::map<TString, TString>& paramSources)
274
+ TCsvParser::TCsvParser (TString&& headerRow, const char delimeter, const std::optional<TString>& nullValue,
275
+ const std::map<TString, TType>* paramTypes,
276
+ const std::map<TString, TString>* paramSources)
244
277
: HeaderRow(std::move(headerRow))
245
278
, Delimeter(delimeter)
279
+ , NullValue(nullValue)
246
280
, ParamTypes(paramTypes)
247
281
, ParamSources(paramSources)
248
282
{
249
283
NCsvFormat::CsvSplitter splitter (HeaderRow, Delimeter);
250
284
Header = static_cast <TVector<TString>>(splitter);
251
285
}
252
286
253
- TValue TCsvParser::FieldToValue (TTypeParser& parser, TStringBuf token) {
254
- TCsvToYdbConverter converter (parser);
287
+ TCsvParser::TCsvParser (TVector<TString>&& header, const char delimeter, const std::optional<TString>& nullValue,
288
+ const std::map<TString, TType>* paramTypes,
289
+ const std::map<TString, TString>* paramSources)
290
+ : Header(std::move(header))
291
+ , Delimeter(delimeter)
292
+ , NullValue(nullValue)
293
+ , ParamTypes(paramTypes)
294
+ , ParamSources(paramSources)
295
+ {
296
+ }
297
+
298
+ TValue TCsvParser::FieldToValue (TTypeParser& parser, TStringBuf token) const {
299
+ TCsvToYdbConverter converter (parser, NullValue);
255
300
return converter.Convert (token);
256
301
}
257
302
258
- void TCsvParser::GetParams (TString&& data, TParamsBuilder& builder) {
303
+ void TCsvParser::GetParams (TString&& data, TParamsBuilder& builder) const {
259
304
NCsvFormat::CsvSplitter splitter (data, Delimeter);
260
305
auto headerIt = Header.begin ();
261
306
do {
@@ -264,14 +309,16 @@ void TCsvParser::GetParams(TString&& data, TParamsBuilder& builder) {
264
309
throw TMisuseException () << " Header contains less fields than data. Header: \" " << HeaderRow << " \" , data: \" " << data << " \" " ;
265
310
}
266
311
TString fullname = " $" + *headerIt;
267
- auto paramIt = ParamTypes. find (fullname);
268
- if (paramIt == ParamTypes. end ()) {
312
+ auto paramIt = ParamTypes-> find (fullname);
313
+ if (paramIt == ParamTypes-> end ()) {
269
314
++headerIt;
270
315
continue ;
271
316
}
272
- auto paramSource = ParamSources.find (fullname);
273
- if (paramSource != ParamSources.end ()) {
274
- throw TMisuseException () << " Parameter " << fullname << " value found in more than one source: stdin, " << paramSource->second << " ." ;
317
+ if (ParamSources) {
318
+ auto paramSource = ParamSources->find (fullname);
319
+ if (paramSource != ParamSources->end ()) {
320
+ throw TMisuseException () << " Parameter " << fullname << " value found in more than one source: stdin, " << paramSource->second << " ." ;
321
+ }
275
322
}
276
323
TTypeParser parser (paramIt->second );
277
324
builder.AddParam (fullname, FieldToValue (parser, token));
@@ -283,27 +330,30 @@ void TCsvParser::GetParams(TString&& data, TParamsBuilder& builder) {
283
330
}
284
331
}
285
332
286
- void TCsvParser::GetValue (TString&& data, const TType& type, TValueBuilder& builder) {
333
+ void TCsvParser::GetValue (TString&& data, TValueBuilder& builder, const TType& type) const {
287
334
NCsvFormat::CsvSplitter splitter (data, Delimeter);
288
- auto headerIt = Header.begin ();
335
+ auto headerIt = Header.cbegin ();
289
336
std::map<TString, TStringBuf> fields;
290
337
do {
291
338
TStringBuf token = splitter.Consume ();
292
- if (headerIt == Header.end ()) {
339
+ if (headerIt == Header.cend ()) {
293
340
throw TMisuseException () << " Header contains less fields than data. Header: \" " << HeaderRow << " \" , data: \" " << data << " \" " ;
294
341
}
295
342
fields[*headerIt] = token;
296
343
++headerIt;
297
344
} while (splitter.Step ());
298
345
299
- if (headerIt != Header.end ()) {
346
+ if (headerIt != Header.cend ()) {
300
347
throw TMisuseException () << " Header contains more fields than data. Header: \" " << HeaderRow << " \" , data: \" " << data << " \" " ;
301
348
}
302
349
builder.BeginStruct ();
303
350
TTypeParser parser (type);
304
351
parser.OpenStruct ();
305
352
while (parser.TryNextMember ()) {
306
353
TString name = parser.GetMemberName ();
354
+ if (name == " __ydb_skip_column_name" ) {
355
+ continue ;
356
+ }
307
357
auto fieldIt = fields.find (name);
308
358
if (fieldIt == fields.end ()) {
309
359
throw TMisuseException () << " No member \" " << name << " \" in csv string for YDB struct type" ;
@@ -314,5 +364,19 @@ void TCsvParser::GetValue(TString&& data, const TType& type, TValueBuilder& buil
314
364
builder.EndStruct ();
315
365
}
316
366
367
+ TType TCsvParser::GetColumnsType () const {
368
+ TTypeBuilder builder;
369
+ builder.BeginStruct ();
370
+ for (const auto & colName : Header) {
371
+ if (ParamTypes->find (colName) != ParamTypes->end ()) {
372
+ builder.AddMember (colName, ParamTypes->at (colName));
373
+ } else {
374
+ builder.AddMember (" __ydb_skip_column_name" , TTypeBuilder ().Build ());
375
+ }
376
+ }
377
+ builder.EndStruct ();
378
+ return builder.Build ();
379
+ }
380
+
317
381
}
318
382
}
0 commit comments