Reimplement indices in objects in more straightforward way

This commit is contained in:
Vitaly Baranov 2019-05-10 11:49:03 +03:00
parent dcc88f3a0c
commit 0d26ac8583
5 changed files with 54 additions and 20 deletions

View File

@ -43,10 +43,11 @@ public:
if (pjh.down())
{
size += 1;
++size;
while (pjh.next())
size += 1;
++size;
if (pjh.get_scope_type() == '{')
size /= 2;
}
return {size};
@ -322,6 +323,20 @@ public:
}
};
class JSONExtractKeyImpl : public JSONNullableImplBase<DataTypeString>
{
public:
static constexpr auto name{"jsonExtractKey"};
static Field getValue(ParsedJson::iterator & pjh)
{
if (pjh.get_scope_type() == '{' && pjh.prev() && pjh.is_string())
return {String{pjh.get_string()}};
else
return getDefault();
}
};
}
#else
namespace DB
@ -336,6 +351,7 @@ struct JSONExtractFloatImpl { static constexpr auto name{"jsonExtractFloat"}; };
struct JSONExtractBoolImpl { static constexpr auto name{"jsonExtractBool"}; };
//struct JSONExtractRawImpl { static constexpr auto name {"jsonExtractRaw"}; };
struct JSONExtractStringImpl { static constexpr auto name{"jsonExtractString"}; };
struct JSONExtractKeyImpl { static constexpr auto name{"jsonExtractKey"}; };
}
#endif
@ -360,6 +376,7 @@ void registerFunctionsJSON(FunctionFactory & factory)
// false
// >>();
factory.registerFunction<FunctionJSONBase<JSONExtractStringImpl, false>>();
factory.registerFunction<FunctionJSONBase<JSONExtractKeyImpl, false>>();
return;
}
#endif
@ -373,6 +390,7 @@ void registerFunctionsJSON(FunctionFactory & factory)
factory.registerFunction<FunctionJSONDummy<JSONExtractBoolImpl>>();
//factory.registerFunction<FunctionJSONDummy<JSONExtractRawImpl>>();
factory.registerFunction<FunctionJSONDummy<JSONExtractStringImpl>>();
factory.registerFunction<FunctionJSONDummy<JSONExtractKeyImpl>>();
}
}

View File

@ -59,18 +59,26 @@ private:
if (!pjh.is_object_or_array() || !pjh.down())
return false;
int steps = accessor.get<Int64>();
if (steps > 0)
steps -= 1;
else if (steps < 0)
int index = accessor.get<Int64>();
size_t steps;
if (index > 0)
{
steps += 1;
if (pjh.get_scope_type() == '{')
steps = index * 2 - 1;
else
steps = index - 1;
}
else if (index < 0)
{
size_t steps_to_end = 0;
ParsedJson::iterator pjh1{pjh};
while (pjh1.next())
steps += 1;
++steps_to_end;
if (pjh.get_scope_type() == '{')
steps = index * 2 + steps_to_end + 2;
else
steps = index + steps_to_end + 1;
}
else
return false;

View File

@ -1,8 +1,11 @@
4
2
Object
1
1
a
b
b
a
hello
hello
3

View File

@ -2,8 +2,11 @@ select jsonLength('{"a": "hello", "b": [-100, 200.0, 300]}');
select jsonType('{"a": "hello", "b": [-100, 200.0, 300]}');
select jsonHas('{"a": "hello", "b": [-100, 200.0, 300]}', 'a');
select jsonHas('{"a": "hello", "b": [-100, 200.0, 300]}', 'b');
select jsonExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', 1);
select jsonExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', 2);
select jsonExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', -1);
select jsonExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', -2);
select jsonExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 1);
select jsonExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 2);
select jsonExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 'a');
select jsonLength('{"a": "hello", "b": [-100, 200.0, 300]}', 'b');
select jsonType('{"a": "hello", "b": [-100, 200.0, 300]}', 'b');

View File

@ -79,19 +79,21 @@ An accessor can be either a string, a positive integer or a negative integer.
* Positive integer = access the n-th member/key from the beginning.
* Negative integer = access the n-th member/key from the end.
You may use integers to access both JSON arrays and JSON objects. JSON objects are accessed as an array with the `[key, value, key, value, ...]` layout.
You may use integers to access both JSON arrays and JSON objects.
So, for example:
```
select jsonExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 1) = 'a'
select jsonExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 2) = 'hello'
select jsonExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', -2) = 'b'
select jsonExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', 1) = 'a'
select jsonExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', 2) = 'b'
select jsonExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', -1) = 'b'
select jsonExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', -2) = 'a'
select jsonExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 1) = 'hello'
```
## jsonLength(params[, accessors]...)
Return the length of a JSON array or a JSON object. For JSON objects, both keys and values are included.
Return the length of a JSON array or a JSON object.
If the value does not exist or has a wrong type, `null` will be returned.
@ -99,7 +101,7 @@ Examples:
```
select jsonLength('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = 3
select jsonLength('{"a": "hello", "b": [-100, 200.0, 300]}') = 4
select jsonLength('{"a": "hello", "b": [-100, 200.0, 300]}') = 2
```
The usage of accessors is the same as above.