Ver Fonte

release(v2.1.0): client API cleanup — BREAKING

Following shadowman's v2.0 alignment audit, drops the pre-v1.6 backward-
compat surfaces in the client header. Consumers (shadowman, callerai,
OCR-API) must rebuild against the new headers; the .so soname stays at
2 so dpkg won't see this as a parallel install.

## Breaking changes

- Deleted `smartbotic::database::QueryOptions` from document.hpp. The
  pre-v1.6 EQ-only shape (`vector<pair<string, json>> filters`) was dead
  code; the canonical type has been `Client::QueryOptions` (with the rich
  Filter API) since v1.6. Zero in-tree callers of the deleted struct.
- Removed `Client::find(const std::string& collection)` no-options
  overload. Pass `QueryOptions{}` explicitly. The named callsite reads
  clearer and prevents the silent "scan the whole collection" footgun.

## Added

- Named factories on `Client::Filter` covering every FilterOp:
  `Filter::eq` / `ne` / `gt` / `gte` / `lt` / `lte` / `in` / `contains` /
  `exists` / `regex` / `search`. Replaces the 3-arg raw constructor at
  callsites — `Filter::gt("age", 18)` instead of `Filter{"age",
  FilterOp::GT, 18}`. The raw constructor stays; the factories are
  preferred. Documented at the Filter declaration site.

## Migration cookbook for consumers

Before:
    QueryOptions opts;
    opts.filters.push_back({"status", FilterOp::EQ, "active"});
    auto results = client.find("users");           // implicit all
    auto active  = client.find("users", opts);

After:
    auto results = client.find("users", QueryOptions{});
    QueryOptions opts;
    opts.filters.push_back(Filter::eq("status", "active"));
    auto active  = client.find("users", opts);

For new code, prefer the factories at every callsite:
    auto adults_admins = client.find("users", {
        .filters = {
            Filter::gt("age", 18),
            Filter::in("role", {"admin", "owner"}),
        },
        .limit = 100
    });

## SOVERSION

Aligned CMake `SOVERSION` to 2 (was 1 — the deb script already produced
.so.2 via VERSION major; the misalignment was harmless). Library bumps
v2.0 → v2.1 at API level; same on-wire gRPC protocol; same .so.2 binary
soname. Consumer deb deps should pin `libsmartbotic-db-client (>= 2.1.0)`.

Full suite (12/12) green.
fszontagh há 2 meses atrás
pai
commit
8e92761988

Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
CLAUDE.md


+ 1 - 1
VERSION

@@ -1 +1 @@
-2.0.0
+2.1.0

+ 1 - 1
client/CMakeLists.txt

@@ -7,7 +7,7 @@ if(BUILD_SHARED_LIBS)
     )
     set_target_properties(smartbotic-db-client PROPERTIES
         VERSION ${SMARTBOTIC_DB_VERSION}
-        SOVERSION 1
+        SOVERSION 2
     )
 else()
     add_library(smartbotic-db-client STATIC

+ 60 - 8
client/include/smartbotic/database/client.hpp

@@ -179,6 +179,27 @@ public:
 
     /**
      * A single query filter with operator.
+     *
+     * Construction options, in increasing order of readability:
+     *
+     *   Filter{"age", FilterOp::GT, 18}             // raw 3-arg
+     *   Filter::gt("age", 18)                       // named factory (recommended)
+     *
+     * The named factories cover every operator; pick the one that matches
+     * the predicate's intent so callsites read like the question they're
+     * asking:
+     *
+     *   Filter::eq("status", "active")
+     *   Filter::ne("deleted", true)
+     *   Filter::gt("age", 18)                       // age > 18
+     *   Filter::gte("score", 0.8)                   // score ≥ 0.8
+     *   Filter::lt("retry_count", 5)                // retry_count < 5
+     *   Filter::lte("priority", 3)                  // priority ≤ 3
+     *   Filter::in("role", {"admin", "owner"})      // role IN (...)
+     *   Filter::contains("tags", "urgent")          // tags contains "urgent"
+     *   Filter::exists("email", true)               // email is set
+     *   Filter::regex("name", "^Alice")             // name matches /^Alice/
+     *   Filter::search("description", "needle")     // case-insensitive substr
      */
     struct Filter {
         std::string field;
@@ -188,9 +209,41 @@ public:
         Filter() = default;
         Filter(std::string f, FilterOp o, nlohmann::json v)
             : field(std::move(f)), op(o), value(std::move(v)) {}
-        // Convenience: equality filter
-        Filter(std::string f, nlohmann::json v)
-            : field(std::move(f)), op(FilterOp::EQ), value(std::move(v)) {}
+
+        // Named factories — preferred at callsites.
+        static Filter eq(std::string f, nlohmann::json v) {
+            return Filter{std::move(f), FilterOp::EQ, std::move(v)};
+        }
+        static Filter ne(std::string f, nlohmann::json v) {
+            return Filter{std::move(f), FilterOp::NE, std::move(v)};
+        }
+        static Filter gt(std::string f, nlohmann::json v) {
+            return Filter{std::move(f), FilterOp::GT, std::move(v)};
+        }
+        static Filter gte(std::string f, nlohmann::json v) {
+            return Filter{std::move(f), FilterOp::GTE, std::move(v)};
+        }
+        static Filter lt(std::string f, nlohmann::json v) {
+            return Filter{std::move(f), FilterOp::LT, std::move(v)};
+        }
+        static Filter lte(std::string f, nlohmann::json v) {
+            return Filter{std::move(f), FilterOp::LTE, std::move(v)};
+        }
+        static Filter in(std::string f, nlohmann::json array_value) {
+            return Filter{std::move(f), FilterOp::IN, std::move(array_value)};
+        }
+        static Filter contains(std::string f, nlohmann::json v) {
+            return Filter{std::move(f), FilterOp::CONTAINS, std::move(v)};
+        }
+        static Filter exists(std::string f, bool present = true) {
+            return Filter{std::move(f), FilterOp::EXISTS, present};
+        }
+        static Filter regex(std::string f, std::string pattern) {
+            return Filter{std::move(f), FilterOp::REGEX, std::move(pattern)};
+        }
+        static Filter search(std::string f, std::string term) {
+            return Filter{std::move(f), FilterOp::SEARCH, std::move(term)};
+        }
     };
 
     struct QueryOptions {
@@ -219,15 +272,14 @@ public:
 
     /**
      * Find documents matching a query.
+     *
+     * Pass `QueryOptions{}` for "no filters, default page size" — the
+     * no-options overload was removed in v2.1 because it silently scanned
+     * the whole collection and the named call site reads clearer.
      */
     [[nodiscard]] std::vector<nlohmann::json> find(const std::string& collection,
                                                    const QueryOptions& options);
 
-    /**
-     * Find all documents in a collection (no filters).
-     */
-    [[nodiscard]] std::vector<nlohmann::json> find(const std::string& collection);
-
     /**
      * Find documents with full metrics (including WAL fallback info).
      */

+ 6 - 17
client/include/smartbotic/database/document.hpp

@@ -1,27 +1,16 @@
 #pragma once
 
-// This header provides document types for client usage.
-// It's a simplified version focused on client-side operations.
+// Client-facing helper types that aren't part of the main Client interface.
+// The query-option / filter types live in client.hpp under `Client::Filter`,
+// `Client::FilterOp`, `Client::QueryOptions`. This header keeps only the
+// passive info structs (collection / health) so consumers can pull them
+// without dragging in the whole gRPC client header.
 
-#include <nlohmann/json.hpp>
-
-#include <optional>
+#include <cstdint>
 #include <string>
-#include <vector>
 
 namespace smartbotic::database {
 
-/**
- * Query options for find operations.
- */
-struct QueryOptions {
-    std::vector<std::pair<std::string, nlohmann::json>> filters;  // field, value pairs
-    std::string sortField;
-    bool sortDescending = false;
-    uint32_t limit = 100;
-    uint32_t offset = 0;
-};
-
 /**
  * Collection information.
  */

+ 0 - 4
client/src/client.cpp

@@ -1575,10 +1575,6 @@ std::vector<nlohmann::json> Client::find(const std::string& collection,
     return impl_->find(collection, options);
 }
 
-std::vector<nlohmann::json> Client::find(const std::string& collection) {
-    return impl_->find(collection, QueryOptions{});
-}
-
 Client::FindResult Client::findWithMetrics(const std::string& collection,
                                             const QueryOptions& options) {
     return impl_->findWithMetrics(collection, options);

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff