refactor parseTypeOfField & fix tests

This commit is contained in:
Mikhail Artemenko 2022-03-27 23:00:28 +03:00
parent 96cfc7f07a
commit 1886d9c2ea
7 changed files with 68 additions and 56 deletions

View File

@ -1,14 +1,14 @@
version: '2.3' version: '2.3'
services: services:
meili1: meili1:
image: getmeili/meilisearch image: getmeili/meilisearch:latest
restart: always restart: always
command: ./meilisearch command: ./meilisearch
ports: ports:
- ${MEILI_EXTERNAL_PORT}:${MEILI_INTERNAL_PORT} - ${MEILI_EXTERNAL_PORT}:${MEILI_INTERNAL_PORT}
meili_secure: meili_secure:
image: getmeili/meilisearch image: getmeili/meilisearch:latest
restart: always restart: always
command: ./meilisearch --master-key="password" command: ./meilisearch --master-key="password"
ports: ports:

View File

@ -1,11 +1,14 @@
#include <memory> #include <memory>
#include <string>
#include <Storages/MeiliSearch/MeiliSearchColumnDescriptionFetcher.h> #include <Storages/MeiliSearch/MeiliSearchColumnDescriptionFetcher.h>
#include <base/JSON.h> #include <base/JSON.h>
#include "DataTypes/DataTypeArray.h" #include <DataTypes/DataTypeArray.h>
#include "DataTypes/DataTypeNullable.h" #include <DataTypes/DataTypeNullable.h>
#include "DataTypes/DataTypeString.h" #include <DataTypes/DataTypeString.h>
#include "DataTypes/DataTypesNumber.h" #include <DataTypes/DataTypesNumber.h>
#include "DataTypes/Serializations/ISerialization.h" #include <DataTypes/Serializations/ISerialization.h>
#include <IO/ReadHelpers.h>
#include <base/types.h>
namespace DB namespace DB
{ {
@ -25,12 +28,9 @@ void MeiliSearchColumnDescriptionFetcher::addParam(const String & key, const Str
query_params[key] = val; query_params[key] = val;
} }
bool isDouble(const std::string & val) bool checkIfInteger(const String & s)
{ {
std::istringstream iss(val); return s.find('.') == String::npos;
double f;
iss >> std::noskipws >> f;
return iss.eof() && !iss.fail() && static_cast<Int64>(f) != f;
} }
DataTypePtr parseTypeOfField(JSON ptr) DataTypePtr parseTypeOfField(JSON ptr)
@ -53,19 +53,15 @@ DataTypePtr parseTypeOfField(JSON ptr)
DataTypePtr res = std::make_shared<DataTypeNullable>(res); DataTypePtr res = std::make_shared<DataTypeNullable>(res);
return res; return res;
} }
if (isDouble(ptr.toString()))
{
return std::make_shared<DataTypeFloat64>();
}
if (ptr.isNumber()) if (ptr.isNumber())
{ {
return std::make_shared<DataTypeInt64>(); if (checkIfInteger(ptr.toString()))
{
return std::make_shared<DataTypeInt64>();
}
return std::make_shared<DataTypeFloat64>();
} }
if (ptr.isObject()) return std::make_shared<DataTypeString>();
{
return std::make_shared<DataTypeString>();
}
throw Exception(ErrorCodes::UNSUPPORTED_MEILISEARCH_TYPE, "Can't recognize type of some fields");
} }
ColumnsDescription MeiliSearchColumnDescriptionFetcher::fetchColumnsDescription() const ColumnsDescription MeiliSearchColumnDescriptionFetcher::fetchColumnsDescription() const

View File

@ -28,7 +28,14 @@ CURLcode MeiliSearchConnection::execQuery(std::string_view url, std::string_view
headers_list = nullptr; headers_list = nullptr;
headers_list = curl_slist_append(headers_list, "Content-Type: application/json"); headers_list = curl_slist_append(headers_list, "Content-Type: application/json");
headers_list = curl_slist_append(headers_list, config.key.c_str());
String full_key;
if (!config.key.empty())
{
full_key = config.key_prefix + config.key;
headers_list = curl_slist_append(headers_list, full_key.c_str());
}
handle = curl_easy_init(); handle = curl_easy_init();
curl_easy_setopt(handle, CURLOPT_URL, url.data()); curl_easy_setopt(handle, CURLOPT_URL, url.data());

View File

@ -10,14 +10,15 @@ namespace DB
{ {
struct MeiliSearchConfiguration struct MeiliSearchConfiguration
{ {
inline const static String key_prefix = "Authorization: Bearer ";
String key; String key;
String index; String index;
String connection_string; String connection_string;
MeiliSearchConfiguration(const String & url_, const String & index_, const String & key_) : index{index_} MeiliSearchConfiguration(const String & url_, const String & index_, const String & key_) : key{key_}, index{index_}
{ {
connection_string = url_ + "/indexes/" + index_ + "/"; connection_string = url_ + "/indexes/" + index_ + "/";
key = "Authorization: Bearer " + key_;
} }
}; };

View File

@ -126,48 +126,33 @@ MeiliSearchConfiguration StorageMeiliSearch::getConfiguration(ASTs engine_args,
if (auto named_collection = getExternalDataSourceConfiguration(engine_args, context)) if (auto named_collection = getExternalDataSourceConfiguration(engine_args, context))
{ {
auto [common_configuration, storage_specific_args] = named_collection.value(); auto [common_configuration, storage_specific_args] = named_collection.value();
String url = common_configuration.addresses_expr; String url = common_configuration.addresses_expr;
String index = common_configuration.table; String index = common_configuration.table;
String key = common_configuration.password; String key = common_configuration.password;
for (const auto & [arg_name, arg_value] : storage_specific_args)
{
if (arg_name == "url")
{
if (!url.empty())
throw Exception(
"2 times given 'url' value, old = " + url + " new = " + arg_value->as<ASTLiteral>()->value.safeGet<String>(),
ErrorCodes::BAD_ARGUMENTS);
url = arg_value->as<ASTLiteral>()->value.safeGet<String>();
}
else if (arg_name == "key" || arg_name == "password")
{
if (!key.empty())
throw Exception(
"2 times given 'key' value, old = " + key + " new = " + arg_value->as<ASTLiteral>()->value.safeGet<String>(),
ErrorCodes::BAD_ARGUMENTS);
key = arg_value->as<ASTLiteral>()->value.safeGet<String>();
}
else
throw Exception("Unexpected key-value argument", ErrorCodes::BAD_ARGUMENTS);
}
if (url.empty() || index.empty()) if (url.empty() || index.empty())
{ {
throw Exception("Storage MeiliSearch requires 3 parameters: {url, index, [key]}", ErrorCodes::BAD_ARGUMENTS); throw Exception(
"Storage MeiliSearch requires 3 parameters: MeiliSearch('url', 'index', 'key'= \"\")", ErrorCodes::BAD_ARGUMENTS);
} }
return MeiliSearchConfiguration(url, index, key); return MeiliSearchConfiguration(url, index, key);
} }
else else
{ {
if (engine_args.size() != 3) if (engine_args.size() < 2 || 3 < engine_args.size())
{ {
throw Exception( throw Exception(
"Storage MeiliSearch requires 3 parameters: MeiliSearch('url', 'index', 'key')", "Storage MeiliSearch requires 3 parameters: MeiliSearch('url', 'index', 'key'= \"\")",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
} }
String url = engine_args[0]->as<ASTLiteral &>().value.safeGet<String>(); String url = engine_args[0]->as<ASTLiteral &>().value.safeGet<String>();
String index = engine_args[1]->as<ASTLiteral &>().value.safeGet<String>(); String index = engine_args[1]->as<ASTLiteral &>().value.safeGet<String>();
String key = engine_args[2]->as<ASTLiteral &>().value.safeGet<String>(); String key;
if (engine_args.size() == 3)
key = engine_args[2]->as<ASTLiteral &>().value.safeGet<String>();
return MeiliSearchConfiguration(url, index, key); return MeiliSearchConfiguration(url, index, key);
} }
} }

View File

@ -11,6 +11,14 @@
<database>MeiliSearch</database> <database>MeiliSearch</database>
<addresses_expr>meili_secure:7700</addresses_expr> <addresses_expr>meili_secure:7700</addresses_expr>
<table>new_table</table> <table>new_table</table>
<password>password</password>
</named_collection_for_meili_secure> </named_collection_for_meili_secure>
<named_collection_for_meili_secure_no_password>
<database>MeiliSearch</database>
<addresses_expr>meili_secure:7700</addresses_expr>
<table>new_table</table>
</named_collection_for_meili_secure_no_password>
</named_collections> </named_collections>
</clickhouse> </clickhouse>

View File

@ -427,25 +427,37 @@ def test_named_collection(started_cluster):
@pytest.mark.parametrize('started_cluster', [False], indirect=['started_cluster']) @pytest.mark.parametrize('started_cluster', [False], indirect=['started_cluster'])
def test_named_collection_secure(started_cluster): def test_named_collection_secure(started_cluster):
client = get_meili_secure_client(started_cluster) client_secure = get_meili_secure_client(started_cluster)
table = client.index("new_table") client_free = get_meili_client(started_cluster)
table_secure = client_secure.index("new_table")
table_free = client_free.index("new_table")
data = [] data = []
for i in range(0, 100): for i in range(0, 100):
data.append({'id': i, 'data': hex(i * i)}) data.append({'id': i, 'data': hex(i * i)})
push_data(client, table, data) push_data(client_secure, table_secure, data)
push_data(client_free, table_free, data)
node = started_cluster.instances['meili'] node = started_cluster.instances['meili']
node.query( node.query(
"CREATE TABLE simple_meili_table(id UInt64, data String) ENGINE = MeiliSearch( named_collection_for_meili_secure, key='password')") "CREATE TABLE simple_meili_table(id UInt64, data String) ENGINE = MeiliSearch( named_collection_for_meili_secure )")
node.query( node.query(
"CREATE TABLE wrong_meili_table(id UInt64, data String) ENGINE = MeiliSearch( named_collection_for_meili_secure )") "CREATE TABLE wrong_meili_table(id UInt64, data String) ENGINE = MeiliSearch( named_collection_for_meili_secure_no_password )")
node.query(
"CREATE TABLE combine_meili_table(id UInt64, data String) ENGINE = MeiliSearch( named_collection_for_meili_secure_no_password, password=\"password\" )")
assert node.query("SELECT COUNT() FROM simple_meili_table") == '100\n' assert node.query("SELECT COUNT() FROM simple_meili_table") == '100\n'
assert node.query("SELECT sum(id) FROM simple_meili_table") == str(sum(range(0, 100))) + '\n' assert node.query("SELECT sum(id) FROM simple_meili_table") == str(sum(range(0, 100))) + '\n'
assert node.query("SELECT data FROM simple_meili_table WHERE id = 42") == hex(42 * 42) + '\n' assert node.query("SELECT data FROM simple_meili_table WHERE id = 42") == hex(42 * 42) + '\n'
assert node.query("SELECT COUNT() FROM combine_meili_table") == '100\n'
assert node.query("SELECT sum(id) FROM combine_meili_table") == str(sum(range(0, 100))) + '\n'
assert node.query("SELECT data FROM combine_meili_table WHERE id = 42") == hex(42 * 42) + '\n'
error = node.query_and_get_error("SELECT COUNT() FROM wrong_meili_table") error = node.query_and_get_error("SELECT COUNT() FROM wrong_meili_table")
assert("MEILISEARCH_EXCEPTION" in error) assert("MEILISEARCH_EXCEPTION" in error)
@ -457,7 +469,10 @@ def test_named_collection_secure(started_cluster):
node.query("DROP TABLE simple_meili_table") node.query("DROP TABLE simple_meili_table")
node.query("DROP TABLE wrong_meili_table") node.query("DROP TABLE wrong_meili_table")
table.delete() node.query("DROP TABLE combine_meili_table")
table_secure.delete()
table_free.delete()
@pytest.mark.parametrize('started_cluster', [False], indirect=['started_cluster']) @pytest.mark.parametrize('started_cluster', [False], indirect=['started_cluster'])
def test_table_function(started_cluster): def test_table_function(started_cluster):