blob: b943e6e117d5a53ad342ae8b5eab0c94e4bd5f90 [file]
/*
* Copyright 2026-present Alibaba Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cstdint>
#include <map>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include "paimon/common/utils/jsonizable.h"
#include "paimon/common/utils/rapidjson_util.h"
#include "paimon/core/snapshot.h"
#include "rapidjson/allocators.h"
#include "rapidjson/document.h"
#include "rapidjson/rapidjson.h"
namespace paimon {
// Request and response objects of the REST catalog protocol. The JSON field names must
// stay aligned with the REST catalog open api.
class ErrorResponse : public Jsonizable<ErrorResponse> {
public:
static constexpr const char* kResourceTypeDatabase = "DATABASE";
static constexpr const char* kResourceTypeTable = "TABLE";
ErrorResponse(const std::string& resource_type, const std::string& resource_name,
const std::string& message, int32_t code)
: resource_type_(resource_type),
resource_name_(resource_name),
message_(message),
code_(code) {}
rapidjson::Value ToJson(rapidjson::Document::AllocatorType* allocator) const
noexcept(false) override;
void FromJson(const rapidjson::Value& obj) noexcept(false) override;
const std::string& GetResourceType() const {
return resource_type_;
}
const std::string& GetResourceName() const {
return resource_name_;
}
const std::string& GetMessage() const {
return message_;
}
int32_t GetCode() const {
return code_;
}
ErrorResponse() = default;
private:
std::string resource_type_;
std::string resource_name_;
std::string message_;
int32_t code_ = 0;
};
/// The response of "/v1/config".
class ConfigResponse : public Jsonizable<ConfigResponse> {
public:
ConfigResponse(const std::map<std::string, std::string>& defaults,
const std::map<std::string, std::string>& overrides)
: defaults_(defaults), overrides_(overrides) {}
rapidjson::Value ToJson(rapidjson::Document::AllocatorType* allocator) const
noexcept(false) override;
void FromJson(const rapidjson::Value& obj) noexcept(false) override;
/// Merges with the client options; the precedence is
/// `overrides` > `client_options` > `defaults`. A key sent as null in `overrides` is
/// removed from the result, which is how the server unsets a client option; a null in
/// `defaults` is ignored.
std::map<std::string, std::string> Merge(
const std::map<std::string, std::string>& client_options) const;
const std::map<std::string, std::string>& GetDefaults() const {
return defaults_;
}
const std::map<std::string, std::string>& GetOverrides() const {
return overrides_;
}
ConfigResponse() = default;
private:
std::map<std::string, std::string> defaults_;
std::map<std::string, std::string> overrides_;
/// Keys the server sent as null in `overrides`; `Merge` removes them from the result
/// and `ToJson` does not re-emit them.
std::set<std::string> removed_keys_;
};
/// The audit fields shared by database/table responses.
struct RestAuditFields {
std::optional<std::string> owner;
std::optional<int64_t> created_at;
std::optional<std::string> created_by;
std::optional<int64_t> updated_at;
std::optional<std::string> updated_by;
void ParseFrom(const rapidjson::Value& obj);
void AddTo(rapidjson::Value* obj, rapidjson::Document::AllocatorType* allocator) const;
/// Adds the present fields to `options`, keyed by their JSON field names.
void PutAuditOptionsTo(std::map<std::string, std::string>* options) const;
};
class CreateDatabaseRequest : public Jsonizable<CreateDatabaseRequest> {
public:
CreateDatabaseRequest(const std::string& name,
const std::map<std::string, std::string>& options)
: name_(name), options_(options) {}
rapidjson::Value ToJson(rapidjson::Document::AllocatorType* allocator) const
noexcept(false) override;
void FromJson(const rapidjson::Value& obj) noexcept(false) override;
const std::string& GetName() const {
return name_;
}
const std::map<std::string, std::string>& GetOptions() const {
return options_;
}
CreateDatabaseRequest() = default;
private:
std::string name_;
std::map<std::string, std::string> options_;
};
class GetDatabaseResponse : public Jsonizable<GetDatabaseResponse> {
public:
GetDatabaseResponse(const std::string& id, const std::string& name, const std::string& location,
const std::map<std::string, std::string>& options)
: id_(id), name_(name), location_(location), options_(options) {}
rapidjson::Value ToJson(rapidjson::Document::AllocatorType* allocator) const
noexcept(false) override;
void FromJson(const rapidjson::Value& obj) noexcept(false) override;
const std::string& GetId() const {
return id_;
}
const std::string& GetName() const {
return name_;
}
const std::string& GetLocation() const {
return location_;
}
const std::map<std::string, std::string>& GetOptions() const {
return options_;
}
const RestAuditFields& GetAuditFields() const {
return audit_;
}
GetDatabaseResponse() = default;
private:
std::string id_;
std::string name_;
std::string location_;
std::map<std::string, std::string> options_;
RestAuditFields audit_;
};
class ListDatabasesResponse : public Jsonizable<ListDatabasesResponse> {
public:
using ItemType = std::string;
ListDatabasesResponse(const std::vector<std::string>& databases,
const std::optional<std::string>& next_page_token)
: databases_(databases), next_page_token_(next_page_token) {}
rapidjson::Value ToJson(rapidjson::Document::AllocatorType* allocator) const
noexcept(false) override;
void FromJson(const rapidjson::Value& obj) noexcept(false) override;
const std::vector<std::string>& Data() const {
return databases_;
}
const std::optional<std::string>& NextPageToken() const {
return next_page_token_;
}
ListDatabasesResponse() = default;
private:
std::vector<std::string> databases_;
std::optional<std::string> next_page_token_;
};
class ListTablesResponse : public Jsonizable<ListTablesResponse> {
public:
using ItemType = std::string;
ListTablesResponse(const std::vector<std::string>& tables,
const std::optional<std::string>& next_page_token)
: tables_(tables), next_page_token_(next_page_token) {}
rapidjson::Value ToJson(rapidjson::Document::AllocatorType* allocator) const
noexcept(false) override;
void FromJson(const rapidjson::Value& obj) noexcept(false) override;
const std::vector<std::string>& Data() const {
return tables_;
}
const std::optional<std::string>& NextPageToken() const {
return next_page_token_;
}
ListTablesResponse() = default;
private:
std::vector<std::string> tables_;
std::optional<std::string> next_page_token_;
};
/// Each element is a snapshot in the same JSON layout as the snapshot files.
class ListSnapshotsResponse : public Jsonizable<ListSnapshotsResponse> {
public:
using ItemType = Snapshot;
ListSnapshotsResponse(const std::vector<Snapshot>& snapshots,
const std::optional<std::string>& next_page_token)
: snapshots_(snapshots), next_page_token_(next_page_token) {}
rapidjson::Value ToJson(rapidjson::Document::AllocatorType* allocator) const
noexcept(false) override;
void FromJson(const rapidjson::Value& obj) noexcept(false) override;
const std::vector<Snapshot>& Data() const {
return snapshots_;
}
const std::optional<std::string>& NextPageToken() const {
return next_page_token_;
}
ListSnapshotsResponse() = default;
private:
std::vector<Snapshot> snapshots_;
std::optional<std::string> next_page_token_;
};
/// The nested `schema` object (fields/partitionKeys/primaryKeys/options/comment) is
/// kept as a raw JSON string and converted to a `TableSchema` by the catalog.
class GetTableResponse : public Jsonizable<GetTableResponse> {
public:
GetTableResponse(const std::string& id, const std::string& database, const std::string& name,
const std::string& path, bool is_external, int64_t schema_id,
const std::string& schema_json)
: id_(id),
database_(database),
name_(name),
path_(path),
is_external_(is_external),
schema_id_(schema_id),
schema_json_(schema_json) {}
rapidjson::Value ToJson(rapidjson::Document::AllocatorType* allocator) const
noexcept(false) override;
void FromJson(const rapidjson::Value& obj) noexcept(false) override;
const std::string& GetId() const {
return id_;
}
/// The database of the table. The server reports it so that a table addressed by its
/// id alone can be resolved; it is empty on the endpoints that address a table by
/// database and name, which are the ones `RestCatalog` uses.
const std::string& GetDatabase() const {
return database_;
}
const std::string& GetName() const {
return name_;
}
const std::string& GetPath() const {
return path_;
}
bool IsExternal() const {
return is_external_;
}
int64_t GetSchemaId() const {
return schema_id_;
}
const std::string& GetSchemaJson() const {
return schema_json_;
}
const RestAuditFields& GetAuditFields() const {
return audit_;
}
GetTableResponse() = default;
private:
std::string id_;
std::string database_;
std::string name_;
std::string path_;
bool is_external_ = false;
int64_t schema_id_ = 0;
std::string schema_json_;
RestAuditFields audit_;
};
/// `schema_json` uses the same schema JSON layout as `GetTableResponse`.
class CreateTableRequest : public Jsonizable<CreateTableRequest> {
public:
CreateTableRequest(const std::string& database, const std::string& table,
const std::string& schema_json)
: database_(database), table_(table), schema_json_(schema_json) {}
rapidjson::Value ToJson(rapidjson::Document::AllocatorType* allocator) const
noexcept(false) override;
void FromJson(const rapidjson::Value& obj) noexcept(false) override;
const std::string& GetDatabase() const {
return database_;
}
const std::string& GetTable() const {
return table_;
}
const std::string& GetSchemaJson() const {
return schema_json_;
}
CreateTableRequest() = default;
private:
std::string database_;
std::string table_;
std::string schema_json_;
};
class RenameTableRequest : public Jsonizable<RenameTableRequest> {
public:
RenameTableRequest(const std::string& source_database, const std::string& source_table,
const std::string& destination_database,
const std::string& destination_table)
: source_database_(source_database),
source_table_(source_table),
destination_database_(destination_database),
destination_table_(destination_table) {}
rapidjson::Value ToJson(rapidjson::Document::AllocatorType* allocator) const
noexcept(false) override;
void FromJson(const rapidjson::Value& obj) noexcept(false) override;
const std::string& GetSourceDatabase() const {
return source_database_;
}
const std::string& GetSourceTable() const {
return source_table_;
}
const std::string& GetDestinationDatabase() const {
return destination_database_;
}
const std::string& GetDestinationTable() const {
return destination_table_;
}
RenameTableRequest() = default;
private:
std::string source_database_;
std::string source_table_;
std::string destination_database_;
std::string destination_table_;
};
} // namespace paimon