diff --git a/.github/workflows/rust.yaml b/.github/workflows/rust.yaml index 9a3f71a..97205fd 100644 --- a/.github/workflows/rust.yaml +++ b/.github/workflows/rust.yaml @@ -7,7 +7,7 @@ on: branches: [ "*" ] env: - cd gxtdb-rs && CARGO_TERM_COLOR: always + CARGO_TERM_COLOR: always jobs: build: @@ -20,7 +20,7 @@ jobs: - name: Install alsa and udev run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev - name: Build - run: cd gxtdb-rs && cargo build --all-features --release --verbose + run: cargo build --all-features --release --verbose test: runs-on: ubuntu-latest @@ -32,7 +32,7 @@ jobs: - name: Install alsa and udev run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev - name: tests - run: cd gxtdb-rs && cargo test --all-features -- --nocapture + run: cargo test --all-features -- --nocapture fmt: runs-on: ubuntu-latest @@ -40,7 +40,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: FMT - run: cd gxtdb-rs && cargo fmt -- --check + run: cargo fmt -- --check clippy: runs-on: ubuntu-latest @@ -54,4 +54,4 @@ jobs: - name: install-clippy run: rustup component add clippy - name: clippy - run: cd gxtdb-rs && cargo clippy --all-features -- -W clippy::all --deny "warnings" \ No newline at end of file + run: cargo clippy --all-features -- -W clippy::all --deny "warnings" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index f13f4b2..7531377 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[package]] name = "async-trait" @@ -16,7 +16,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -27,9 +27,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b70caf9f1b0c045f7da350636435b775a9733adf2df56e8aa2a29210fbc335d4" +checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", @@ -204,7 +204,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -266,9 +266,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" dependencies = [ "bytes", "fnv", @@ -433,15 +433,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.142" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "linux-raw-sys" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" @@ -522,22 +522,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.16", ] [[package]] @@ -570,9 +570,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" dependencies = [ "unicode-ident", ] @@ -633,9 +633,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" dependencies = [ "proc-macro2", ] @@ -696,9 +696,9 @@ checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" [[package]] name = "rustix" -version = "0.37.17" +version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc809f704c03a812ac71f22456c857be34185cac691a4316f27ab0f633bb9009" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ "bitflags", "errno", @@ -722,22 +722,22 @@ checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "serde" -version = "1.0.160" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -783,9 +783,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" dependencies = [ "proc-macro2", "quote", @@ -813,9 +813,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.28.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" +checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" dependencies = [ "autocfg", "bytes", @@ -846,7 +846,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -949,10 +949,11 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.38" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9cf6a813d3f40c88b0b6b6f29a5c95c6cdbf97c1f9cc53fb820200f5ad814d" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ + "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -967,14 +968,14 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", ] diff --git a/Cargo.toml b/Cargo.toml index 051ef40..3102591 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members=["gxtdb-rs"] \ No newline at end of file +members = ["gxtdb-rs"] \ No newline at end of file diff --git a/Makefile b/Makefile index 9dbdfb3..08a6011 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,21 @@ -all: - protoc --clojure_out=grpc-client,grpc-server:src --proto_path=resources resources/service.proto +fmt: + lein cljfmt fix + +kibit: + lein kibit --replace + +lint: fmt kibit + +proto: + protoc --clojure_out=grpc-client,grpc-server:src --proto_path=resources resources/transactions.proto resources/service.proto + +all: proto lint + +run: + lein run + +jar: + lein uberjar + +test: + lein test \ No newline at end of file diff --git a/gxtdb-rs/Cargo.lock b/gxtdb-rs/Cargo.lock deleted file mode 100644 index 1eaa0d6..0000000 --- a/gxtdb-rs/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "gxtdb-rs" -version = "0.1.0" diff --git a/gxtdb-rs/build.rs b/gxtdb-rs/build.rs index c9e7d42..1ec4950 100644 --- a/gxtdb-rs/build.rs +++ b/gxtdb-rs/build.rs @@ -2,6 +2,13 @@ fn main() -> Result<(), Box> { tonic_build::configure() .build_server(true) .compile_well_known_types(true) - .compile(&["../resources/service.proto"], &["../resources/"])?; + .include_file("mod.rs") + .compile( + &[ + "../resources/service.proto", + "../resources/transactions.proto", + ], + &["../resources/"], + )?; Ok(()) } diff --git a/gxtdb-rs/src/lib.rs b/gxtdb-rs/src/lib.rs index 01e9a56..62a0032 100644 --- a/gxtdb-rs/src/lib.rs +++ b/gxtdb-rs/src/lib.rs @@ -1,15 +1,18 @@ -pub mod api { - tonic::include_proto!("com.xtdb.protos"); +mod api { + #![allow(clippy::enum_variant_names)] + tonic::include_proto!("mod"); } -use api::{grpc_api_client::GrpcApiClient, Empty}; +pub use crate::api::com::xtdb::protos as proto_api; +use crate::api::com::xtdb::protos::{grpc_api_client::GrpcApiClient, Empty}; + use tonic::transport::Channel; -impl From for Option { - fn from(value: api::OptionString) -> Self { +impl From for Option { + fn from(value: proto_api::OptionString) -> Self { value.value.and_then(|val| match val { - api::option_string::Value::None(_) => None, - api::option_string::Value::Some(s) => Some(s), + proto_api::option_string::Value::None(_) => None, + proto_api::option_string::Value::Some(s) => Some(s), }) } } @@ -33,7 +36,9 @@ impl Client { } } - pub async fn status(&mut self) -> Result, tonic::Status> { + pub async fn status( + &mut self, + ) -> Result, tonic::Status> { let request = tonic::Request::new(Empty {}); self.client.status(request).await } diff --git a/gxtdb-rs/tests/lib.rs b/gxtdb-rs/tests/lib.rs index eb25db3..e423bde 100644 --- a/gxtdb-rs/tests/lib.rs +++ b/gxtdb-rs/tests/lib.rs @@ -1,12 +1,12 @@ -pub mod api { - tonic::include_proto!("com.xtdb.protos"); -} +// pub mod api { +// tonic::include_proto!("com.xtdb.protos"); +// } pub mod mock; #[tokio::test] async fn test_status_response() { - let expected = gxtdb_rs::api::StatusResponse::default(); + let expected = gxtdb_rs::proto_api::StatusResponse::default(); let mut client = mock::client().await; let status = client.status().await.unwrap(); assert_eq!(status.into_inner(), expected); diff --git a/gxtdb-rs/tests/mock.rs b/gxtdb-rs/tests/mock.rs index e49c427..b0c5cbe 100644 --- a/gxtdb-rs/tests/mock.rs +++ b/gxtdb-rs/tests/mock.rs @@ -1,5 +1,5 @@ -use gxtdb_rs::api; -use gxtdb_rs::api::grpc_api_server::{GrpcApi, GrpcApiServer}; +use gxtdb_rs::proto_api::grpc_api_server::{GrpcApi, GrpcApiServer}; +use gxtdb_rs::proto_api::{self}; use tonic::transport::{Endpoint, Server, Uri}; use tower::service_fn; @@ -10,9 +10,16 @@ pub struct ServerMock; impl GrpcApi for ServerMock { async fn status( &self, - _request: tonic::Request, - ) -> Result, tonic::Status> { - Ok(tonic::Response::new(api::StatusResponse::default())) + _request: tonic::Request, + ) -> Result, tonic::Status> { + Ok(tonic::Response::new(proto_api::StatusResponse::default())) + } + + async fn submit_tx( + &self, + _request: tonic::Request, + ) -> Result, tonic::Status> { + todo!() } } diff --git a/kreya/grpc/com/xtdb/protos/GrpcApi/SubmitTx-request.json b/kreya/grpc/com/xtdb/protos/GrpcApi/SubmitTx-request.json new file mode 100644 index 0000000..ff872e6 --- /dev/null +++ b/kreya/grpc/com/xtdb/protos/GrpcApi/SubmitTx-request.json @@ -0,0 +1,11 @@ +{ + "txOps": [ + { + "put": { + "xtId": "id1", + "idType":"Keyword", + "document": {"key": "value"} + } + } + ] +} \ No newline at end of file diff --git a/kreya/grpc/com/xtdb/protos/GrpcApi/SubmitTx.krop b/kreya/grpc/com/xtdb/protos/GrpcApi/SubmitTx.krop new file mode 100644 index 0000000..e31cf43 --- /dev/null +++ b/kreya/grpc/com/xtdb/protos/GrpcApi/SubmitTx.krop @@ -0,0 +1,12 @@ +{ + "details": { + "methodFqn": "com.xtdb.protos.GrpcApi.SubmitTx" + }, + "requests": [ + { + "location": "SubmitTx-request.json" + } + ], + "operationType": "unary", + "invokerName": "grpc" +} \ No newline at end of file diff --git a/project.clj b/project.clj index 7884540..a19a451 100644 --- a/project.clj +++ b/project.clj @@ -8,7 +8,7 @@ :plugins [[lein-cljfmt "0.9.2"] [lein-kibit "0.1.8"] [jonase/eastwood "1.4.0"]] - :dependencies [[org.clojure/clojure "1.10.3"] + :dependencies [[org.clojure/clojure "1.11.0"] [com.xtdb/xtdb-core "1.22.1"] [io.pedestal/pedestal.service "0.5.9"] [com.cognitect/anomalies "0.1.12"] diff --git a/resources/service.proto b/resources/service.proto index d37eede..9ac1e5d 100644 --- a/resources/service.proto +++ b/resources/service.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package com.xtdb.protos; +import "transactions.proto"; + message Empty { } message OptionString { @@ -23,4 +25,5 @@ message StatusResponse { service GrpcApi { rpc Status (Empty) returns (StatusResponse); + rpc SubmitTx (com.xtdb.protos.SubmitRequest) returns (com.xtdb.protos.SubmitResponse); } \ No newline at end of file diff --git a/resources/transactions.proto b/resources/transactions.proto new file mode 100644 index 0000000..2cdfc8b --- /dev/null +++ b/resources/transactions.proto @@ -0,0 +1,45 @@ +syntax = "proto3"; + +package com.xtdb.protos; +import "google/protobuf/struct.proto"; + + +message Transaction { + oneof transaction_type { + Put put = 1; + Delete delete = 2; + Evict evict = 3; + } +} + +enum IdType { + Uuid = 0; + Keyword = 1; + String = 2; + Int = 3; +} + +message Put { + IdType id_type = 1; + string xt_id = 2; + google.protobuf.Struct document = 3; +} + +message Delete { + string document_id = 1; + IdType id_type = 2; +} + +message Evict { + string document_id = 1; + IdType id_type = 2; +} + +message SubmitRequest { + repeated Transaction tx_ops = 1; +} + +message SubmitResponse { + string tx_time = 1; + int64 tx_id = 2; +} \ No newline at end of file diff --git a/src/com/google/protobuf.cljc b/src/com/google/protobuf.cljc new file mode 100644 index 0000000..04fc5e4 --- /dev/null +++ b/src/com/google/protobuf.cljc @@ -0,0 +1,714 @@ +;;;---------------------------------------------------------------------------------- +;;; Generated by protoc-gen-clojure. DO NOT EDIT +;;; +;;; Message Implementation of package com.google.protobuf +;;;---------------------------------------------------------------------------------- +(ns com.google.protobuf + (:require [protojure.protobuf.protocol :as pb] + [protojure.protobuf.serdes.core :as serdes.core] + [protojure.protobuf.serdes.complex :as serdes.complex] + [protojure.protobuf.serdes.utils :refer [tag-map]] + [protojure.protobuf.serdes.stream :as serdes.stream] + [com.google.protobuf :as com.google.protobuf] + [clojure.set :as set] + [clojure.spec.alpha :as s])) + +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- +;; Forward declarations +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- + +(declare cis->ListValue) +(declare ecis->ListValue) +(declare new-ListValue) +(declare cis->Empty) +(declare ecis->Empty) +(declare new-Empty) +(declare cis->Struct) +(declare ecis->Struct) +(declare new-Struct) +(declare cis->StatusResponse) +(declare ecis->StatusResponse) +(declare new-StatusResponse) +(declare cis->Evict) +(declare ecis->Evict) +(declare new-Evict) +(declare cis->Struct-FieldsEntry) +(declare ecis->Struct-FieldsEntry) +(declare new-Struct-FieldsEntry) +(declare cis->Put) +(declare ecis->Put) +(declare new-Put) +(declare cis->Delete) +(declare ecis->Delete) +(declare new-Delete) +(declare cis->SubmitRequest) +(declare ecis->SubmitRequest) +(declare new-SubmitRequest) +(declare cis->SubmitResponse) +(declare ecis->SubmitResponse) +(declare new-SubmitResponse) +(declare cis->Value) +(declare ecis->Value) +(declare new-Value) +(declare cis->Transaction) +(declare ecis->Transaction) +(declare new-Transaction) +(declare cis->OptionString) +(declare ecis->OptionString) +(declare new-OptionString) + +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- +;; Enumerations +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- + +;----------------------------------------------------------------------------- +; NullValue +;----------------------------------------------------------------------------- +(def NullValue-default :null-value) + +(def NullValue-val2label {0 :null-value}) + +(def NullValue-label2val (set/map-invert NullValue-val2label)) + +(defn cis->NullValue [is] + (let [val (serdes.core/cis->Enum is)] + (get NullValue-val2label val val))) + +(defn- get-NullValue [value] + {:pre [(or (int? value) (contains? NullValue-label2val value))]} + (get NullValue-label2val value value)) + +(defn write-NullValue + ([tag value os] (write-NullValue tag {:optimize false} value os)) + ([tag options value os] + (serdes.core/write-Enum tag options (get-NullValue value) os))) + +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- +;; Value-kind's oneof Implementations +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- + +(defn convert-Value-kind [origkeyval] + (cond + (get-in origkeyval [:kind :null-value]) origkeyval + (get-in origkeyval [:kind :number-value]) origkeyval + (get-in origkeyval [:kind :string-value]) origkeyval + (get-in origkeyval [:kind :bool-value]) origkeyval + (get-in origkeyval [:kind :struct-value]) (update-in origkeyval [:kind :struct-value] new-Struct) + (get-in origkeyval [:kind :list-value]) (update-in origkeyval [:kind :list-value] new-ListValue) + :default origkeyval)) + +(defn write-Value-kind [kind os] + (let [field (first kind) + k (when-not (nil? field) (key field)) + v (when-not (nil? field) (val field))] + (case k + :null-value (write-NullValue 1 {:optimize false} v os) + :number-value (serdes.core/write-Double 2 {:optimize false} v os) + :string-value (serdes.core/write-String 3 {:optimize false} v os) + :bool-value (serdes.core/write-Bool 4 {:optimize false} v os) + :struct-value (serdes.core/write-embedded 5 v os) + :list-value (serdes.core/write-embedded 6 v os) + nil))) + +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- +;; Transaction-transaction-type's oneof Implementations +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- + +(defn convert-Transaction-transaction-type [origkeyval] + (cond + (get-in origkeyval [:transaction-type :put]) (update-in origkeyval [:transaction-type :put] new-Put) + (get-in origkeyval [:transaction-type :delete]) (update-in origkeyval [:transaction-type :delete] new-Delete) + (get-in origkeyval [:transaction-type :evict]) (update-in origkeyval [:transaction-type :evict] new-Evict) + :default origkeyval)) + +(defn write-Transaction-transaction-type [transaction-type os] + (let [field (first transaction-type) + k (when-not (nil? field) (key field)) + v (when-not (nil? field) (val field))] + (case k + :put (serdes.core/write-embedded 1 v os) + :delete (serdes.core/write-embedded 2 v os) + :evict (serdes.core/write-embedded 3 v os) + nil))) + +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- +;; OptionString-value's oneof Implementations +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- + +(defn convert-OptionString-value [origkeyval] + (cond + (get-in origkeyval [:value :none]) (update-in origkeyval [:value :none] new-Empty) + (get-in origkeyval [:value :some]) origkeyval + :default origkeyval)) + +(defn write-OptionString-value [value os] + (let [field (first value) + k (when-not (nil? field) (key field)) + v (when-not (nil? field) (val field))] + (case k + :none (serdes.core/write-embedded 1 v os) + :some (serdes.core/write-String 2 {:optimize false} v os) + nil))) + +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- +;; Message Implementations +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- + +;----------------------------------------------------------------------------- +; ListValue +;----------------------------------------------------------------------------- +(defrecord ListValue-record [values] + pb/Writer + (serialize [this os] + (serdes.complex/write-repeated serdes.core/write-embedded 1 (:values this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.ListValue")) + +(s/def ::ListValue-spec (s/keys :opt-un [])) +(def ListValue-defaults {:values []}) + +(defn cis->ListValue + "CodedInputStream to ListValue" + [is] + (map->ListValue-record (tag-map ListValue-defaults (fn [tag index] (case index 1 [:values (serdes.complex/cis->repeated ecis->Value is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->ListValue + "Embedded CodedInputStream to ListValue" + [is] + (serdes.core/cis->embedded cis->ListValue is)) + +(defn new-ListValue + "Creates a new instance from a map, similar to map->ListValue except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::ListValue-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::ListValue-spec init))))]} + (-> (merge ListValue-defaults init) + (cond-> (some? (get init :values)) (update :values #(map new-Value %))) + (map->ListValue-record))) + +(defn pb->ListValue + "Protobuf to ListValue" + [input] + (cis->ListValue (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record ListValue-meta {:type "com.google.protobuf.ListValue" :decoder pb->ListValue}) + +;----------------------------------------------------------------------------- +; Empty +;----------------------------------------------------------------------------- +(defrecord Empty-record [] + pb/Writer + (serialize [this os]) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.Empty")) + +(s/def ::Empty-spec (s/keys :opt-un [])) +(def Empty-defaults {}) + +(defn cis->Empty + "CodedInputStream to Empty" + [is] + (map->Empty-record (tag-map Empty-defaults (fn [tag index] (case index [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Empty + "Embedded CodedInputStream to Empty" + [is] + (serdes.core/cis->embedded cis->Empty is)) + +(defn new-Empty + "Creates a new instance from a map, similar to map->Empty except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Empty-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Empty-spec init))))]} + (map->Empty-record (merge Empty-defaults init))) + +(defn pb->Empty + "Protobuf to Empty" + [input] + (cis->Empty (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Empty-meta {:type "com.google.protobuf.Empty" :decoder pb->Empty}) + +;----------------------------------------------------------------------------- +; Struct +;----------------------------------------------------------------------------- +(defrecord Struct-record [fields] + pb/Writer + (serialize [this os] + (serdes.complex/write-map new-Struct-FieldsEntry 1 (:fields this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.Struct")) + +(s/def ::Struct-spec (s/keys :opt-un [])) +(def Struct-defaults {:fields []}) + +(defn cis->Struct + "CodedInputStream to Struct" + [is] + (map->Struct-record (tag-map Struct-defaults (fn [tag index] (case index 1 [:fields (serdes.complex/cis->map ecis->Struct-FieldsEntry is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Struct + "Embedded CodedInputStream to Struct" + [is] + (serdes.core/cis->embedded cis->Struct is)) + +(defn new-Struct + "Creates a new instance from a map, similar to map->Struct except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Struct-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Struct-spec init))))]} + (map->Struct-record (merge Struct-defaults init))) + +(defn pb->Struct + "Protobuf to Struct" + [input] + (cis->Struct (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Struct-meta {:type "com.google.protobuf.Struct" :decoder pb->Struct}) + +;----------------------------------------------------------------------------- +; StatusResponse +;----------------------------------------------------------------------------- +(defrecord StatusResponse-record [version index-version kv-store estimate-num-keys size revision consumer-state] + pb/Writer + (serialize [this os] + (serdes.core/write-String 1 {:optimize true} (:version this) os) + (serdes.core/write-Int32 2 {:optimize true} (:index-version this) os) + (serdes.core/write-String 3 {:optimize true} (:kv-store this) os) + (serdes.core/write-Int32 4 {:optimize true} (:estimate-num-keys this) os) + (serdes.core/write-Int64 5 {:optimize true} (:size this) os) + (serdes.core/write-embedded 6 (:revision this) os) + (serdes.core/write-embedded 7 (:consumer-state this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.StatusResponse")) + +(s/def :com.google.protobuf.StatusResponse/version string?) +(s/def :com.google.protobuf.StatusResponse/index-version int?) +(s/def :com.google.protobuf.StatusResponse/kv-store string?) +(s/def :com.google.protobuf.StatusResponse/estimate-num-keys int?) +(s/def :com.google.protobuf.StatusResponse/size int?) + +(s/def ::StatusResponse-spec (s/keys :opt-un [:com.google.protobuf.StatusResponse/version :com.google.protobuf.StatusResponse/index-version :com.google.protobuf.StatusResponse/kv-store :com.google.protobuf.StatusResponse/estimate-num-keys :com.google.protobuf.StatusResponse/size])) +(def StatusResponse-defaults {:version "" :index-version 0 :kv-store "" :estimate-num-keys 0 :size 0}) + +(defn cis->StatusResponse + "CodedInputStream to StatusResponse" + [is] + (map->StatusResponse-record (tag-map StatusResponse-defaults (fn [tag index] (case index 1 [:version (serdes.core/cis->String is)] 2 [:index-version (serdes.core/cis->Int32 is)] 3 [:kv-store (serdes.core/cis->String is)] 4 [:estimate-num-keys (serdes.core/cis->Int32 is)] 5 [:size (serdes.core/cis->Int64 is)] 6 [:revision (ecis->OptionString is)] 7 [:consumer-state (ecis->OptionString is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->StatusResponse + "Embedded CodedInputStream to StatusResponse" + [is] + (serdes.core/cis->embedded cis->StatusResponse is)) + +(defn new-StatusResponse + "Creates a new instance from a map, similar to map->StatusResponse except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::StatusResponse-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::StatusResponse-spec init))))]} + (-> (merge StatusResponse-defaults init) + (cond-> (some? (get init :revision)) (update :revision new-OptionString)) + (cond-> (some? (get init :consumer-state)) (update :consumer-state new-OptionString)) + (map->StatusResponse-record))) + +(defn pb->StatusResponse + "Protobuf to StatusResponse" + [input] + (cis->StatusResponse (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record StatusResponse-meta {:type "com.google.protobuf.StatusResponse" :decoder pb->StatusResponse}) + +;----------------------------------------------------------------------------- +; Evict +;----------------------------------------------------------------------------- +(defrecord Evict-record [document-id] + pb/Writer + (serialize [this os] + (serdes.core/write-String 1 {:optimize true} (:document-id this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.Evict")) + +(s/def :com.google.protobuf.Evict/document-id string?) +(s/def ::Evict-spec (s/keys :opt-un [:com.google.protobuf.Evict/document-id])) +(def Evict-defaults {:document-id ""}) + +(defn cis->Evict + "CodedInputStream to Evict" + [is] + (map->Evict-record (tag-map Evict-defaults (fn [tag index] (case index 1 [:document-id (serdes.core/cis->String is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Evict + "Embedded CodedInputStream to Evict" + [is] + (serdes.core/cis->embedded cis->Evict is)) + +(defn new-Evict + "Creates a new instance from a map, similar to map->Evict except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Evict-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Evict-spec init))))]} + (map->Evict-record (merge Evict-defaults init))) + +(defn pb->Evict + "Protobuf to Evict" + [input] + (cis->Evict (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Evict-meta {:type "com.google.protobuf.Evict" :decoder pb->Evict}) + +;----------------------------------------------------------------------------- +; Struct-FieldsEntry +;----------------------------------------------------------------------------- +(defrecord Struct-FieldsEntry-record [key value] + pb/Writer + (serialize [this os] + (serdes.core/write-String 1 {:optimize true} (:key this) os) + (serdes.core/write-embedded 2 (:value this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.Struct-FieldsEntry")) + +(s/def :com.google.protobuf.Struct-FieldsEntry/key string?) + +(s/def ::Struct-FieldsEntry-spec (s/keys :opt-un [:com.google.protobuf.Struct-FieldsEntry/key])) +(def Struct-FieldsEntry-defaults {:key ""}) + +(defn cis->Struct-FieldsEntry + "CodedInputStream to Struct-FieldsEntry" + [is] + (map->Struct-FieldsEntry-record (tag-map Struct-FieldsEntry-defaults (fn [tag index] (case index 1 [:key (serdes.core/cis->String is)] 2 [:value (ecis->Value is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Struct-FieldsEntry + "Embedded CodedInputStream to Struct-FieldsEntry" + [is] + (serdes.core/cis->embedded cis->Struct-FieldsEntry is)) + +(defn new-Struct-FieldsEntry + "Creates a new instance from a map, similar to map->Struct-FieldsEntry except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Struct-FieldsEntry-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Struct-FieldsEntry-spec init))))]} + (-> (merge Struct-FieldsEntry-defaults init) + (cond-> (some? (get init :value)) (update :value new-Value)) + (map->Struct-FieldsEntry-record))) + +(defn pb->Struct-FieldsEntry + "Protobuf to Struct-FieldsEntry" + [input] + (cis->Struct-FieldsEntry (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Struct-FieldsEntry-meta {:type "com.google.protobuf.Struct-FieldsEntry" :decoder pb->Struct-FieldsEntry}) + +;----------------------------------------------------------------------------- +; Put +;----------------------------------------------------------------------------- +(defrecord Put-record [xt-id document] + pb/Writer + (serialize [this os] + (serdes.core/write-String 1 {:optimize true} (:xt-id this) os) + (serdes.core/write-embedded 2 (:document this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.Put")) + +(s/def :com.google.protobuf.Put/xt-id string?) + +(s/def ::Put-spec (s/keys :opt-un [:com.google.protobuf.Put/xt-id])) +(def Put-defaults {:xt-id ""}) + +(defn cis->Put + "CodedInputStream to Put" + [is] + (map->Put-record (tag-map Put-defaults (fn [tag index] (case index 1 [:xt-id (serdes.core/cis->String is)] 2 [:document (ecis->Value is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Put + "Embedded CodedInputStream to Put" + [is] + (serdes.core/cis->embedded cis->Put is)) + +(defn new-Put + "Creates a new instance from a map, similar to map->Put except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Put-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Put-spec init))))]} + (-> (merge Put-defaults init) + (cond-> (some? (get init :document)) (update :document new-Value)) + (map->Put-record))) + +(defn pb->Put + "Protobuf to Put" + [input] + (cis->Put (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Put-meta {:type "com.google.protobuf.Put" :decoder pb->Put}) + +;----------------------------------------------------------------------------- +; Delete +;----------------------------------------------------------------------------- +(defrecord Delete-record [document-id] + pb/Writer + (serialize [this os] + (serdes.core/write-String 1 {:optimize true} (:document-id this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.Delete")) + +(s/def :com.google.protobuf.Delete/document-id string?) +(s/def ::Delete-spec (s/keys :opt-un [:com.google.protobuf.Delete/document-id])) +(def Delete-defaults {:document-id ""}) + +(defn cis->Delete + "CodedInputStream to Delete" + [is] + (map->Delete-record (tag-map Delete-defaults (fn [tag index] (case index 1 [:document-id (serdes.core/cis->String is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Delete + "Embedded CodedInputStream to Delete" + [is] + (serdes.core/cis->embedded cis->Delete is)) + +(defn new-Delete + "Creates a new instance from a map, similar to map->Delete except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Delete-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Delete-spec init))))]} + (map->Delete-record (merge Delete-defaults init))) + +(defn pb->Delete + "Protobuf to Delete" + [input] + (cis->Delete (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Delete-meta {:type "com.google.protobuf.Delete" :decoder pb->Delete}) + +;----------------------------------------------------------------------------- +; SubmitRequest +;----------------------------------------------------------------------------- +(defrecord SubmitRequest-record [tx-ops] + pb/Writer + (serialize [this os] + (serdes.complex/write-repeated serdes.core/write-embedded 1 (:tx-ops this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.SubmitRequest")) + +(s/def ::SubmitRequest-spec (s/keys :opt-un [])) +(def SubmitRequest-defaults {:tx-ops []}) + +(defn cis->SubmitRequest + "CodedInputStream to SubmitRequest" + [is] + (map->SubmitRequest-record (tag-map SubmitRequest-defaults (fn [tag index] (case index 1 [:tx-ops (serdes.complex/cis->repeated ecis->Transaction is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->SubmitRequest + "Embedded CodedInputStream to SubmitRequest" + [is] + (serdes.core/cis->embedded cis->SubmitRequest is)) + +(defn new-SubmitRequest + "Creates a new instance from a map, similar to map->SubmitRequest except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::SubmitRequest-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::SubmitRequest-spec init))))]} + (-> (merge SubmitRequest-defaults init) + (cond-> (some? (get init :tx-ops)) (update :tx-ops #(map new-Transaction %))) + (map->SubmitRequest-record))) + +(defn pb->SubmitRequest + "Protobuf to SubmitRequest" + [input] + (cis->SubmitRequest (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record SubmitRequest-meta {:type "com.google.protobuf.SubmitRequest" :decoder pb->SubmitRequest}) + +;----------------------------------------------------------------------------- +; SubmitResponse +;----------------------------------------------------------------------------- +(defrecord SubmitResponse-record [tx-time tx-id] + pb/Writer + (serialize [this os] + (serdes.core/write-String 1 {:optimize true} (:tx-time this) os) + (serdes.core/write-Int64 2 {:optimize true} (:tx-id this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.SubmitResponse")) + +(s/def :com.google.protobuf.SubmitResponse/tx-time string?) +(s/def :com.google.protobuf.SubmitResponse/tx-id int?) +(s/def ::SubmitResponse-spec (s/keys :opt-un [:com.google.protobuf.SubmitResponse/tx-time :com.google.protobuf.SubmitResponse/tx-id])) +(def SubmitResponse-defaults {:tx-time "" :tx-id 0}) + +(defn cis->SubmitResponse + "CodedInputStream to SubmitResponse" + [is] + (map->SubmitResponse-record (tag-map SubmitResponse-defaults (fn [tag index] (case index 1 [:tx-time (serdes.core/cis->String is)] 2 [:tx-id (serdes.core/cis->Int64 is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->SubmitResponse + "Embedded CodedInputStream to SubmitResponse" + [is] + (serdes.core/cis->embedded cis->SubmitResponse is)) + +(defn new-SubmitResponse + "Creates a new instance from a map, similar to map->SubmitResponse except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::SubmitResponse-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::SubmitResponse-spec init))))]} + (map->SubmitResponse-record (merge SubmitResponse-defaults init))) + +(defn pb->SubmitResponse + "Protobuf to SubmitResponse" + [input] + (cis->SubmitResponse (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record SubmitResponse-meta {:type "com.google.protobuf.SubmitResponse" :decoder pb->SubmitResponse}) + +;----------------------------------------------------------------------------- +; Value +;----------------------------------------------------------------------------- +(defrecord Value-record [kind] + pb/Writer + (serialize [this os] + (write-Value-kind (:kind this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.Value")) + +(s/def ::Value-spec (s/keys :opt-un [])) +(def Value-defaults {}) + +(defn cis->Value + "CodedInputStream to Value" + [is] + (map->Value-record (tag-map Value-defaults (fn [tag index] (case index 1 [:kind {:null-value (cis->NullValue is)}] 2 [:kind {:number-value (serdes.core/cis->Double is)}] 3 [:kind {:string-value (serdes.core/cis->String is)}] 4 [:kind {:bool-value (serdes.core/cis->Bool is)}] 5 [:kind {:struct-value (ecis->Struct is)}] 6 [:kind {:list-value (ecis->ListValue is)}] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Value + "Embedded CodedInputStream to Value" + [is] + (serdes.core/cis->embedded cis->Value is)) + +(defn new-Value + "Creates a new instance from a map, similar to map->Value except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Value-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Value-spec init))))]} + (-> (merge Value-defaults init) + (convert-Value-kind) + (map->Value-record))) + +(defn pb->Value + "Protobuf to Value" + [input] + (cis->Value (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Value-meta {:type "com.google.protobuf.Value" :decoder pb->Value}) + +;----------------------------------------------------------------------------- +; Transaction +;----------------------------------------------------------------------------- +(defrecord Transaction-record [transaction-type] + pb/Writer + (serialize [this os] + (write-Transaction-transaction-type (:transaction-type this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.Transaction")) + +(s/def ::Transaction-spec (s/keys :opt-un [])) +(def Transaction-defaults {}) + +(defn cis->Transaction + "CodedInputStream to Transaction" + [is] + (map->Transaction-record (tag-map Transaction-defaults (fn [tag index] (case index 1 [:transaction-type {:put (ecis->Put is)}] 2 [:transaction-type {:delete (ecis->Delete is)}] 3 [:transaction-type {:evict (ecis->Evict is)}] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Transaction + "Embedded CodedInputStream to Transaction" + [is] + (serdes.core/cis->embedded cis->Transaction is)) + +(defn new-Transaction + "Creates a new instance from a map, similar to map->Transaction except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Transaction-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Transaction-spec init))))]} + (-> (merge Transaction-defaults init) + (convert-Transaction-transaction-type) + (map->Transaction-record))) + +(defn pb->Transaction + "Protobuf to Transaction" + [input] + (cis->Transaction (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Transaction-meta {:type "com.google.protobuf.Transaction" :decoder pb->Transaction}) + +;----------------------------------------------------------------------------- +; OptionString +;----------------------------------------------------------------------------- +(defrecord OptionString-record [value] + pb/Writer + (serialize [this os] + (write-OptionString-value (:value this) os)) + pb/TypeReflection + (gettype [this] + "com.google.protobuf.OptionString")) + +(s/def ::OptionString-spec (s/keys :opt-un [])) +(def OptionString-defaults {}) + +(defn cis->OptionString + "CodedInputStream to OptionString" + [is] + (map->OptionString-record (tag-map OptionString-defaults (fn [tag index] (case index 1 [:value {:none (ecis->Empty is)}] 2 [:value {:some (serdes.core/cis->String is)}] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->OptionString + "Embedded CodedInputStream to OptionString" + [is] + (serdes.core/cis->embedded cis->OptionString is)) + +(defn new-OptionString + "Creates a new instance from a map, similar to map->OptionString except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::OptionString-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::OptionString-spec init))))]} + (-> (merge OptionString-defaults init) + (convert-OptionString-value) + (map->OptionString-record))) + +(defn pb->OptionString + "Protobuf to OptionString" + [input] + (cis->OptionString (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record OptionString-meta {:type "com.google.protobuf.OptionString" :decoder pb->OptionString}) + diff --git a/src/com/google/protobuf/GrpcApi/client.cljc b/src/com/google/protobuf/GrpcApi/client.cljc new file mode 100644 index 0000000..f48f01a --- /dev/null +++ b/src/com/google/protobuf/GrpcApi/client.cljc @@ -0,0 +1,43 @@ +;;;---------------------------------------------------------------------------------- +;;; Generated by protoc-gen-clojure. DO NOT EDIT +;;; +;;; GRPC com.google.protobuf.GrpcApi Client Implementation +;;;---------------------------------------------------------------------------------- +(ns com.google.protobuf.GrpcApi.client + (:require [com.google.protobuf :refer :all] + [com.google.protobuf :as com.google.protobuf] + [clojure.core.async :as async] + [protojure.grpc.client.utils :refer [send-unary-params invoke-unary]] + [promesa.core :as p] + [protojure.grpc.client.api :as grpc])) + +;----------------------------------------------------------------------------- +; GRPC Client Implementation +;----------------------------------------------------------------------------- + +(def GrpcApi-service-name "com.xtdb.protos.GrpcApi") + +(defn Status + ([client params] (Status client {} params)) + ([client metadata params] + (let [input (async/chan 1) + output (async/chan 1) + desc {:service "com.xtdb.protos.GrpcApi" + :method "Status" + :input {:f com.google.protobuf/new-Empty :ch input} + :output {:f com.google.protobuf/pb->StatusResponse :ch output} + :metadata metadata}] + (p/then (send-unary-params input params) (fn [_] (invoke-unary client desc output)))))) + +(defn SubmitTx + ([client params] (SubmitTx client {} params)) + ([client metadata params] + (let [input (async/chan 1) + output (async/chan 1) + desc {:service "com.xtdb.protos.GrpcApi" + :method "SubmitTx" + :input {:f com.google.protobuf/new-SubmitRequest :ch input} + :output {:f com.google.protobuf/pb->SubmitResponse :ch output} + :metadata metadata}] + (p/then (send-unary-params input params) (fn [_] (invoke-unary client desc output)))))) + diff --git a/src/com/google/protobuf/GrpcApi/server.cljc b/src/com/google/protobuf/GrpcApi/server.cljc new file mode 100644 index 0000000..3efdeb8 --- /dev/null +++ b/src/com/google/protobuf/GrpcApi/server.cljc @@ -0,0 +1,28 @@ +;;;---------------------------------------------------------------------------------- +;;; Generated by protoc-gen-clojure. DO NOT EDIT +;;; +;;; GRPC com.google.protobuf.GrpcApi Service Implementation +;;;---------------------------------------------------------------------------------- +(ns com.google.protobuf.GrpcApi.server + (:require [com.google.protobuf :refer :all] + [com.google.protobuf :as com.google.protobuf])) + +;----------------------------------------------------------------------------- +; GRPC GrpcApi +;----------------------------------------------------------------------------- +(defprotocol Service + (Status [this param]) + (SubmitTx [this param])) + +(def GrpcApi-service-name "com.xtdb.protos.GrpcApi") + +(defn- Status-dispatch + [ctx request] + (Status ctx request)) +(defn- SubmitTx-dispatch + [ctx request] + (SubmitTx ctx request)) + +(def ^:const rpc-metadata + [{:pkg "com.xtdb.protos" :service "GrpcApi" :method "Status" :method-fn Status-dispatch :server-streaming false :client-streaming false :input pb->Empty :output new-StatusResponse} + {:pkg "com.xtdb.protos" :service "GrpcApi" :method "SubmitTx" :method-fn SubmitTx-dispatch :server-streaming false :client-streaming false :input pb->SubmitRequest :output new-SubmitResponse}]) diff --git a/src/com/xtdb/protos.cljc b/src/com/xtdb/protos.cljc index 04a01eb..4256bc2 100644 --- a/src/com/xtdb/protos.cljc +++ b/src/com/xtdb/protos.cljc @@ -9,6 +9,8 @@ [protojure.protobuf.serdes.complex :as serdes.complex] [protojure.protobuf.serdes.utils :refer [tag-map]] [protojure.protobuf.serdes.stream :as serdes.stream] + [com.xtdb.protos :as com.xtdb.protos] + [com.google.protobuf :as com.google.protobuf] [clojure.set :as set] [clojure.spec.alpha :as s])) @@ -21,12 +23,84 @@ (declare cis->Empty) (declare ecis->Empty) (declare new-Empty) -(declare cis->OptionString) -(declare ecis->OptionString) -(declare new-OptionString) (declare cis->StatusResponse) (declare ecis->StatusResponse) (declare new-StatusResponse) +(declare cis->Evict) +(declare ecis->Evict) +(declare new-Evict) +(declare cis->Put) +(declare ecis->Put) +(declare new-Put) +(declare cis->Delete) +(declare ecis->Delete) +(declare new-Delete) +(declare cis->SubmitRequest) +(declare ecis->SubmitRequest) +(declare new-SubmitRequest) +(declare cis->SubmitResponse) +(declare ecis->SubmitResponse) +(declare new-SubmitResponse) +(declare cis->Transaction) +(declare ecis->Transaction) +(declare new-Transaction) +(declare cis->OptionString) +(declare ecis->OptionString) +(declare new-OptionString) + +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- +;; Enumerations +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- + +;----------------------------------------------------------------------------- +; IdType +;----------------------------------------------------------------------------- +(def IdType-default :uuid) + +(def IdType-val2label {0 :uuid + 1 :keyword + 2 :string + 3 :int}) + +(def IdType-label2val (set/map-invert IdType-val2label)) + +(defn cis->IdType [is] + (let [val (serdes.core/cis->Enum is)] + (get IdType-val2label val val))) + +(defn- get-IdType [value] + {:pre [(or (int? value) (contains? IdType-label2val value))]} + (get IdType-label2val value value)) + +(defn write-IdType + ([tag value os] (write-IdType tag {:optimize false} value os)) + ([tag options value os] + (serdes.core/write-Enum tag options (get-IdType value) os))) + +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- +;; Transaction-transaction-type's oneof Implementations +;;---------------------------------------------------------------------------------- +;;---------------------------------------------------------------------------------- + +(defn convert-Transaction-transaction-type [origkeyval] + (cond + (get-in origkeyval [:transaction-type :put]) (update-in origkeyval [:transaction-type :put] new-Put) + (get-in origkeyval [:transaction-type :delete]) (update-in origkeyval [:transaction-type :delete] new-Delete) + (get-in origkeyval [:transaction-type :evict]) (update-in origkeyval [:transaction-type :evict] new-Evict) + :default origkeyval)) + +(defn write-Transaction-transaction-type [transaction-type os] + (let [field (first transaction-type) + k (when-not (nil? field) (key field)) + v (when-not (nil? field) (val field))] + (case k + :put (serdes.core/write-embedded 1 v os) + :delete (serdes.core/write-embedded 2 v os) + :evict (serdes.core/write-embedded 3 v os) + nil))) ;;---------------------------------------------------------------------------------- ;;---------------------------------------------------------------------------------- @@ -93,47 +167,6 @@ (def ^:protojure.protobuf.any/record Empty-meta {:type "com.xtdb.protos.Empty" :decoder pb->Empty}) -;----------------------------------------------------------------------------- -; OptionString -;----------------------------------------------------------------------------- -(defrecord OptionString-record [value] - pb/Writer - (serialize [this os] - (write-OptionString-value (:value this) os)) - pb/TypeReflection - (gettype [this] - "com.xtdb.protos.OptionString")) - -(s/def ::OptionString-spec (s/keys :opt-un [])) -(def OptionString-defaults {}) - -(defn cis->OptionString - "CodedInputStream to OptionString" - [is] - (map->OptionString-record (tag-map OptionString-defaults (fn [tag index] (case index 1 [:value {:none (ecis->Empty is)}] 2 [:value {:some (serdes.core/cis->String is)}] [index (serdes.core/cis->undefined tag is)])) is))) - -(defn ecis->OptionString - "Embedded CodedInputStream to OptionString" - [is] - (serdes.core/cis->embedded cis->OptionString is)) - -(defn new-OptionString - "Creates a new instance from a map, similar to map->OptionString except that - it properly accounts for nested messages, when applicable. - " - [init] - {:pre [(if (s/valid? ::OptionString-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::OptionString-spec init))))]} - (-> (merge OptionString-defaults init) - (convert-OptionString-value) - (map->OptionString-record))) - -(defn pb->OptionString - "Protobuf to OptionString" - [input] - (cis->OptionString (serdes.stream/new-cis input))) - -(def ^:protojure.protobuf.any/record OptionString-meta {:type "com.xtdb.protos.OptionString" :decoder pb->OptionString}) - ;----------------------------------------------------------------------------- ; StatusResponse ;----------------------------------------------------------------------------- @@ -188,3 +221,298 @@ (def ^:protojure.protobuf.any/record StatusResponse-meta {:type "com.xtdb.protos.StatusResponse" :decoder pb->StatusResponse}) +;----------------------------------------------------------------------------- +; Evict +;----------------------------------------------------------------------------- +(defrecord Evict-record [document-id id-type] + pb/Writer + (serialize [this os] + (serdes.core/write-String 1 {:optimize true} (:document-id this) os) + (write-IdType 2 {:optimize true} (:id-type this) os)) + pb/TypeReflection + (gettype [this] + "com.xtdb.protos.Evict")) + +(s/def :com.xtdb.protos.Evict/document-id string?) +(s/def :com.xtdb.protos.Evict/id-type (s/or :keyword keyword? :int int?)) +(s/def ::Evict-spec (s/keys :opt-un [:com.xtdb.protos.Evict/document-id :com.xtdb.protos.Evict/id-type])) +(def Evict-defaults {:document-id "" :id-type IdType-default}) + +(defn cis->Evict + "CodedInputStream to Evict" + [is] + (map->Evict-record (tag-map Evict-defaults (fn [tag index] (case index 1 [:document-id (serdes.core/cis->String is)] 2 [:id-type (cis->IdType is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Evict + "Embedded CodedInputStream to Evict" + [is] + (serdes.core/cis->embedded cis->Evict is)) + +(defn new-Evict + "Creates a new instance from a map, similar to map->Evict except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Evict-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Evict-spec init))))]} + (map->Evict-record (merge Evict-defaults init))) + +(defn pb->Evict + "Protobuf to Evict" + [input] + (cis->Evict (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Evict-meta {:type "com.xtdb.protos.Evict" :decoder pb->Evict}) + +;----------------------------------------------------------------------------- +; Put +;----------------------------------------------------------------------------- +(defrecord Put-record [id-type xt-id document] + pb/Writer + (serialize [this os] + (write-IdType 1 {:optimize true} (:id-type this) os) + (serdes.core/write-String 2 {:optimize true} (:xt-id this) os) + (serdes.core/write-embedded 3 (:document this) os)) + pb/TypeReflection + (gettype [this] + "com.xtdb.protos.Put")) + +(s/def :com.xtdb.protos.Put/id-type (s/or :keyword keyword? :int int?)) +(s/def :com.xtdb.protos.Put/xt-id string?) + +(s/def ::Put-spec (s/keys :opt-un [:com.xtdb.protos.Put/id-type :com.xtdb.protos.Put/xt-id])) +(def Put-defaults {:id-type IdType-default :xt-id ""}) + +(defn cis->Put + "CodedInputStream to Put" + [is] + (map->Put-record (tag-map Put-defaults (fn [tag index] (case index 1 [:id-type (cis->IdType is)] 2 [:xt-id (serdes.core/cis->String is)] 3 [:document (com.google.protobuf/ecis->Struct is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Put + "Embedded CodedInputStream to Put" + [is] + (serdes.core/cis->embedded cis->Put is)) + +(defn new-Put + "Creates a new instance from a map, similar to map->Put except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Put-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Put-spec init))))]} + (-> (merge Put-defaults init) + (cond-> (some? (get init :document)) (update :document com.google.protobuf/new-Struct)) + (map->Put-record))) + +(defn pb->Put + "Protobuf to Put" + [input] + (cis->Put (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Put-meta {:type "com.xtdb.protos.Put" :decoder pb->Put}) + +;----------------------------------------------------------------------------- +; Delete +;----------------------------------------------------------------------------- +(defrecord Delete-record [document-id id-type] + pb/Writer + (serialize [this os] + (serdes.core/write-String 1 {:optimize true} (:document-id this) os) + (write-IdType 2 {:optimize true} (:id-type this) os)) + pb/TypeReflection + (gettype [this] + "com.xtdb.protos.Delete")) + +(s/def :com.xtdb.protos.Delete/document-id string?) +(s/def :com.xtdb.protos.Delete/id-type (s/or :keyword keyword? :int int?)) +(s/def ::Delete-spec (s/keys :opt-un [:com.xtdb.protos.Delete/document-id :com.xtdb.protos.Delete/id-type])) +(def Delete-defaults {:document-id "" :id-type IdType-default}) + +(defn cis->Delete + "CodedInputStream to Delete" + [is] + (map->Delete-record (tag-map Delete-defaults (fn [tag index] (case index 1 [:document-id (serdes.core/cis->String is)] 2 [:id-type (cis->IdType is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Delete + "Embedded CodedInputStream to Delete" + [is] + (serdes.core/cis->embedded cis->Delete is)) + +(defn new-Delete + "Creates a new instance from a map, similar to map->Delete except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Delete-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Delete-spec init))))]} + (map->Delete-record (merge Delete-defaults init))) + +(defn pb->Delete + "Protobuf to Delete" + [input] + (cis->Delete (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Delete-meta {:type "com.xtdb.protos.Delete" :decoder pb->Delete}) + +;----------------------------------------------------------------------------- +; SubmitRequest +;----------------------------------------------------------------------------- +(defrecord SubmitRequest-record [tx-ops] + pb/Writer + (serialize [this os] + (serdes.complex/write-repeated serdes.core/write-embedded 1 (:tx-ops this) os)) + pb/TypeReflection + (gettype [this] + "com.xtdb.protos.SubmitRequest")) + +(s/def ::SubmitRequest-spec (s/keys :opt-un [])) +(def SubmitRequest-defaults {:tx-ops []}) + +(defn cis->SubmitRequest + "CodedInputStream to SubmitRequest" + [is] + (map->SubmitRequest-record (tag-map SubmitRequest-defaults (fn [tag index] (case index 1 [:tx-ops (serdes.complex/cis->repeated ecis->Transaction is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->SubmitRequest + "Embedded CodedInputStream to SubmitRequest" + [is] + (serdes.core/cis->embedded cis->SubmitRequest is)) + +(defn new-SubmitRequest + "Creates a new instance from a map, similar to map->SubmitRequest except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::SubmitRequest-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::SubmitRequest-spec init))))]} + (-> (merge SubmitRequest-defaults init) + (cond-> (some? (get init :tx-ops)) (update :tx-ops #(map new-Transaction %))) + (map->SubmitRequest-record))) + +(defn pb->SubmitRequest + "Protobuf to SubmitRequest" + [input] + (cis->SubmitRequest (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record SubmitRequest-meta {:type "com.xtdb.protos.SubmitRequest" :decoder pb->SubmitRequest}) + +;----------------------------------------------------------------------------- +; SubmitResponse +;----------------------------------------------------------------------------- +(defrecord SubmitResponse-record [tx-time tx-id] + pb/Writer + (serialize [this os] + (serdes.core/write-String 1 {:optimize true} (:tx-time this) os) + (serdes.core/write-Int64 2 {:optimize true} (:tx-id this) os)) + pb/TypeReflection + (gettype [this] + "com.xtdb.protos.SubmitResponse")) + +(s/def :com.xtdb.protos.SubmitResponse/tx-time string?) +(s/def :com.xtdb.protos.SubmitResponse/tx-id int?) +(s/def ::SubmitResponse-spec (s/keys :opt-un [:com.xtdb.protos.SubmitResponse/tx-time :com.xtdb.protos.SubmitResponse/tx-id])) +(def SubmitResponse-defaults {:tx-time "" :tx-id 0}) + +(defn cis->SubmitResponse + "CodedInputStream to SubmitResponse" + [is] + (map->SubmitResponse-record (tag-map SubmitResponse-defaults (fn [tag index] (case index 1 [:tx-time (serdes.core/cis->String is)] 2 [:tx-id (serdes.core/cis->Int64 is)] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->SubmitResponse + "Embedded CodedInputStream to SubmitResponse" + [is] + (serdes.core/cis->embedded cis->SubmitResponse is)) + +(defn new-SubmitResponse + "Creates a new instance from a map, similar to map->SubmitResponse except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::SubmitResponse-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::SubmitResponse-spec init))))]} + (map->SubmitResponse-record (merge SubmitResponse-defaults init))) + +(defn pb->SubmitResponse + "Protobuf to SubmitResponse" + [input] + (cis->SubmitResponse (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record SubmitResponse-meta {:type "com.xtdb.protos.SubmitResponse" :decoder pb->SubmitResponse}) + +;----------------------------------------------------------------------------- +; Transaction +;----------------------------------------------------------------------------- +(defrecord Transaction-record [transaction-type] + pb/Writer + (serialize [this os] + (write-Transaction-transaction-type (:transaction-type this) os)) + pb/TypeReflection + (gettype [this] + "com.xtdb.protos.Transaction")) + +(s/def ::Transaction-spec (s/keys :opt-un [])) +(def Transaction-defaults {}) + +(defn cis->Transaction + "CodedInputStream to Transaction" + [is] + (map->Transaction-record (tag-map Transaction-defaults (fn [tag index] (case index 1 [:transaction-type {:put (ecis->Put is)}] 2 [:transaction-type {:delete (ecis->Delete is)}] 3 [:transaction-type {:evict (ecis->Evict is)}] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->Transaction + "Embedded CodedInputStream to Transaction" + [is] + (serdes.core/cis->embedded cis->Transaction is)) + +(defn new-Transaction + "Creates a new instance from a map, similar to map->Transaction except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::Transaction-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::Transaction-spec init))))]} + (-> (merge Transaction-defaults init) + (convert-Transaction-transaction-type) + (map->Transaction-record))) + +(defn pb->Transaction + "Protobuf to Transaction" + [input] + (cis->Transaction (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record Transaction-meta {:type "com.xtdb.protos.Transaction" :decoder pb->Transaction}) + +;----------------------------------------------------------------------------- +; OptionString +;----------------------------------------------------------------------------- +(defrecord OptionString-record [value] + pb/Writer + (serialize [this os] + (write-OptionString-value (:value this) os)) + pb/TypeReflection + (gettype [this] + "com.xtdb.protos.OptionString")) + +(s/def ::OptionString-spec (s/keys :opt-un [])) +(def OptionString-defaults {}) + +(defn cis->OptionString + "CodedInputStream to OptionString" + [is] + (map->OptionString-record (tag-map OptionString-defaults (fn [tag index] (case index 1 [:value {:none (ecis->Empty is)}] 2 [:value {:some (serdes.core/cis->String is)}] [index (serdes.core/cis->undefined tag is)])) is))) + +(defn ecis->OptionString + "Embedded CodedInputStream to OptionString" + [is] + (serdes.core/cis->embedded cis->OptionString is)) + +(defn new-OptionString + "Creates a new instance from a map, similar to map->OptionString except that + it properly accounts for nested messages, when applicable. + " + [init] + {:pre [(if (s/valid? ::OptionString-spec init) true (throw (ex-info "Invalid input" (s/explain-data ::OptionString-spec init))))]} + (-> (merge OptionString-defaults init) + (convert-OptionString-value) + (map->OptionString-record))) + +(defn pb->OptionString + "Protobuf to OptionString" + [input] + (cis->OptionString (serdes.stream/new-cis input))) + +(def ^:protojure.protobuf.any/record OptionString-meta {:type "com.xtdb.protos.OptionString" :decoder pb->OptionString}) + diff --git a/src/com/xtdb/protos/GrpcApi/client.cljc b/src/com/xtdb/protos/GrpcApi/client.cljc index 3880ac7..abbfaac 100644 --- a/src/com/xtdb/protos/GrpcApi/client.cljc +++ b/src/com/xtdb/protos/GrpcApi/client.cljc @@ -5,6 +5,8 @@ ;;;---------------------------------------------------------------------------------- (ns com.xtdb.protos.GrpcApi.client (:require [com.xtdb.protos :refer :all] + [com.xtdb.protos :as com.xtdb.protos] + [com.google.protobuf :as com.google.protobuf] [clojure.core.async :as async] [protojure.grpc.client.utils :refer [send-unary-params invoke-unary]] [promesa.core :as p] @@ -28,3 +30,15 @@ :metadata metadata}] (p/then (send-unary-params input params) (fn [_] (invoke-unary client desc output)))))) +(defn SubmitTx + ([client params] (SubmitTx client {} params)) + ([client metadata params] + (let [input (async/chan 1) + output (async/chan 1) + desc {:service "com.xtdb.protos.GrpcApi" + :method "SubmitTx" + :input {:f com.xtdb.protos/new-SubmitRequest :ch input} + :output {:f com.xtdb.protos/pb->SubmitResponse :ch output} + :metadata metadata}] + (p/then (send-unary-params input params) (fn [_] (invoke-unary client desc output)))))) + diff --git a/src/com/xtdb/protos/GrpcApi/server.cljc b/src/com/xtdb/protos/GrpcApi/server.cljc index a56d271..48f65c0 100644 --- a/src/com/xtdb/protos/GrpcApi/server.cljc +++ b/src/com/xtdb/protos/GrpcApi/server.cljc @@ -4,19 +4,26 @@ ;;; GRPC com.xtdb.protos.GrpcApi Service Implementation ;;;---------------------------------------------------------------------------------- (ns com.xtdb.protos.GrpcApi.server - (:require [com.xtdb.protos :refer :all])) + (:require [com.xtdb.protos :refer :all] + [com.xtdb.protos :as com.xtdb.protos] + [com.google.protobuf :as com.google.protobuf])) ;----------------------------------------------------------------------------- ; GRPC GrpcApi ;----------------------------------------------------------------------------- (defprotocol Service - (Status [this param])) + (Status [this param]) + (SubmitTx [this param])) (def GrpcApi-service-name "com.xtdb.protos.GrpcApi") (defn- Status-dispatch [ctx request] (Status ctx request)) +(defn- SubmitTx-dispatch + [ctx request] + (SubmitTx ctx request)) (def ^:const rpc-metadata - [{:pkg "com.xtdb.protos" :service "GrpcApi" :method "Status" :method-fn Status-dispatch :server-streaming false :client-streaming false :input pb->Empty :output new-StatusResponse}]) + [{:pkg "com.xtdb.protos" :service "GrpcApi" :method "Status" :method-fn Status-dispatch :server-streaming false :client-streaming false :input pb->Empty :output new-StatusResponse} + {:pkg "com.xtdb.protos" :service "GrpcApi" :method "SubmitTx" :method-fn SubmitTx-dispatch :server-streaming false :client-streaming false :input pb->SubmitRequest :output new-SubmitResponse}]) diff --git a/src/gxtdb/adapters/json.clj b/src/gxtdb/adapters/json.clj new file mode 100644 index 0000000..efbc227 --- /dev/null +++ b/src/gxtdb/adapters/json.clj @@ -0,0 +1,13 @@ +(ns gxtdb.adapters.json + (:require [gxtdb.utils :as utils])) + +(defn value-record->edn [record] + (let [kind (:kind record) + key (-> kind keys first)] + (case key + :number-value (:number-value kind) + :bool-value (:bool-value kind) + :string-value (-> kind :string-value str) + :list-value (->> kind :list-value :values (mapv value-record->edn)) + :struct-value (->> kind :struct-value :fields (map (fn [[k v]] {(utils/str->keyword k) (value-record->edn v)})) (reduce into {})) + ""))) \ No newline at end of file diff --git a/src/gxtdb/adapters/tx_log.clj b/src/gxtdb/adapters/tx_log.clj new file mode 100644 index 0000000..94fffc9 --- /dev/null +++ b/src/gxtdb/adapters/tx_log.clj @@ -0,0 +1,39 @@ +(ns gxtdb.adapters.tx-log + (:require [gxtdb.utils :as utils] + [xtdb.api :as xt] + [gxtdb.adapters.json :as json])) + +(defn ->evict [transaction] + (let [transaction (:evict transaction) + id (:document-id transaction) + id-type (:id-type transaction)] + [::xt/evict (utils/->id id-type id)])) + +(defn ->delete [transaction] + (let [transaction (:delete transaction) + id (:document-id transaction) + id-type (:id-type transaction)] + [::xt/delete (utils/->id id-type id)])) + +(defn ->put [transaction] + (let [transaction (:put transaction) + id (:xt-id transaction) + id-type (:id-type transaction) + document (:document transaction)] + [::xt/put (into {:xt/id (utils/->id id-type id)} (json/value-record->edn {:kind {:struct-value document}}))])) + +(defn ->tx-log [ops] + (let [transaction (:transaction-type ops) + transaction-type (-> transaction keys first) + xt-converted-type (->> transaction-type name (keyword ":xt"))] + (case transaction-type + :put (->put transaction) + :delete (->delete transaction) + :evict (->evict transaction) + :else (throw (str "Transaction type " xt-converted-type " not implemented"))))) + +(defn proto->tx-log [tx-ops] + (mapv ->tx-log tx-ops)) + +(defn xtdb->proto [edn] + {:tx-time (-> edn :xtdb.api/tx-time utils/->inst-str) :tx-id (:xtdb.api/tx-id edn)}) \ No newline at end of file diff --git a/src/gxtdb/service.clj b/src/gxtdb/service.clj index 235155c..f0c4991 100644 --- a/src/gxtdb/service.clj +++ b/src/gxtdb/service.clj @@ -5,6 +5,7 @@ [ring.util.response :as ring-resp] [gxtdb.adapters.status :as status-adapter] + [gxtdb.adapters.tx-log :as tx-log-adapter] ;; -- XTDB -- [xtdb.api :as xt] @@ -12,7 +13,8 @@ ;; -- PROTOC-GEN-CLOJURE -- [protojure.pedestal.core :as protojure.pedestal] [protojure.pedestal.routes :as proutes] - [com.xtdb.protos.GrpcApi.server :as api])) + [com.xtdb.protos.GrpcApi.server :as api] + [gxtdb.adapters.tx-log :as tx-log])) (defn about-page [_request] @@ -43,15 +45,17 @@ (deftype GrpcAPI [xtdb-node] api/Service + (SubmitTx [_this {{:keys [tx-ops]} :grpc-params}] + (let [tx-log (tx-log-adapter/proto->tx-log tx-ops) + xt-response (xt/submit-tx xtdb-node tx-log)] + {:status 200 + :body (tx-log-adapter/xtdb->proto xt-response)})) (Status [_this _request] (let [status (xt/status xtdb-node)] {:status 200 :body (status-adapter/edn->grpc status)}))) -;; Defines "/" and "/about" routes with their associated :get handlers. -;; The interceptors defined after the verb map (e.g., {:get home-page} -;; apply to / and its children (/about). (def common-interceptors [(body-params/body-params) http/html-body]) ;; Tabular routes @@ -59,19 +63,11 @@ ["/about" :get (conj common-interceptors `about-page)]}) ;; -- PROTOC-GEN-CLOJURE -- -;; Add the routes produced by Greeter->routes (defn grpc-routes [xtdb-node] (reduce conj routes (proutes/->tablesyntax {:rpc-metadata api/rpc-metadata :interceptors common-interceptors :callback-context (GrpcAPI. xtdb-node)}))) (defn service [xtdb-node] {:env :prod ::http/routes (grpc-routes xtdb-node) - - ;; -- PROTOC-GEN-CLOJURE -- - ;; We override the chain-provider with one provided by protojure.protobuf - ;; and based on the Undertow webserver. This provides the proper support - ;; for HTTP/2 trailers, which GRPCs rely on. A future version of pedestal - ;; may provide this support, in which case we can go back to using - ;; chain-providers from pedestal. ::http/type protojure.pedestal/config ::http/chain-provider protojure.pedestal/provider diff --git a/src/gxtdb/utils.clj b/src/gxtdb/utils.clj index 7cf57ea..e6905dd 100644 --- a/src/gxtdb/utils.clj +++ b/src/gxtdb/utils.clj @@ -3,6 +3,7 @@ [clojure.string :as str]) (:import java.text.SimpleDateFormat)) +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defmacro tokenize [x] `(let [x# ~x] x#)) (defn assoc-some-str @@ -34,4 +35,24 @@ (defn edn-or-str [value] (if (str/starts-with? value ":") (keyword (subs value 1)) - value)) \ No newline at end of file + value)) + +(defn str->keyword [s] + (when-not (or (empty? s) (= s ":")) (-> s (str/replace #" " "-") keyword))) + +(defn ->id [id-type id] + (case id-type + :keyword (str->keyword id) + :string id + :int (parse-long id) + :uuid (let [uuid (parse-uuid id)] + (if (uuid? uuid) uuid id)) + (str->keyword id))) + +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} +(defn record->map + [record] + (let [f #(if (record? %) (record->map %) %) + ks (keys record) + vs (map f (vals record))] + (zipmap ks vs))) \ No newline at end of file diff --git a/test/gxtdb/adapters/json_test.clj b/test/gxtdb/adapters/json_test.clj new file mode 100644 index 0000000..90bb251 --- /dev/null +++ b/test/gxtdb/adapters/json_test.clj @@ -0,0 +1,20 @@ +(ns gxtdb.adapters.json-test + #_{:clj-kondo/ignore [:refer-all]} + (:require [clojure.test :refer :all] + [gxtdb.adapters.json :as json])) + +(def edn {:kind {:struct-value {:fields + {"painting ids" {:kind {:list-value {:values [{:kind {:number-value 2.0}} {:kind {:number-value 3.0}} {:kind {:number-value 76.0}} {:kind {:number-value 3.0}}]}}}, + "age" {:kind {:number-value 200.0}}, + "is-artist?" {:kind {:bool-value true}}, + "full name" {:kind {:struct-value {:fields {"last" {:kind {:string-value "picasso"}}, "first" {:kind {:string-value "pablo"}}}}}}, + "name" {:kind {:string-value "pablo picasso"}}}}}}) +(def json {:painting-ids [2.0 3.0 76.0 3.0], + :age 200.0, + :is-artist? true, + :full-name {:last "picasso", :first "pablo"}, + :name "pablo picasso"}) + +(deftest json-value-test + (testing "convert proto to value" + (is (= (json/value-record->edn edn) json)))) \ No newline at end of file diff --git a/test/gxtdb/adapters/tx_log_test.clj b/test/gxtdb/adapters/tx_log_test.clj new file mode 100644 index 0000000..b0b714f --- /dev/null +++ b/test/gxtdb/adapters/tx_log_test.clj @@ -0,0 +1,46 @@ +(ns gxtdb.adapters.tx-log-test + #_{:clj-kondo/ignore [:refer-all]} + (:require [clojure.test :refer :all] + [gxtdb.utils :as utils] + [gxtdb.adapters.tx-log :as tx-log])) + +(def var->put-tx {:put {:xt-id "id 2", :document {:fields {"painting ids" {:kind {:list-value {:values [{:kind {:number-value 2.0}}, {:kind {:number-value 3.0}} {:kind {:number-value 76.0}} {:kind {:number-value 3.0}}]}}}, "age" {:kind {:number-value 200.0}}, "is-artist?" {:kind {:bool-value true}}, "full name" {:kind {:struct-value {:fields {"last" {:kind {:string-value "picasso"}}, "first" {:kind {:string-value "pablo"}}}}}}, "name" {:kind {:string-value "pablo picasso"}}}}}}) +(def expected-put-tx [:xtdb.api/put + {:xt/id :id-2, + :painting-ids [2.0 3.0 76.0 3.0], + :age 200.0, + :is-artist? true, + :full-name {:last "picasso", :first "pablo"}, + :name "pablo picasso"}]) + +(def var->delete-tx {:delete {:document-id "f2eed61a-1928-4d75-8620-debfc23eae8d", :id-type :uuid}}) +(def expected-delete-tx [:xtdb.api/delete #uuid "f2eed61a-1928-4d75-8620-debfc23eae8d"]) + +(def var->evict-tx {:evict {:document-id "f2eed61a-1928-4d75-8620-debfc23eae8d", :id-type :uuid}}) +(def expected-evict-tx [:xtdb.api/evict #uuid "f2eed61a-1928-4d75-8620-debfc23eae8d"]) + +(def var->tx-ops + [{:transaction-type + {:put {:id-type :keyword, :xt-id "id1", :document {:fields {"key" {:kind {:string-value "value"}}}}}}} + {:transaction-type + {:evict {:document-id "45", :id-type :int}}} + {:transaction-type + {:delete {:document-id "f2eed61a-1928-4d75-8620-debfc23eae8d", :id-type :uuid}}}]) + +(deftest tx-log-adapters-testing + (testing "Testing if put transactions parses correctly" + (is (= (tx-log/->put var->put-tx) expected-put-tx))) + (testing "Testing if delete transactions parses correctly" + (is (= (tx-log/->delete var->delete-tx) expected-delete-tx))) + (testing "Testing if evict transactions parses correctly" + (is (= (tx-log/->evict var->evict-tx) expected-evict-tx))) + (testing "Testing if proto tx-ops becomes xtdb datalog transaction" + (let [tx-ops (tx-log/proto->tx-log var->tx-ops)] + (is (= tx-ops + [[:xtdb.api/put {:xt/id :id1, :key "value"}] [:xtdb.api/evict 45] [:xtdb.api/delete #uuid "f2eed61a-1928-4d75-8620-debfc23eae8d"]]))))) + +(deftest xtdb-edn->proto-test + (testing "Testing if submit tx response can be parsed to proto" + (let [proto (tx-log/xtdb->proto {:xtdb.api/tx-id 0, :xtdb.api/tx-time #inst "2023-05-20T18:12:24.836Z"})] + (is (inst? (-> proto :tx-time utils/->inst))) + (is (= (:tx-id proto) 0))))) \ No newline at end of file diff --git a/test/gxtdb/service_test.clj b/test/gxtdb/service_test.clj index b137adb..79dada0 100644 --- a/test/gxtdb/service_test.clj +++ b/test/gxtdb/service_test.clj @@ -1,3 +1,4 @@ +#_{:clj-kondo/ignore [:refer-all]} (ns gxtdb.service-test (:require [clojure.test :refer :all] [com.xtdb.protos.GrpcApi.client :refer :all] @@ -6,7 +7,8 @@ [protojure.grpc.client.providers.http2 :refer [connect]] [protojure.pedestal.core :as protojure.pedestal] [xtdb.api :as xt] - [gxtdb.service :as service])) + [gxtdb.service :as service] + [gxtdb.utils :as utils])) (def ^:dynamic *opts* {}) @@ -42,3 +44,12 @@ (:kv-store @(Status @(connect {:uri (str "http://localhost:" (:port @test-env))}) {})) "xtdb.mem_kv.MemKv")))) +(deftest submit-tx-test + (testing "Submit a put tx to xtdb-node" + (let [tx @(SubmitTx @(connect {:uri (str "http://localhost:" (:port @test-env))}) + {:tx-ops [{:transaction-type + {:put {:id-type :keyword, :xt-id "id1", :document {:fields {"key" {:kind {:string-value "value"}}}}}}}]})] + (is (inst? (-> tx :tx-time utils/->inst))) + (is (>= + (:tx-id tx) + 0))))) diff --git a/test/gxtdb/utils_test.clj b/test/gxtdb/utils_test.clj new file mode 100644 index 0000000..6a1fdbd --- /dev/null +++ b/test/gxtdb/utils_test.clj @@ -0,0 +1,106 @@ +#_{:clj-kondo/ignore [:refer-all]} +(ns gxtdb.utils-test + (:require [clojure.test :refer :all] + [gxtdb.utils :refer :all])) + +;; assoc-some-str tests +(deftest assoc-some-str-test + (testing "Should associate a key with a value when the value is not nil" + (let [input {:foo 42}] + (is (= (assoc-some-str input :bar "hello") + {:foo 42 :bar {:value {:some "hello"}}})))) + + (testing "Should associate a key with {:value {:none {}}} when the value is nil" + (let [input {:foo 42}] + (is (= (assoc-some-str input :bar nil) + {:foo 42 :bar {:value {:none {}}}}))))) + +;; assoc-with-fn tests +(deftest assoc-with-fn-test + (testing "Should associate a key in a map if the function applied to value is non-nil" + (let [input {:foo 42}] + (is (= (assoc-with-fn input :bar "hello" str) + {:foo 42 :bar "hello"})))) + + (testing "Should not associate a key in a map if the value is nil" + (let [input {:foo 42}] + (is (= (assoc-with-fn input :bar nil str) + {:foo 42}))))) + +;; nil->default tests +(deftest nil->default-test + (testing "Should associate a key with the default value when the value is nil" + (let [input {:foo nil}] + (is (= (nil->default input :foo nil "default") + {:foo "default"})))) + + (testing "Should not associate a key with the default value when the value is not nil" + (let [input {:foo "value"}] + (is (= (nil->default input :foo "default" :default) + {:foo "default"}))))) + +;; not-nil? tests +(deftest not-nil?-test + (testing "Should return true if the value is not nil" + (is (not-nil? 42))) + + (testing "Should return false if the value is nil" + (is (not (not-nil? nil))))) + +;; ->inst tests +(deftest ->inst-test + (testing "Should convert a valid string representation of an instant to an instance of java.time.Instant" + (let [input "2023-05-19T10:30:00Z"] + (is (inst? (->inst input))))) + + (testing "Should return nil if the input is an invalid string representation of an instant" + (let [input "invalid-instant"] + (is (nil? (->inst input)))))) + +;; ->inst-str tests +(deftest ->inst-str-test + (testing "Should convert an instance of java.time.Instant to a formatted string representation" + (let [input (->inst "2023-05-19T10:30:00Z")] + (is (string? (->inst-str input)))))) + +;; edn-or-str tests +(deftest edn-or-str-test + (testing "Should return a keyword when the value starts with a colon" + (is (= (edn-or-str ":keyword") :keyword))) + + (testing "Should return the original value when it doesn't start with a colon" + (is (= (edn-or-str "value") "value"))) + + (testing "Should handle empty string as input" + (is (= (edn-or-str "") "")))) + +;; str->keyword tests +(deftest str->keyword-test + (testing "Should convert a string to a keyword" + (is (= (str->keyword "my-keyword") :my-keyword))) + + (testing "Should handle whitespace in the string and replace it with hyphen" + (is (= (str->keyword "my keyword") :my-keyword))) + + (testing "Should handle empty string as input" + (is (= (str->keyword "") nil)))) + +;; ->id tests +(deftest ->id-test + (testing "Should convert a string ID to a keyword when id-type is :keyword" + (is (= (->id :keyword "my-id") :my-id))) + + (testing "Should parse a valid integer string and return the parsed integer when id-type is :int" + (is (= (->id :int "42") 42))) + + (testing "Should return the original string ID when id-type is :string" + (is (= (->id :string "my-id") "my-id"))) + + (testing "Should parse a valid UUID string and return the parsed UUID when id-type is :uuid" + (is (uuid? (->id :uuid "08d1fc6e-85f9-4a55-b0b9-3fd08963c375")))) + + (testing "Should return the original value when id-type is not recognized" + (is (= (->id :unknown "my-id") :my-id))) + + (testing "Should handle empty string as input" + (is (= (->id :keyword "") nil)))) \ No newline at end of file