// Data model: MDBX_val, integer keys, empty key/value, named tables
// Раздел учебника: Том I, глава 3, «Базовая модель данных»,
//   разделы «MDBX_val», «Главная таблица и dbi», «Integer-ключи», «Нулевые ключи/значения».
// Что демонстрирует: представление ключей и значений как «указатель+длина»;
//   главную таблицу и именованные таблицы; integer-ключи (key_mode::ordinal);
//   пустой ключ и пустое значение.
// Сборка: g++ -std=c++17 -I<libmdbx-include> -I../common 02-data-model.c++ -lmdbx
// Запуск: ./02-data-model
// Ожидаемый вывод:
//   main[key] = value
//   named[config] = 42
//   ordinal[1000] = thousand
//   empty value length = 0
//   ok: integer keys, named table, empty key/value
// При сбое — сообщение в stderr и exit 1.
//
// SPDX-License-Identifier: Apache-2.0

#include <cstdint>
#include <iostream>
#include <string>

#include "common.h++"
#include <mdbx.h++>

using buffer = mdbx::buffer<mdbx::default_allocator, mdbx::default_capacity_policy>;

int main() {
  try {
    const std::string path = std::string(example::tmpdir()) + "/mdbx-02-data-model.mdbx";
    mdbx::env::remove(path);

    mdbx::env_managed env = example::env_open(path);
    auto txn = env.start_write();

    // Главная таблица (name == nullptr): обычные ключи и значения.
    auto main = txn.open_map(nullptr);
    txn.insert(main, mdbx::slice("key"), mdbx::slice("value"));
    std::cout << "main[key] = " << txn.get(main, mdbx::slice("key")).as_string() << "\n";

    // Именованная таблица: отдельное пространство ключей внутри той же БД.
    auto named = txn.create_map("named", mdbx::key_mode::usual, mdbx::value_mode::single);
    txn.insert(named, mdbx::slice("config"), mdbx::slice("42"));
    std::cout << "named[config] = " << txn.get(named, mdbx::slice("config")).as_string() << "\n";

    // Integer-ключи: таблица с key_mode::ordinal (MDBX_INTEGERKEY),
    // ключи — uint64_t в нативном порядке байт.
    auto ord = txn.create_map("ordinal", mdbx::key_mode::ordinal, mdbx::value_mode::single);
    const uint64_t k1 = 1, k2 = 1000;
    txn.insert(ord, buffer::key_from_u64(k1), mdbx::slice("one"));
    txn.insert(ord, buffer::key_from_u64(k2), mdbx::slice("thousand"));
    std::cout << "ordinal[1000] = " << txn.get(ord, buffer::key_from_u64(k2)).as_string() << "\n";

    // Пустой ключ (нулевой длины) и пустое значение.
    txn.insert(main, mdbx::slice(), mdbx::slice("empty-key-value"));
    txn.insert(named, mdbx::slice("empty"), mdbx::slice());
    std::cout << "empty value length = " << txn.get(named, mdbx::slice("empty")).size() << "\n";

    txn.commit();

    std::cout << "ok: integer keys, named table, empty key/value\n";
    return EXIT_SUCCESS;
  } catch (const std::exception &ex) {
    std::cerr << "error: " << ex.what() << "\n";
    return EXIT_FAILURE;
  }
}