3 miesięcy temu | 132 commitów w main od tego wydania
Exposes the full filter operator set in the client API. The server has supported EQ/NE/GT/GTE/LT/LTE/IN/CONTAINS/EXISTS/REGEX/SEARCH all along — the client library was artificially forcing every filter to EQ. This release lifts that limitation.
Client::FilterOp enum mirroring the server-side proto FilterOpClient::Filter struct: {field, op, value} with a convenience 2-arg constructor (defaults to EQ)QueryOptions::filters changed type: vector<pair<string, json>> → vector<Filter>client.cpp (find, findWithMetrics, count) now pick up the operator from Filter::op instead of hardcoding EQusing Op = smartbotic::database::Client::FilterOp;
smartbotic::database::Client::QueryOptions opts;
opts.filters = {
{"age", Op::GTE, 18},
{"status", Op::NE, "deleted"},
{"tags", Op::CONTAINS, "admin"},
{"role", Op::IN, nlohmann::json::array({"admin", "moderator"})},
{"bio", Op::REGEX, "^senior "},
{"email", Op::EXISTS, true}
};
auto results = db.find("users", opts);
The 2-arg Filter(field, value) constructor defaults op = EQ, so existing callers using brace-init continue to compile and behave the same:
opts.filters = {{"status", "active"}, {"role", "admin"}}; // still works, both are EQ
The magic _search field name no longer auto-selects FILTER_OP_SEARCH. Use FilterOp::SEARCH explicitly:
// Before (v1.4.1)
opts.filters = {{"_search", "query"}}; // auto-promoted to SEARCH
// After (v1.4.2)
opts.filters = {{"_search", Op::SEARCH, "query"}}; // explicit
docs/integration-guide.md — Querying section updated with operator table and examplesFour .deb packages published to repository.smartbotics.ai (suite: trixie):
smartbotic-database_1.4.2-1_amd64.deblibsmartbotic-db-client_1.4.2-1_amd64.deblibsmartbotic-db-client-dev_1.4.2-1_amd64.debsmartbotic-db-cli_1.4.2-1_amd64.deb3 miesięcy temu | 133 commitów w main od tego wydania
Adds two new migration operation types — upsert_setting and generate_secret — for declarative settings seeding and secret generation during migrations. Patch release, fully backward compatible.
upsert_settingUpserts a single document into a collection. Useful for seeding default settings:
{
"type": "upsert_setting",
"collection": "settings",
"id": "feature_flags",
"data": {
"dark_mode_enabled": true,
"beta_features": false
}
}
generate_secretGenerates a cryptographically-random secret and stores it in a document — only if the document doesn't already exist (so re-running the migration doesn't rotate the secret):
{
"type": "generate_secret",
"collection": "settings",
"id": "jwt_signing_key",
"field": "value",
"bytes": 32,
"format": "hex"
}
Supported formats: hex, base64. Default bytes: 32.
Consumers (ShadowMan, CallerAI) can now declare their initial runtime configuration entirely in migrations, including secrets that must be stable across restarts but unique per deployment. No more "run this script after installing the package" step in deployment docs.
Four .deb packages published to repository.smartbotics.ai (suite: trixie):
smartbotic-database_1.4.1-1_amd64.deblibsmartbotic-db-client_1.4.1-1_amd64.deblibsmartbotic-db-client-dev_1.4.1-1_amd64.debsmartbotic-db-cli_1.4.1-1_amd64.deb3 miesięcy temu | 137 commitów w main od tego wydania
Client::update() now uses automatic optimistic locking with retry — transparent to callers. The silent data-loss race where two concurrent update() calls would blindly overwrite each other at the storage layer is gone.
Before v1.3.0:
client1: read doc (v1), modify, update() → blind write → v2
client2: read doc (v1), modify, update() → blind write → v3
# client1's write silently not recorded as a version-ordered change
After v1.3.0:
client1: update() → get(v1) → updateIfVersion(v1) → SUCCESS → v2
client2: update() → get(v2) → updateIfVersion(v2) → SUCCESS → v3
# ↑ sees v2 now, not stale v1 — writes are properly sequenced
Both writes still land, but now each is a proper version-checked write with history preserved. No writes are silently lost at the storage layer.
Client::update() internally:
_version, _id, _created_at, etc.) from the caller's dataget() to obtain the current versionupdateIfVersion() with that versionConfig::maxRetries timestrue on success, false if retries exhaustedThe caller just calls update() as before — no API change.
This is still "last writer wins" for complete document replacement. If two clients modify different fields via update(), the last winning retry overwrites the other's field change. For true partial-update safety, use patch() shipped in v1.4.0.
Callers can now pass the JSON from get() directly after modifying fields — the embedded _version etc. are automatically stripped before the write:
auto doc = db.get("users", "u1");
(*doc)["name"] = "Alice Smith";
(*doc)["role"] = "admin";
db.update("users", "u1", *doc); // _version, _id, _created_at etc. stripped internally
bool return and the same success/failure semanticsmaxRetries (default 3) controls retry countFour .deb packages published to repository.smartbotics.ai (suite: trixie):
smartbotic-database_1.3.0-1_amd64.deblibsmartbotic-db-client_1.3.0-1_amd64.deblibsmartbotic-db-client-dev_1.3.0-1_amd64.debsmartbotic-db-cli_1.3.0-1_amd64.deb