From dd3b0f143c0a13ebb21450db0944b02373826a92 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Thu, 25 Sep 2025 18:22:52 +0200 Subject: [PATCH 01/22] Get build & tests breaking --- Cargo.lock | 1066 +++++++++++++++----------- dependencies/typedb/repositories.bzl | 8 +- rust/Cargo.toml | 2 +- 3 files changed, 617 insertions(+), 459 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 66f26e573..e86c5342b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,21 +1,21 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "addr2line" -version = "0.24.1" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -58,43 +58,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.88" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "async-attributes" @@ -119,9 +120,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", "event-listener-strategy", @@ -131,14 +132,15 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.1" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.1", - "futures-lite 2.3.0", + "fastrand 2.3.0", + "futures-lite 2.6.1", + "pin-project-lite", "slab", ] @@ -160,12 +162,12 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel 2.3.1", + "async-channel 2.5.0", "async-executor", - "async-io 2.3.4", - "async-lock 3.4.0", + "async-io 2.6.0", + "async-lock 3.4.1", "blocking", - "futures-lite 2.3.0", + "futures-lite 2.6.1", "once_cell", ] @@ -183,7 +185,7 @@ dependencies = [ "log", "parking", "polling 2.8.0", - "rustix 0.37.27", + "rustix 0.37.28", "slab", "socket2 0.4.10", "waker-fn", @@ -191,21 +193,20 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.4" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock 3.4.0", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.6.1", "parking", - "polling 3.7.3", - "rustix 0.38.37", + "polling 3.11.0", + "rustix 1.1.2", "slab", - "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -219,11 +220,11 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] @@ -252,26 +253,26 @@ dependencies = [ "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.37", + "rustix 0.38.44", "windows-sys 0.48.0", ] [[package]] name = "async-signal" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ - "async-io 2.3.4", - "async-lock 3.4.0", + "async-io 2.6.0", + "async-lock 3.4.1", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.37", + "rustix 1.1.2", "signal-hook-registry", "slab", - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -283,13 +284,13 @@ dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", - "async-io 2.3.4", - "async-lock 3.4.0", + "async-io 2.6.0", + "async-lock 3.4.1", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.6.1", "gloo-timers", "kv-log-macro", "log", @@ -303,9 +304,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -314,13 +315,13 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] @@ -331,13 +332,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] @@ -359,15 +360,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", "axum-core", @@ -384,17 +385,17 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper 1.0.1", - "tower", + "sync_wrapper", + "tower 0.5.2", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -405,16 +406,16 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper", "tower-layer", "tower-service", ] [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -422,7 +423,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -439,28 +440,28 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "blocking" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel 2.3.1", + "async-channel 2.5.0", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.6.1", "piper", ] [[package]] name = "bstr" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "serde", @@ -468,42 +469,37 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytecount" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytes" -version = "1.7.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.1.18" +version = "1.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "chrono" @@ -517,7 +513,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -546,9 +542,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.17" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" dependencies = [ "clap_builder", "clap_derive", @@ -556,9 +552,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.17" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" dependencies = [ "anstream", "anstyle", @@ -569,27 +565,27 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "concurrent-queue" @@ -606,22 +602,22 @@ version = "0.0.0" [[package]] name = "console" -version = "0.15.8" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", - "lazy_static", "libc", + "once_cell", "unicode-width", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -648,18 +644,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -676,18 +672,18 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "cucumber" @@ -763,13 +759,13 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.18" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] @@ -780,15 +776,15 @@ checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "env_logger" @@ -805,18 +801,18 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.1", ] [[package]] @@ -838,9 +834,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.3.1" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -849,11 +845,11 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.1", "pin-project-lite", ] @@ -868,15 +864,21 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" [[package]] name = "fixedbitset" -version = "0.4.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "fnv" @@ -950,11 +952,11 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ - "fastrand 2.1.1", + "fastrand 2.3.0", "futures-core", "futures-io", "parking", @@ -969,7 +971,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] @@ -1004,25 +1006,25 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] @@ -1044,21 +1046,21 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "globset" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" +checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" dependencies = [ "aho-corasick", "bstr", "log", "regex-automata", - "regex-syntax 0.8.5", + "regex-syntax 0.8.6", ] [[package]] @@ -1086,9 +1088,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.6" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -1096,7 +1098,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.5.0", + "indexmap 2.11.4", "slab", "tokio", "tokio-util", @@ -1115,6 +1117,12 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "heck" version = "0.3.3" @@ -1153,9 +1161,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "http" @@ -1180,12 +1188,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", + "futures-core", "http", "http-body", "pin-project-lite", @@ -1193,9 +1201,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -1205,19 +1213,20 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" -version = "1.4.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "h2", "http", "http-body", @@ -1225,6 +1234,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -1232,9 +1242,9 @@ dependencies = [ [[package]] name = "hyper-timeout" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ "hyper", "hyper-util", @@ -1245,34 +1255,36 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.8" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "libc", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.6.0", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -1314,12 +1326,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.16.0", ] [[package]] @@ -1339,9 +1351,12 @@ dependencies = [ [[package]] name = "inventory" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" +checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" +dependencies = [ + "rustversion", +] [[package]] name = "io-lifetimes" @@ -1360,20 +1375,20 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "cfg-if", "libc", ] [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.4.0", + "hermit-abi 0.5.2", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1393,18 +1408,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" @@ -1451,25 +1466,30 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" dependencies = [ "value-bag", ] @@ -1504,14 +1524,14 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mime" @@ -1527,30 +1547,29 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ - "hermit-abi 0.3.9", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] name = "multimap" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "nom" @@ -1584,34 +1603,40 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.5.2", "libc", ] [[package]] name = "object" -version = "0.36.4" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.20.0" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "parking" @@ -1621,9 +1646,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1631,15 +1656,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -1686,34 +1711,34 @@ checksum = "9555b1514d2d99d78150d3c799d4c357a3e2c2a8062cd108e93a06d9057629c5" [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "petgraph" -version = "0.6.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset", - "indexmap 2.5.0", + "indexmap 2.11.4", ] [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_shared", ] [[package]] name = "phf_codegen" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ "phf_generator", "phf_shared", @@ -1721,9 +1746,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", "rand 0.8.5", @@ -1731,9 +1756,9 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", "uncased", @@ -1741,29 +1766,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1778,7 +1803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.1", + "fastrand 2.3.0", "futures-io", ] @@ -1800,36 +1825,35 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.3" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.4.0", + "hermit-abi 0.5.2", "pin-project-lite", - "rustix 0.38.37", - "tracing", - "windows-sys 0.59.0", + "rustix 1.1.2", + "windows-sys 0.61.1", ] [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.7.35", + "zerocopy", ] [[package]] name = "prettyplease" -version = "0.2.25" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] @@ -1858,9 +1882,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -1877,13 +1901,12 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.2" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ - "bytes", "heck 0.5.0", - "itertools 0.13.0", + "itertools 0.14.0", "log", "multimap", "once_cell", @@ -1892,7 +1915,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.87", + "syn 2.0.106", "tempfile", ] @@ -1903,30 +1926,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] name = "prost-types" -version = "0.13.2" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" dependencies = [ "prost", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.8.5" @@ -1940,13 +1969,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.0", - "zerocopy 0.8.17", + "rand_core 0.9.3", ] [[package]] @@ -1966,7 +1994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -1975,49 +2003,48 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] name = "rand_core" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", - "zerocopy 0.8.17", + "getrandom 0.3.3", ] [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.5", + "regex-syntax 0.8.6", ] [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax 0.8.6", ] [[package]] @@ -2028,36 +2055,35 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "ring" -version = "0.17.8" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustix" -version = "0.37.27" +version = "0.37.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" dependencies = [ "bitflags 1.3.2", "errno", @@ -2069,22 +2095,35 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "errno", "libc", - "linux-raw-sys 0.4.14", - "windows-sys 0.52.0", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.1", ] [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "log", "once_cell", @@ -2109,25 +2148,27 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ "ring", "rustls-pki-types", @@ -2136,15 +2177,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -2157,11 +2198,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -2196,11 +2237,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.2.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "core-foundation", "core-foundation-sys", "libc", @@ -2209,9 +2250,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -2244,7 +2285,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] @@ -2253,7 +2294,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.11.4", "itoa", "memchr", "ryu", @@ -2295,33 +2336,30 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] [[package]] name = "siphasher" -version = "0.3.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smart-default" @@ -2369,9 +2407,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2387,12 +2425,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - [[package]] name = "steps" version = "0.0.0" @@ -2436,9 +2468,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -2447,15 +2479,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] name = "synthez" @@ -2492,15 +2518,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "cfg-if", - "fastrand 2.1.1", + "fastrand 2.3.0", + "getrandom 0.3.3", "once_cell", - "rustix 0.38.37", - "windows-sys 0.59.0", + "rustix 1.1.2", + "windows-sys 0.61.1", ] [[package]] @@ -2514,19 +2540,19 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ - "rustix 0.38.37", - "windows-sys 0.48.0", + "rustix 1.1.2", + "windows-sys 0.60.2", ] [[package]] name = "textwrap" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" dependencies = [ "smawk", "unicode-linebreak", @@ -2535,22 +2561,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] @@ -2581,17 +2607,16 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", - "rustls-pki-types", "tokio", ] @@ -2608,9 +2633,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -2642,11 +2667,11 @@ dependencies = [ "prost", "rustls-native-certs", "rustls-pemfile", - "socket2 0.5.7", + "socket2 0.5.10", "tokio", "tokio-rustls", "tokio-stream", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -2663,7 +2688,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] @@ -2697,6 +2722,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -2711,9 +2750,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -2722,20 +2761,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", ] @@ -2790,7 +2829,7 @@ dependencies = [ [[package]] name = "typedb-protocol" version = "0.0.0" -source = "git+https://github.com/typedb/typedb-protocol?tag=3.4.0#3fc4c0fe0ac37c517af0e31415347299cff0307c" +source = "git+https://github.com/typedb/typedb-protocol?rev=9fba4c5c8105594053ab6b5fea01117e144b7de6#9fba4c5c8105594053ab6b5fea01117e144b7de6" dependencies = [ "prost", "tonic", @@ -2819,9 +2858,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-linebreak" @@ -2837,9 +2876,9 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "untrusted" @@ -2859,18 +2898,18 @@ version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.3", "js-sys", - "rand 0.9.0", + "rand 0.9.2", "serde", "wasm-bindgen", ] [[package]] name = "value-bag" -version = "1.9.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" [[package]] name = "version_check" @@ -2905,17 +2944,26 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -2941,18 +2989,19 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] @@ -2975,7 +3024,7 @@ checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.106", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2991,9 +3040,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" dependencies = [ "js-sys", "wasm-bindgen", @@ -3017,11 +3066,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -3032,18 +3081,68 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" dependencies = [ - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "windows-interface" +version = "0.59.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.1", +] [[package]] name = "windows-sys" @@ -3072,6 +3171,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.4", +] + +[[package]] +name = "windows-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -3096,13 +3213,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3115,6 +3249,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3127,6 +3267,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3139,12 +3285,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3157,6 +3315,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3169,6 +3333,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3181,6 +3351,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3194,57 +3370,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "wit-bindgen-rt" -version = "0.33.0" +name = "windows_x86_64_msvc" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags 2.6.0", -] +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] -name = "zerocopy" -version = "0.7.35" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "zerocopy" -version = "0.8.17" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ - "zerocopy-derive 0.8.17", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", + "syn 2.0.106", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index 90a2a7751..c7d5f44f7 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -27,13 +27,13 @@ def typedb_dependencies(): def typedb_protocol(): git_repository( name = "typedb_protocol", - remote = "https://github.com/typedb/typedb-protocol", - tag = "3.4.0", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol + remote = "https://github.com/krishnangovindraj/typedb-protocol", + commit = "9fba4c5c8105594053ab6b5fea01117e144b7de6", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol ) def typedb_behaviour(): git_repository( name = "typedb_behaviour", - remote = "https://github.com/typedb/typedb-behaviour", - commit = "095a58cb823dd8436600526ceb3ff2c0bdf377f9", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour + remote = "https://github.com/krishnangovindraj/typedb-behaviour", + commit = "a6a85a75cbce32ad9953df587630afe2929c5b9e", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour ) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 5503f44ee..6496211bf 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -65,8 +65,8 @@ [dependencies.typedb-protocol] features = [] + rev = "9fba4c5c8105594053ab6b5fea01117e144b7de6" git = "https://github.com/typedb/typedb-protocol" - tag = "3.4.0" default-features = false [dependencies.log] From f577a139b69051ca26ba5737beeec6b5154a89b6 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Thu, 25 Sep 2025 22:56:39 +0200 Subject: [PATCH 02/22] Ok now maybe --- rust/src/analyze/mod.rs | 40 ++++++++++++++++++++ rust/src/connection/message.rs | 2 + rust/src/connection/network/proto/message.rs | 1 + rust/src/lib.rs | 1 + 4 files changed, 44 insertions(+) create mode 100644 rust/src/analyze/mod.rs diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs new file mode 100644 index 000000000..1ccb02c18 --- /dev/null +++ b/rust/src/analyze/mod.rs @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +#[derive(Debug)] +pub struct AnalyzeResponse { + structure: QueryStructure, + annotations: QueryAnnotations, +} + +#[derive(Debug)] +pub struct QueryStructure { + query: PipelineStructure, + preamble: FunctionStructure, +} + +#[derive(Debug)] +pub struct PipelineStructure { } + +#[derive(Debug)] +pub struct FunctionStructure { } + +#[derive(Debug)] +pub struct QueryAnnotations { } diff --git a/rust/src/connection/message.rs b/rust/src/connection/message.rs index 20239740c..b0463310e 100644 --- a/rust/src/connection/message.rs +++ b/rust/src/connection/message.rs @@ -36,6 +36,7 @@ use crate::{ info::UserInfo, Credentials, QueryOptions, TransactionOptions, TransactionType, }; +use crate::analyze::AnalyzeResponse; #[derive(Debug)] pub(super) enum Request { @@ -154,6 +155,7 @@ pub(super) enum TransactionResponse { Commit, Rollback, Query(QueryResponse), + Analyze(AnalyzeResponse), Close, } diff --git a/rust/src/connection/network/proto/message.rs b/rust/src/connection/network/proto/message.rs index eb8a81da0..3a00ba059 100644 --- a/rust/src/connection/network/proto/message.rs +++ b/rust/src/connection/network/proto/message.rs @@ -397,6 +397,7 @@ impl TryFromProto for TransactionResponse { Err(ConnectionError::MissingResponseField { field: "transaction.res.query.initial_res.res" }.into()) } }, + Some(transaction::res::Res::AnalyzeRes(analyze_resp)) => todo!(), None => Err(ConnectionError::MissingResponseField { field: "res" }.into()), } } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 20a3d7801..ae45e6ab6 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -32,6 +32,7 @@ pub use self::{ user::{User, UserManager}, }; +pub mod analyze; pub mod answer; mod common; pub mod concept; From 8f8b888525d9d1d9e25baefaf5dd266c66f96389 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Fri, 26 Sep 2025 00:05:23 +0200 Subject: [PATCH 03/22] I dont think I need from_proto --- rust/src/analyze/conjunction.rs | 67 +++++++++++++++++++++++++++++ rust/src/analyze/function.rs | 75 +++++++++++++++++++++++++++++++++ rust/src/analyze/mod.rs | 52 ++++++++++++++++++++--- rust/src/analyze/pipeline.rs | 72 +++++++++++++++++++++++++++++++ 4 files changed, 261 insertions(+), 5 deletions(-) create mode 100644 rust/src/analyze/conjunction.rs create mode 100644 rust/src/analyze/function.rs create mode 100644 rust/src/analyze/pipeline.rs diff --git a/rust/src/analyze/conjunction.rs b/rust/src/analyze/conjunction.rs new file mode 100644 index 000000000..e2607ebee --- /dev/null +++ b/rust/src/analyze/conjunction.rs @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use typedb_protocol::analyze::{res as protocol, res::query_structure as query_structure_proto}; +use typedb_protocol::conjunction_structure; +use crate::analyze::{Context, FromPipelineProto, vec_from_proto}; + +#[derive(Debug)] +pub struct ConjunctionId(pub usize); + +#[derive(Debug)] +pub struct Conjunction { + constraints: Vec, +} + +impl FromPipelineProto for Conjunction { + fn from_proto(context: &Context, value: typedb_protocol::ConjunctionStructure) -> Self { + Self { constraints: vec_from_proto(context, value.constraints) } + } +} + +#[derive(Debug)] +pub enum Constraint { + +} + +#[derive(Debug)] +pub struct Variable { + id: u32, + name: Option, +} + +impl FromPipelineProto for Variable { + fn from_proto(context: &Context, value: conjunction_structure::Variable) -> Self { + Self { id: value.id, name: context.var_name(&value) } + } +} + #[derive(Debug)] +pub struct Reducer { + variables: Vec, + reducer: String, +} + +impl FromPipelineProto for Reducer { + fn from_proto(context: &Context, value: protocol::query_structure::Reducer) -> Self { + Self { + variables: vec_from_proto(context, value.variables), + reducer: value.reducer, + } + } +} diff --git a/rust/src/analyze/function.rs b/rust/src/analyze/function.rs new file mode 100644 index 000000000..05aeffbd3 --- /dev/null +++ b/rust/src/analyze/function.rs @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use typedb_protocol::analyze::res::query_structure; +use crate::analyze::{Context, FromPipelineProto, vec_from_proto}; +use crate::analyze::conjunction::{Reducer, Variable}; +use crate::analyze::pipeline::PipelineStructure; + +#[derive(Debug)] +pub struct FunctionStructure { + arguments: Vec, + returns: ReturnOperation, + body: PipelineStructure, +} + +impl From for FunctionStructure { + fn from(value: query_structure::FunctionStructure) -> Self { + let protocol_pipeline = value.body.expect("expected function body"); + let context = Context::build(&protocol_pipeline); + let body = PipelineStructure::from_proto(&context, protocol_pipeline); + let arguments = vec_from_proto(&context, value.arguments); + let returns = ReturnOperation::from_proto(&context, value.returns.expect("expected function return")); + Self { arguments, returns, body, } + } +} + +#[derive(Debug)] +pub enum ReturnOperation { + Stream { variables: Vec }, + Single { selector: String, variables: Vec }, + Check {}, + Reduce { reducers: Vec }, +} + +impl FromPipelineProto for ReturnOperation { + fn from_proto(context: &Context, value: query_structure::function_structure::Returns) -> Self { + use typedb_protocol::analyze::res::query_structure::function_structure::Returns; + use crate::analyze; + match value { + Returns::Stream(stream) => { + Self::Stream {variables: analyze::vec_from_proto(context, stream.variables) } + } + Returns::Single(single) => { + Self::Single { + selector: single.selector, + variables: analyze::vec_from_proto(context, single.variables) + } + } + Returns::Check(_check) => { + Self::Check {} + }, + Returns::Reduce(reduce) => { + Self::Reduce { + reducers: analyze::vec_from_proto(context, reduce.reducers) + } + } + } + } +} diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs index 1ccb02c18..f9d77baa9 100644 --- a/rust/src/analyze/mod.rs +++ b/rust/src/analyze/mod.rs @@ -17,6 +17,17 @@ * under the License. */ +use std::collections::HashMap; +use std::fmt::format; +use futures::StreamExt; +use itertools::Itertools; +use crate::analyze::pipeline::PipelineStructure; +use typedb_protocol::analyze::res as protocol; +use function::FunctionStructure; + +pub mod pipeline; +pub mod conjunction; +pub mod function; #[derive(Debug)] pub struct AnalyzeResponse { @@ -30,11 +41,42 @@ pub struct QueryStructure { preamble: FunctionStructure, } -#[derive(Debug)] -pub struct PipelineStructure { } - -#[derive(Debug)] -pub struct FunctionStructure { } +impl From for QueryStructure { + fn from(value: protocol::QueryStructure) -> Self { + let query = value.query.expect("Expected query structure").into(); + let preamble = value.preamble.into_iter().map(|f| f.into()).collect(); + Self { query, preamble } + } +} #[derive(Debug)] pub struct QueryAnnotations { } + +// Helpers +pub(crate) struct Context { + variable_names: HashMap, +} + +impl Context { + const UNNAMED: &'static str = "_"; + pub(crate) fn var_name(&self, variable: &typedb_protocol::conjunction_structure::Variable) -> Option { + self.variable_names.get(variable).cloned() + } +} + +impl Context { + fn build(pipeline_structure: &protocol::query_structure::PipelineStructure) -> Self { + let variable_names = pipeline_structure.variable_info.iter().cloned().map(|(id,name)| { + (typedb_protocol::conjunction_structure::Variable { id }, name) + }).collect(); + Self { variable_names } + } +} + +pub trait FromPipelineProto { + fn from_proto(context: &Context, value: T) -> Self; +} + +fn vec_from_proto>(context: &Context, protocol_vec: Vec) -> Vec { + protocol_vec.into_iter().map(|x| To::from_proto(context, x)).collect() +} diff --git a/rust/src/analyze/pipeline.rs b/rust/src/analyze/pipeline.rs new file mode 100644 index 000000000..f9fbb8f2d --- /dev/null +++ b/rust/src/analyze/pipeline.rs @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use typedb_protocol::analyze::{ + res as protocol, + res::query_structure::pipeline_structure as pipeline_proto +}; +use crate::analyze::conjunction::{Conjunction, ConjunctionId, Reducer, Variable}; +use crate::analyze::{Context, FromPipelineProto, vec_from_proto}; + + +#[derive(Debug)] +pub struct PipelineStructure { + conjunctions: Conjunction, + stages: Vec, +} + +impl FromPipelineProto for PipelineStructure { + fn from_proto(context: &Context, value: protocol::query_structure::PipelineStructure) -> Self { + let conjunctions = Conjunction::from_proto(context, value.conjunctions); + let stages = vec_from_proto(context, value.stages); + Self { + conjunctions, + stages + } + } +} + +#[derive(Debug)] +pub enum PipelineStage { + Match { block: ConjunctionId }, + Insert { block: ConjunctionId }, + Put { block: ConjunctionId }, + Update { block: ConjunctionId }, + Delete { block: ConjunctionId, deleted_variables: Vec }, + Select { variables: Vec }, + Sort { variables: Vec }, + Require { variables: Vec }, + Offset { offset: u64 }, + Limit { limit: u64 }, + Distinct, + Reduce { reducers: Vec }, +} + + +#[derive(Debug)] +pub struct SortVariable { + pub variable: Variable, + pub order: SortOrder, +} + +#[derive(Debug)] +pub enum SortOrder { + Ascending, + Descending, +} \ No newline at end of file From 8ed4a9443ee4b42cacf16fb17b2f024140d9ddd5 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Fri, 26 Sep 2025 01:46:06 +0200 Subject: [PATCH 04/22] WIP: Let AI fill in constraint --- rust/src/analyze/conjunction.rs | 266 +++++++++++++++++++++++++++++--- rust/src/analyze/function.rs | 36 +++-- rust/src/analyze/mod.rs | 50 ++---- rust/src/analyze/pipeline.rs | 117 +++++++++++--- 4 files changed, 379 insertions(+), 90 deletions(-) diff --git a/rust/src/analyze/conjunction.rs b/rust/src/analyze/conjunction.rs index e2607ebee..79f46ba30 100644 --- a/rust/src/analyze/conjunction.rs +++ b/rust/src/analyze/conjunction.rs @@ -17,51 +17,279 @@ * under the License. */ -use typedb_protocol::analyze::{res as protocol, res::query_structure as query_structure_proto}; +use typedb_protocol::analyze::res::query_structure; use typedb_protocol::conjunction_structure; -use crate::analyze::{Context, FromPipelineProto, vec_from_proto}; +use typedb_protocol::conjunction_structure::StructureConstraint; +use crate::analyze::vec_from_proto; +use crate::concept; #[derive(Debug)] -pub struct ConjunctionId(pub usize); +pub struct ConjunctionID(pub usize); #[derive(Debug)] pub struct Conjunction { constraints: Vec, } -impl FromPipelineProto for Conjunction { - fn from_proto(context: &Context, value: typedb_protocol::ConjunctionStructure) -> Self { - Self { constraints: vec_from_proto(context, value.constraints) } +impl TryFrom for Conjunction { + type Error = crate::analyze::TryFromError; + + fn try_from(value: typedb_protocol::ConjunctionStructure) -> Result { + Ok(Self { constraints: vec_from_proto(value.constraints)? }) } } +#[derive(Debug)] +pub enum ConstraintExactness { + Exact, + Subtypes, +} + #[derive(Debug)] pub enum Constraint { + Isa { + instance: ConstraintVertex, + r#type: ConstraintVertex, + exactness: ConstraintExactness, + }, + Has { + owner: ConstraintVertex, + attribute: ConstraintVertex, + exactness: ConstraintExactness, + }, + Links { + relation: ConstraintVertex, + player: ConstraintVertex, + role: ConstraintVertex, + exactness: ConstraintExactness, + }, + + Sub { + subtype: ConstraintVertex, + supertype: ConstraintVertex, + exactness: ConstraintExactness, + }, + Owns { + owner: ConstraintVertex, + attribute: ConstraintVertex, + exactness: ConstraintExactness, + }, + Relates { + relation: ConstraintVertex, + role: ConstraintVertex, + exactness: ConstraintExactness, + }, + Plays { + player: ConstraintVertex, + role: ConstraintVertex, + exactness: ConstraintExactness, + }, + + FunctionCall { + name: String, + assigned: Vec, + arguments: Vec, + }, + Expression { + text: String, + assigned: Vec, + arguments: Vec, + }, + Is { + lhs: ConstraintVertex, + rhs: ConstraintVertex, + }, + Iid { + concept: ConstraintVertex, + iid: Vec, + }, + Comparison { + lhs: ConstraintVertex, + rhs: ConstraintVertex, + comparator: String, + }, + Kind { + kind: concept::Kind, + r#type: ConstraintVertex, + }, + Label { + r#type: ConstraintVertex, + label: String, + }, + Value { + attribute_type: ConstraintVertex, + value_type: String, + }, + // Nested patterns are now constraints too + Or { + branches: Vec, + }, + Not { + conjunction: ConjunctionID, + }, + Try { + conjunction: ConjunctionID, + }, } -#[derive(Debug)] -pub struct Variable { - id: u32, - name: Option, +impl TryFrom for Constraint { + type Error = crate::analyze::TryFromError; + + fn try_from(value: StructureConstraint) -> Result { + use conjunction_structure::{structure_constraint as constraint_proto, structure_constraint::{Constraint as ConstraintProto}}; + let constraint = match value.constraint.ok_or("expected constraint")? { + ConstraintProto::Or(constraint_proto::Or { branches }) => { + Constraint::Or { branches: vec_from_proto(branches)? } + } + ConstraintProto::Not(constraint_proto::Not { conjunction }) => { + constraint_proto::Not { conjunction: conjunction.try_into()? } + } + ConstraintProto::Try(constraint_proto::Try { conjunction }) => { + constraint_proto::Try { conjunction: conjunction.try_into()? } + } + ConstraintProto::Isa(constraint_proto::Isa { thing: instance, r#type, exactness }) => { + Constraint::Isa { + instance: instance.try_into()?, + r#type: r#type.try_into()?, + exactness: ConstraintExactness::try_from(exactness)? + } + } + ConstraintProto::Has(constraint_proto::Has { owner, attribute, exactness }) => { + Constraint::Has { + owner: owner.try_into()?, + attribute: attribute.try_into()?, + exactness: ConstraintExactness::try_from(exactness)? + } + } + ConstraintProto::Links(constraint_proto::Links { relation, player, role, exactness }) => { + Constraint::Links { + relation: relation.try_into()?, + player: player.try_into()?, + role: role.try_into()?, + exactness: ConstraintExactness::try_from(exactness)? + } + } + ConstraintProto::Kind(constraint_proto::Kind { kind, r#type }) => { + Constraint::Kind { kind, r#type: r#type.try_into()? } + } + ConstraintProto::Sub(constraint_proto::Sub { subtype, supertype, exactness }) => { + Constraint::Sub { + subtype: subtype.try_into()?, + supertype: supertype.try_into()?, + exactness: ConstraintExactness::try_from(exactness)? + } + } + ConstraintProto::Owns(constraint_proto::Owns { owner, attribute, exactness }) => { + Constraint::Owns { + owner: owner.try_into()?, + attribute: attribute.try_into()?, + exactness: ConstraintExactness::try_from(exactness)? + } + } + ConstraintProto::Relates(constraint_proto::Relates { relation, role, exactness }) => { + Constraint::Relates { + relation: relation.try_into()?, + role: role.try_into()?, + exactness: ConstraintExactness::try_from(exactness)? + } + } + ConstraintProto::Plays(constraint_proto::Plays { player, role, exactness }) => { + Constraint::Plays { + player: player.try_into()?, + role: role.try_into()?, + exactness: ConstraintExactness::try_from(exactness)? + } + } + ConstraintProto::Value(constraint_proto::Value { attribute_type, value_type }) => { + Constraint::Value { + attribute_type: attribute_type.try_into()?, + value_type, + } + } + ConstraintProto::Label(constraint_proto::Label { r#type, label }) => { + Constraint::Label { + r#type: r#type.try_into()?, + label, + } + } + ConstraintProto::Comparison(constraint_proto::Comparison { lhs, rhs, comparator }) => { + let comparator = conjunction_structure::structure_constraint::comparison::Comparator::try_from(comparator)?; + Constraint::Comparison { + lhs: lhs.try_into()?, + rhs: rhs.try_into()?, + comparator: comparator.as_str_name().to_owned(), + } + } + ConstraintProto::Expression(constraint_proto::Expression { assigned, arguments, text }) => { + Constraint::Expression { + assigned: assigned.try_into()?, + arguments: vec_from_proto(arguments)?, + text, + } + } + ConstraintProto::FunctionCall(constraint_proto::FunctionCall { name, assigned, arguments }) => { + Constraint::FunctionCall { + name, + assigned: vec_from_proto(assigned)?, + arguments: vec_from_proto(arguments)?, + } + } + ConstraintProto::Is(constraint_proto::Is { lhs, rhs }) => { + Constraint::Is { + lhs: lhs.try_into()?, + rhs: rhs.try_into()?, + } + } + ConstraintProto::Iid(constraint_proto::Iid { concept, iid }) => { + Constraint::Iid { + concept: concept.try_into()?, + iid, + } + } + }; + Ok(constraint) + } } -impl FromPipelineProto for Variable { - fn from_proto(context: &Context, value: conjunction_structure::Variable) -> Self { - Self { id: value.id, name: context.var_name(&value) } +#[derive(Debug)] +pub struct Variable(u32); + +impl TryFrom for Variable { + type Error = crate::analyze::TryFromError; + + fn try_from(value: conjunction_structure::Variable) -> Result { + Ok(Self(value.id)) } } - #[derive(Debug)] + +#[derive(Debug)] +pub enum ConstraintVertex { + Variable(Variable), + Label(LabelVertex), + Iid(String), + Value(concept::Value), +} + +#[derive(Debug)] +pub enum LabelVertex { + Resolve(concept::Concept), + Unresolved(String), +} + +#[derive(Debug)] pub struct Reducer { variables: Vec, reducer: String, } -impl FromPipelineProto for Reducer { - fn from_proto(context: &Context, value: protocol::query_structure::Reducer) -> Self { - Self { - variables: vec_from_proto(context, value.variables), +impl TryFrom for Reducer { + type Error = crate::analyze::TryFromError; + + fn try_from(value: query_structure::Reducer) -> Result { + Ok(Self { + variables: vec_from_proto(value.variables)?, reducer: value.reducer, - } + }) } } diff --git a/rust/src/analyze/function.rs b/rust/src/analyze/function.rs index 05aeffbd3..1682df0b2 100644 --- a/rust/src/analyze/function.rs +++ b/rust/src/analyze/function.rs @@ -18,7 +18,7 @@ */ use typedb_protocol::analyze::res::query_structure; -use crate::analyze::{Context, FromPipelineProto, vec_from_proto}; +use crate::analyze::vec_from_proto; use crate::analyze::conjunction::{Reducer, Variable}; use crate::analyze::pipeline::PipelineStructure; @@ -29,14 +29,14 @@ pub struct FunctionStructure { body: PipelineStructure, } -impl From for FunctionStructure { - fn from(value: query_structure::FunctionStructure) -> Self { - let protocol_pipeline = value.body.expect("expected function body"); - let context = Context::build(&protocol_pipeline); - let body = PipelineStructure::from_proto(&context, protocol_pipeline); - let arguments = vec_from_proto(&context, value.arguments); - let returns = ReturnOperation::from_proto(&context, value.returns.expect("expected function return")); - Self { arguments, returns, body, } +impl TryFrom for FunctionStructure { + type Error = crate::analyze::TryFromError; + + fn try_from(value: query_structure::FunctionStructure) -> Result { + let body = PipelineStructure::try_from(value.body.ok_or("expected function body")?)?; + let returns = ReturnOperation::try_from(value.returns.ok_or("expected function return")?)?; + let arguments = vec_from_proto(value.arguments)?; + Ok(Self { arguments, returns, body }) } } @@ -48,18 +48,19 @@ pub enum ReturnOperation { Reduce { reducers: Vec }, } -impl FromPipelineProto for ReturnOperation { - fn from_proto(context: &Context, value: query_structure::function_structure::Returns) -> Self { +impl TryFrom for ReturnOperation { + type Error = crate::analyze::TryFromError; + + fn try_from(value: query_structure::function_structure::Returns) -> Result { use typedb_protocol::analyze::res::query_structure::function_structure::Returns; - use crate::analyze; - match value { + let returns = match value { Returns::Stream(stream) => { - Self::Stream {variables: analyze::vec_from_proto(context, stream.variables) } + Self::Stream {variables: vec_from_proto(stream.variables)? } } Returns::Single(single) => { Self::Single { selector: single.selector, - variables: analyze::vec_from_proto(context, single.variables) + variables: vec_from_proto(single.variables)? } } Returns::Check(_check) => { @@ -67,9 +68,10 @@ impl FromPipelineProto for ReturnO }, Returns::Reduce(reduce) => { Self::Reduce { - reducers: analyze::vec_from_proto(context, reduce.reducers) + reducers: vec_from_proto(reduce.reducers)? } } - } + }; + Ok(returns) } } diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs index f9d77baa9..1e4c2d548 100644 --- a/rust/src/analyze/mod.rs +++ b/rust/src/analyze/mod.rs @@ -17,10 +17,7 @@ * under the License. */ -use std::collections::HashMap; -use std::fmt::format; use futures::StreamExt; -use itertools::Itertools; use crate::analyze::pipeline::PipelineStructure; use typedb_protocol::analyze::res as protocol; use function::FunctionStructure; @@ -29,6 +26,8 @@ pub mod pipeline; pub mod conjunction; pub mod function; +pub type TryFromError = &'static str; + #[derive(Debug)] pub struct AnalyzeResponse { structure: QueryStructure, @@ -38,45 +37,24 @@ pub struct AnalyzeResponse { #[derive(Debug)] pub struct QueryStructure { query: PipelineStructure, - preamble: FunctionStructure, + preamble: Vec, } -impl From for QueryStructure { - fn from(value: protocol::QueryStructure) -> Self { - let query = value.query.expect("Expected query structure").into(); - let preamble = value.preamble.into_iter().map(|f| f.into()).collect(); - Self { query, preamble } +impl TryFrom for QueryStructure { + type Error = TryFromError; + + fn try_from(value: protocol::QueryStructure) -> Result { + let query = value.query.ok_or("Expected query structure")?.try_into()?; + let preamble = vec_from_proto(value.preamble)?; + Ok(Self { query, preamble }) } } #[derive(Debug)] pub struct QueryAnnotations { } -// Helpers -pub(crate) struct Context { - variable_names: HashMap, -} - -impl Context { - const UNNAMED: &'static str = "_"; - pub(crate) fn var_name(&self, variable: &typedb_protocol::conjunction_structure::Variable) -> Option { - self.variable_names.get(variable).cloned() - } -} - -impl Context { - fn build(pipeline_structure: &protocol::query_structure::PipelineStructure) -> Self { - let variable_names = pipeline_structure.variable_info.iter().cloned().map(|(id,name)| { - (typedb_protocol::conjunction_structure::Variable { id }, name) - }).collect(); - Self { variable_names } - } -} - -pub trait FromPipelineProto { - fn from_proto(context: &Context, value: T) -> Self; -} - -fn vec_from_proto>(context: &Context, protocol_vec: Vec) -> Vec { - protocol_vec.into_iter().map(|x| To::from_proto(context, x)).collect() +// helpers +fn vec_from_proto(protocol_vec: Vec) -> Result, TryFromError> +where To: TryFrom { + protocol_vec.into_iter().map(|x| To::try_from(x)).collect() } diff --git a/rust/src/analyze/pipeline.rs b/rust/src/analyze/pipeline.rs index f9fbb8f2d..1a2a8739b 100644 --- a/rust/src/analyze/pipeline.rs +++ b/rust/src/analyze/pipeline.rs @@ -21,43 +21,109 @@ use typedb_protocol::analyze::{ res as protocol, res::query_structure::pipeline_structure as pipeline_proto }; -use crate::analyze::conjunction::{Conjunction, ConjunctionId, Reducer, Variable}; -use crate::analyze::{Context, FromPipelineProto, vec_from_proto}; +use typedb_protocol::analyze::res::query_structure::pipeline_structure::pipeline_stage::sort::sort_variable::SortDirection; +use crate::analyze::conjunction::{Conjunction, ConjunctionID, Reducer, Variable}; +use crate::analyze::{vec_from_proto}; #[derive(Debug)] pub struct PipelineStructure { - conjunctions: Conjunction, + conjunctions: Vec, stages: Vec, } -impl FromPipelineProto for PipelineStructure { - fn from_proto(context: &Context, value: protocol::query_structure::PipelineStructure) -> Self { - let conjunctions = Conjunction::from_proto(context, value.conjunctions); - let stages = vec_from_proto(context, value.stages); - Self { - conjunctions, - stages - } +impl TryFrom for PipelineStructure { + type Error = crate::analyze::TryFromError; + + fn try_from(value: protocol::query_structure::PipelineStructure) -> Result { + let conjunctions = vec_from_proto(value.conjunctions)?; + let stages = vec_from_proto(value.stages)?; + Ok(Self { conjunctions, stages }) } } #[derive(Debug)] pub enum PipelineStage { - Match { block: ConjunctionId }, - Insert { block: ConjunctionId }, - Put { block: ConjunctionId }, - Update { block: ConjunctionId }, - Delete { block: ConjunctionId, deleted_variables: Vec }, + Match { block: ConjunctionID }, + Insert { block: ConjunctionID }, + Put { block: ConjunctionID }, + Update { block: ConjunctionID }, + Delete { block: ConjunctionID, deleted_variables: Vec }, Select { variables: Vec }, Sort { variables: Vec }, - Require { variables: Vec }, + Require { variables: Vec }, Offset { offset: u64 }, Limit { limit: u64 }, Distinct, - Reduce { reducers: Vec }, + Reduce { reducers: Vec, groupby: Vec }, +} + +#[derive(Debug)] +pub struct ReduceAssignment { + assigned: Variable, + reducer: Reducer, +} + +impl TryFrom for ReduceAssignment { + type Error = crate::analyze::TryFromError; + + fn try_from(value: pipeline_proto::pipeline_stage::reduce::ReduceAssign) -> Result { + Ok(Self { + assigned: value.assigned.ok_or("expected assigned")?.try_into()?, + reducer: value.reducer.ok_or("expected reducer")?.try_into()?, + }) + } } +impl TryFrom for PipelineStage { + type Error = crate::analyze::TryFromError; + + fn try_from(value: pipeline_proto::PipelineStage) -> Result { + use pipeline_proto::{pipeline_stage as stage_proto, pipeline_stage::Stage as StageProto}; + let stage = match value.stage.ok_or("expected stage")? { + StageProto::Match(stage_proto::Match { block }) => { + Self::Match { block: ConjunctionID(block as usize) } + }, + StageProto::Insert(stage_proto::Insert { block }) => { + Self::Insert { block: ConjunctionID(block as usize) } + } + StageProto::Put(stage_proto::Put { block }) => { + Self::Put { block: ConjunctionID(block as usize) } + } + StageProto::Update(stage_proto::Update { block }) => { + Self::Update { block: ConjunctionID(block as usize) } + } + StageProto::Delete(stage_proto::Delete { block, deleted_variables }) => { + let deleted_variables = vec_from_proto(deleted_variables)?; + Self::Delete { block: ConjunctionID(block as usize), deleted_variables } + } + StageProto::Select(stage_proto::Select { variables }) => { + Self::Select { variables: vec_from_proto(variables)? } + } + StageProto::Sort(stage_proto::Sort { sort_variables }) => { + Self::Sort { variables: vec_from_proto(sort_variables)? } + } + StageProto::Require(stage_proto::Require { variables }) => { + Self::Require { variables: vec_from_proto(variables)? } + } + StageProto::Offset(stage_proto::Offset { offset }) => { + Self::Offset { offset } + } + StageProto::Limit(stage_proto::Limit { limit }) => { + Self::Limit { limit } + } + StageProto::Distinct(stage_proto::Distinct {}) => { + Self::Distinct + } + StageProto::Reduce(stage_proto::Reduce { reducers, groupby }) => { + let reducers = vec_from_proto(reducers)?; + let groupby = vec_from_proto(groupby)?; + Self::Reduce { reducers, groupby } + } + }; + Ok(stage) + } +} #[derive(Debug)] pub struct SortVariable { @@ -65,6 +131,21 @@ pub struct SortVariable { pub order: SortOrder, } +impl TryFrom for SortVariable { + type Error = crate::analyze::TryFromError; + + fn try_from(value: pipeline_proto::pipeline_stage::sort::SortVariable) -> Result { + use pipeline_proto::pipeline_stage::sort::sort_variable::SortDirection; + Ok(Self { + variable: value.variable.ok_or("expected variable")?.try_into()?, + order: match SortDirection::try_from(value.direction).map_err(|_| "expected sort direction")? { + SortDirection::Asc => SortOrder::Ascending, + SortDirection::Desc => SortOrder::Descending, + } + }) + } +} + #[derive(Debug)] pub enum SortOrder { Ascending, From efd2352033391f0ae7050c72fd40c31d3da877a6 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Fri, 26 Sep 2025 14:46:07 +0200 Subject: [PATCH 05/22] Try using TryFromProto. pub super may work --- rust/src/analyze/conjunction.rs | 125 ++++++++++++++++++++++---------- rust/src/analyze/mod.rs | 14 +++- 2 files changed, 97 insertions(+), 42 deletions(-) diff --git a/rust/src/analyze/conjunction.rs b/rust/src/analyze/conjunction.rs index 79f46ba30..a08feeaf2 100644 --- a/rust/src/analyze/conjunction.rs +++ b/rust/src/analyze/conjunction.rs @@ -19,8 +19,8 @@ use typedb_protocol::analyze::res::query_structure; use typedb_protocol::conjunction_structure; -use typedb_protocol::conjunction_structure::StructureConstraint; -use crate::analyze::vec_from_proto; +use typedb_protocol::conjunction_structure::{StructureConstraint, StructureVertex}; +use crate::analyze::{enum_from_proto, expect_try_into, vec_from_proto}; use crate::concept; #[derive(Debug)] @@ -45,6 +45,18 @@ pub enum ConstraintExactness { Subtypes, } +impl TryFrom for ConstraintExactness { + type Error = crate::analyze::TryFromError; + + fn try_from(value: conjunction_structure::structure_constraint::ConstraintExactness) -> Result { + use conjunction_structure::structure_constraint::ConstraintExactness as ExactnessProto; + match value { + ExactnessProto::Exact => Ok(ConstraintExactness::Exact), + ExactnessProto::Subtypes => Ok(ConstraintExactness::Subtypes), + } + } +} + #[derive(Debug)] pub enum Constraint { Isa { @@ -140,90 +152,101 @@ impl TryFrom for Constraint { use conjunction_structure::{structure_constraint as constraint_proto, structure_constraint::{Constraint as ConstraintProto}}; let constraint = match value.constraint.ok_or("expected constraint")? { ConstraintProto::Or(constraint_proto::Or { branches }) => { - Constraint::Or { branches: vec_from_proto(branches)? } + let branches = branches + .iter() + .map(|branch| ConjunctionID(*branch as usize)) + .collect(); + Constraint::Or { branches } } ConstraintProto::Not(constraint_proto::Not { conjunction }) => { - constraint_proto::Not { conjunction: conjunction.try_into()? } + Constraint::Not { conjunction: ConjunctionID(conjunction as usize) } } ConstraintProto::Try(constraint_proto::Try { conjunction }) => { - constraint_proto::Try { conjunction: conjunction.try_into()? } + Constraint::Try { conjunction: ConjunctionID(conjunction as usize) } } ConstraintProto::Isa(constraint_proto::Isa { thing: instance, r#type, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; Constraint::Isa { - instance: instance.try_into()?, - r#type: r#type.try_into()?, - exactness: ConstraintExactness::try_from(exactness)? + instance: expect_try_into(instance)?, + r#type: expect_try_into(r#type)?, + exactness: ConstraintExactness::try_from(exactness_proto)?, } } ConstraintProto::Has(constraint_proto::Has { owner, attribute, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; Constraint::Has { - owner: owner.try_into()?, - attribute: attribute.try_into()?, - exactness: ConstraintExactness::try_from(exactness)? + owner: expect_try_into(owner)?, + attribute: expect_try_into(attribute)?, + exactness: ConstraintExactness::try_from(exactness_proto)? } } ConstraintProto::Links(constraint_proto::Links { relation, player, role, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; Constraint::Links { - relation: relation.try_into()?, - player: player.try_into()?, - role: role.try_into()?, - exactness: ConstraintExactness::try_from(exactness)? + relation: expect_try_into(relation)?, + player: expect_try_into(player)?, + role: expect_try_into(role)?, + exactness: ConstraintExactness::try_from(exactness_proto)? } } ConstraintProto::Kind(constraint_proto::Kind { kind, r#type }) => { - Constraint::Kind { kind, r#type: r#type.try_into()? } + Constraint::Kind { kind, r#type: expect_try_into(r#type)? } } ConstraintProto::Sub(constraint_proto::Sub { subtype, supertype, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; Constraint::Sub { - subtype: subtype.try_into()?, - supertype: supertype.try_into()?, - exactness: ConstraintExactness::try_from(exactness)? + subtype: expect_try_into(subtype)?, + supertype: expect_try_into(supertype)?, + exactness: ConstraintExactness::try_from(exactness_proto)? } } ConstraintProto::Owns(constraint_proto::Owns { owner, attribute, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; Constraint::Owns { - owner: owner.try_into()?, - attribute: attribute.try_into()?, - exactness: ConstraintExactness::try_from(exactness)? + owner: expect_try_into(owner)?, + attribute: expect_try_into(attribute)?, + exactness: ConstraintExactness::try_from(exactness_proto)? } } ConstraintProto::Relates(constraint_proto::Relates { relation, role, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; Constraint::Relates { - relation: relation.try_into()?, - role: role.try_into()?, - exactness: ConstraintExactness::try_from(exactness)? + relation: expect_try_into(relation)?, + role: expect_try_into(role)?, + exactness: ConstraintExactness::try_from(exactness_proto)? } } ConstraintProto::Plays(constraint_proto::Plays { player, role, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; Constraint::Plays { - player: player.try_into()?, - role: role.try_into()?, - exactness: ConstraintExactness::try_from(exactness)? + player: expect_try_into(player)?, + role: expect_try_into(role)?, + exactness: ConstraintExactness::try_from(exactness_proto)? } } ConstraintProto::Value(constraint_proto::Value { attribute_type, value_type }) => { Constraint::Value { - attribute_type: attribute_type.try_into()?, + attribute_type: expect_try_into(attribute_type)?, value_type, } } ConstraintProto::Label(constraint_proto::Label { r#type, label }) => { Constraint::Label { - r#type: r#type.try_into()?, + r#type: expect_try_into(r#type)?, label, } } ConstraintProto::Comparison(constraint_proto::Comparison { lhs, rhs, comparator }) => { - let comparator = conjunction_structure::structure_constraint::comparison::Comparator::try_from(comparator)?; + let comparator = enum_from_proto::(comparator)?; Constraint::Comparison { - lhs: lhs.try_into()?, - rhs: rhs.try_into()?, + lhs: expect_try_into(lhs)?, + rhs: expect_try_into(rhs)?, comparator: comparator.as_str_name().to_owned(), } } ConstraintProto::Expression(constraint_proto::Expression { assigned, arguments, text }) => { Constraint::Expression { - assigned: assigned.try_into()?, + assigned: vec_from_proto(assigned)?, arguments: vec_from_proto(arguments)?, text, } @@ -237,13 +260,13 @@ impl TryFrom for Constraint { } ConstraintProto::Is(constraint_proto::Is { lhs, rhs }) => { Constraint::Is { - lhs: lhs.try_into()?, - rhs: rhs.try_into()?, + lhs: expect_try_into(lhs)?, + rhs: expect_try_into(rhs)?, } } ConstraintProto::Iid(constraint_proto::Iid { concept, iid }) => { Constraint::Iid { - concept: concept.try_into()?, + concept: expect_try_into(concept)?, iid, } } @@ -267,16 +290,40 @@ impl TryFrom for Variable { pub enum ConstraintVertex { Variable(Variable), Label(LabelVertex), - Iid(String), Value(concept::Value), } +impl TryFrom for ConstraintVertex { + type Error = crate::analyze::TryFromError; + + fn try_from(value: conjunction_structure::StructureVertex) -> Result { + use conjunction_structure::structure_vertex::Vertex; + match value.vertex.ok_or("Expected vertex")? { + Vertex::Variable(variable) => Ok(ConstraintVertex::Variable(variable.try_into()?)), + Vertex::Label(label) => Ok(ConstraintVertex::Label(LabelVertex::try_from(label)?)), + Vertex::Value(value) => Ok(ConstraintVertex::Value(value.try_into()?)), + } + } +} + #[derive(Debug)] pub enum LabelVertex { - Resolve(concept::Concept), + Resolved(concept::Concept), Unresolved(String), } +impl TryFrom for LabelVertex { + type Error = crate::analyze::TryFromError; + + fn try_from(value: conjunction_structure::structure_vertex::Label) -> Result { + use conjunction_structure::structure_vertex::label::Label as LabelProto; + match value.label.ok_or("Expected label")? { + LabelProto::Resolved(concept) => Ok(LabelVertex::Resolved(concept.try_into()?)), + LabelProto::FailedInference(label) => Ok(LabelVertex::Unresolved(label.try_into()?)), + } + } +} + #[derive(Debug)] pub struct Reducer { variables: Vec, diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs index 1e4c2d548..1c3712c1a 100644 --- a/rust/src/analyze/mod.rs +++ b/rust/src/analyze/mod.rs @@ -54,7 +54,15 @@ impl TryFrom for QueryStructure { pub struct QueryAnnotations { } // helpers -fn vec_from_proto(protocol_vec: Vec) -> Result, TryFromError> -where To: TryFrom { - protocol_vec.into_iter().map(|x| To::try_from(x)).collect() +fn vec_from_proto(protocol_vec: Vec) -> Result, TryFromError> +where Dst: TryFrom { + protocol_vec.into_iter().map(|x| Dst::try_from(x)).collect() +} + +pub(super) fn expect_try_into>(x: Option) -> Result { + x.ok_or_else(|| format!("Expected {}", std::any::type_name::()))?.try_into() +} + +pub(super)fn enum_from_proto>(as_i32: i32) -> Result { + T::try_from(as_i32).map_err(|_| "Unknown enum value for proto enum") } From 852342f289de3b5adccee4d1d37f29d279fcb031 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Fri, 26 Sep 2025 23:28:39 +0200 Subject: [PATCH 06/22] WIP: Implement deserializing, but now need bdd --- rust/src/analyze/conjunction.rs | 215 +----------- rust/src/analyze/function.rs | 77 ----- rust/src/analyze/mod.rs | 52 ++- rust/src/analyze/pipeline.rs | 103 +----- rust/src/common/error.rs | 19 ++ rust/src/concept/type_.rs | 8 + rust/src/connection/message.rs | 2 +- rust/src/connection/network/proto/analyze.rs | 340 +++++++++++++++++++ rust/src/connection/network/proto/concept.rs | 26 +- rust/src/connection/network/proto/mod.rs | 3 +- 10 files changed, 432 insertions(+), 413 deletions(-) delete mode 100644 rust/src/analyze/function.rs create mode 100644 rust/src/connection/network/proto/analyze.rs diff --git a/rust/src/analyze/conjunction.rs b/rust/src/analyze/conjunction.rs index a08feeaf2..58ac28193 100644 --- a/rust/src/analyze/conjunction.rs +++ b/rust/src/analyze/conjunction.rs @@ -17,26 +17,17 @@ * under the License. */ -use typedb_protocol::analyze::res::query_structure; -use typedb_protocol::conjunction_structure; -use typedb_protocol::conjunction_structure::{StructureConstraint, StructureVertex}; -use crate::analyze::{enum_from_proto, expect_try_into, vec_from_proto}; -use crate::concept; +use crate::{ + concept, + concept::{type_, ValueType}, +}; #[derive(Debug)] pub struct ConjunctionID(pub usize); #[derive(Debug)] pub struct Conjunction { - constraints: Vec, -} - -impl TryFrom for Conjunction { - type Error = crate::analyze::TryFromError; - - fn try_from(value: typedb_protocol::ConjunctionStructure) -> Result { - Ok(Self { constraints: vec_from_proto(value.constraints)? }) - } + pub constraints: Vec, } #[derive(Debug)] @@ -45,18 +36,6 @@ pub enum ConstraintExactness { Subtypes, } -impl TryFrom for ConstraintExactness { - type Error = crate::analyze::TryFromError; - - fn try_from(value: conjunction_structure::structure_constraint::ConstraintExactness) -> Result { - use conjunction_structure::structure_constraint::ConstraintExactness as ExactnessProto; - match value { - ExactnessProto::Exact => Ok(ConstraintExactness::Exact), - ExactnessProto::Subtypes => Ok(ConstraintExactness::Subtypes), - } - } -} - #[derive(Debug)] pub enum Constraint { Isa { @@ -130,7 +109,7 @@ pub enum Constraint { }, Value { attribute_type: ConstraintVertex, - value_type: String, + value_type: ValueType, }, // Nested patterns are now constraints too @@ -145,146 +124,8 @@ pub enum Constraint { }, } -impl TryFrom for Constraint { - type Error = crate::analyze::TryFromError; - - fn try_from(value: StructureConstraint) -> Result { - use conjunction_structure::{structure_constraint as constraint_proto, structure_constraint::{Constraint as ConstraintProto}}; - let constraint = match value.constraint.ok_or("expected constraint")? { - ConstraintProto::Or(constraint_proto::Or { branches }) => { - let branches = branches - .iter() - .map(|branch| ConjunctionID(*branch as usize)) - .collect(); - Constraint::Or { branches } - } - ConstraintProto::Not(constraint_proto::Not { conjunction }) => { - Constraint::Not { conjunction: ConjunctionID(conjunction as usize) } - } - ConstraintProto::Try(constraint_proto::Try { conjunction }) => { - Constraint::Try { conjunction: ConjunctionID(conjunction as usize) } - } - ConstraintProto::Isa(constraint_proto::Isa { thing: instance, r#type, exactness }) => { - let exactness_proto = enum_from_proto::(exactness)?; - Constraint::Isa { - instance: expect_try_into(instance)?, - r#type: expect_try_into(r#type)?, - exactness: ConstraintExactness::try_from(exactness_proto)?, - } - } - ConstraintProto::Has(constraint_proto::Has { owner, attribute, exactness }) => { - let exactness_proto = enum_from_proto::(exactness)?; - Constraint::Has { - owner: expect_try_into(owner)?, - attribute: expect_try_into(attribute)?, - exactness: ConstraintExactness::try_from(exactness_proto)? - } - } - ConstraintProto::Links(constraint_proto::Links { relation, player, role, exactness }) => { - let exactness_proto = enum_from_proto::(exactness)?; - Constraint::Links { - relation: expect_try_into(relation)?, - player: expect_try_into(player)?, - role: expect_try_into(role)?, - exactness: ConstraintExactness::try_from(exactness_proto)? - } - } - ConstraintProto::Kind(constraint_proto::Kind { kind, r#type }) => { - Constraint::Kind { kind, r#type: expect_try_into(r#type)? } - } - ConstraintProto::Sub(constraint_proto::Sub { subtype, supertype, exactness }) => { - let exactness_proto = enum_from_proto::(exactness)?; - Constraint::Sub { - subtype: expect_try_into(subtype)?, - supertype: expect_try_into(supertype)?, - exactness: ConstraintExactness::try_from(exactness_proto)? - } - } - ConstraintProto::Owns(constraint_proto::Owns { owner, attribute, exactness }) => { - let exactness_proto = enum_from_proto::(exactness)?; - Constraint::Owns { - owner: expect_try_into(owner)?, - attribute: expect_try_into(attribute)?, - exactness: ConstraintExactness::try_from(exactness_proto)? - } - } - ConstraintProto::Relates(constraint_proto::Relates { relation, role, exactness }) => { - let exactness_proto = enum_from_proto::(exactness)?; - Constraint::Relates { - relation: expect_try_into(relation)?, - role: expect_try_into(role)?, - exactness: ConstraintExactness::try_from(exactness_proto)? - } - } - ConstraintProto::Plays(constraint_proto::Plays { player, role, exactness }) => { - let exactness_proto = enum_from_proto::(exactness)?; - Constraint::Plays { - player: expect_try_into(player)?, - role: expect_try_into(role)?, - exactness: ConstraintExactness::try_from(exactness_proto)? - } - } - ConstraintProto::Value(constraint_proto::Value { attribute_type, value_type }) => { - Constraint::Value { - attribute_type: expect_try_into(attribute_type)?, - value_type, - } - } - ConstraintProto::Label(constraint_proto::Label { r#type, label }) => { - Constraint::Label { - r#type: expect_try_into(r#type)?, - label, - } - } - ConstraintProto::Comparison(constraint_proto::Comparison { lhs, rhs, comparator }) => { - let comparator = enum_from_proto::(comparator)?; - Constraint::Comparison { - lhs: expect_try_into(lhs)?, - rhs: expect_try_into(rhs)?, - comparator: comparator.as_str_name().to_owned(), - } - } - ConstraintProto::Expression(constraint_proto::Expression { assigned, arguments, text }) => { - Constraint::Expression { - assigned: vec_from_proto(assigned)?, - arguments: vec_from_proto(arguments)?, - text, - } - } - ConstraintProto::FunctionCall(constraint_proto::FunctionCall { name, assigned, arguments }) => { - Constraint::FunctionCall { - name, - assigned: vec_from_proto(assigned)?, - arguments: vec_from_proto(arguments)?, - } - } - ConstraintProto::Is(constraint_proto::Is { lhs, rhs }) => { - Constraint::Is { - lhs: expect_try_into(lhs)?, - rhs: expect_try_into(rhs)?, - } - } - ConstraintProto::Iid(constraint_proto::Iid { concept, iid }) => { - Constraint::Iid { - concept: expect_try_into(concept)?, - iid, - } - } - }; - Ok(constraint) - } -} - #[derive(Debug)] -pub struct Variable(u32); - -impl TryFrom for Variable { - type Error = crate::analyze::TryFromError; - - fn try_from(value: conjunction_structure::Variable) -> Result { - Ok(Self(value.id)) - } -} +pub struct Variable(pub u32); #[derive(Debug)] pub enum ConstraintVertex { @@ -293,50 +134,14 @@ pub enum ConstraintVertex { Value(concept::Value), } -impl TryFrom for ConstraintVertex { - type Error = crate::analyze::TryFromError; - - fn try_from(value: conjunction_structure::StructureVertex) -> Result { - use conjunction_structure::structure_vertex::Vertex; - match value.vertex.ok_or("Expected vertex")? { - Vertex::Variable(variable) => Ok(ConstraintVertex::Variable(variable.try_into()?)), - Vertex::Label(label) => Ok(ConstraintVertex::Label(LabelVertex::try_from(label)?)), - Vertex::Value(value) => Ok(ConstraintVertex::Value(value.try_into()?)), - } - } -} - #[derive(Debug)] pub enum LabelVertex { - Resolved(concept::Concept), + Resolved(type_::Type), Unresolved(String), } -impl TryFrom for LabelVertex { - type Error = crate::analyze::TryFromError; - - fn try_from(value: conjunction_structure::structure_vertex::Label) -> Result { - use conjunction_structure::structure_vertex::label::Label as LabelProto; - match value.label.ok_or("Expected label")? { - LabelProto::Resolved(concept) => Ok(LabelVertex::Resolved(concept.try_into()?)), - LabelProto::FailedInference(label) => Ok(LabelVertex::Unresolved(label.try_into()?)), - } - } -} - #[derive(Debug)] pub struct Reducer { - variables: Vec, - reducer: String, -} - -impl TryFrom for Reducer { - type Error = crate::analyze::TryFromError; - - fn try_from(value: query_structure::Reducer) -> Result { - Ok(Self { - variables: vec_from_proto(value.variables)?, - reducer: value.reducer, - }) - } + pub variables: Vec, + pub reducer: String, } diff --git a/rust/src/analyze/function.rs b/rust/src/analyze/function.rs deleted file mode 100644 index 1682df0b2..000000000 --- a/rust/src/analyze/function.rs +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -use typedb_protocol::analyze::res::query_structure; -use crate::analyze::vec_from_proto; -use crate::analyze::conjunction::{Reducer, Variable}; -use crate::analyze::pipeline::PipelineStructure; - -#[derive(Debug)] -pub struct FunctionStructure { - arguments: Vec, - returns: ReturnOperation, - body: PipelineStructure, -} - -impl TryFrom for FunctionStructure { - type Error = crate::analyze::TryFromError; - - fn try_from(value: query_structure::FunctionStructure) -> Result { - let body = PipelineStructure::try_from(value.body.ok_or("expected function body")?)?; - let returns = ReturnOperation::try_from(value.returns.ok_or("expected function return")?)?; - let arguments = vec_from_proto(value.arguments)?; - Ok(Self { arguments, returns, body }) - } -} - -#[derive(Debug)] -pub enum ReturnOperation { - Stream { variables: Vec }, - Single { selector: String, variables: Vec }, - Check {}, - Reduce { reducers: Vec }, -} - -impl TryFrom for ReturnOperation { - type Error = crate::analyze::TryFromError; - - fn try_from(value: query_structure::function_structure::Returns) -> Result { - use typedb_protocol::analyze::res::query_structure::function_structure::Returns; - let returns = match value { - Returns::Stream(stream) => { - Self::Stream {variables: vec_from_proto(stream.variables)? } - } - Returns::Single(single) => { - Self::Single { - selector: single.selector, - variables: vec_from_proto(single.variables)? - } - } - Returns::Check(_check) => { - Self::Check {} - }, - Returns::Reduce(reduce) => { - Self::Reduce { - reducers: vec_from_proto(reduce.reducers)? - } - } - }; - Ok(returns) - } -} diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs index 1c3712c1a..5508a2a56 100644 --- a/rust/src/analyze/mod.rs +++ b/rust/src/analyze/mod.rs @@ -18,51 +18,43 @@ */ use futures::StreamExt; -use crate::analyze::pipeline::PipelineStructure; -use typedb_protocol::analyze::res as protocol; -use function::FunctionStructure; -pub mod pipeline; +use crate::analyze::{ + conjunction::{Reducer, Variable}, + pipeline::PipelineStructure, +}; + pub mod conjunction; -pub mod function; +pub mod pipeline; pub type TryFromError = &'static str; #[derive(Debug)] pub struct AnalyzeResponse { - structure: QueryStructure, - annotations: QueryAnnotations, + pub structure: QueryStructure, + pub annotations: QueryAnnotations, } #[derive(Debug)] pub struct QueryStructure { - query: PipelineStructure, - preamble: Vec, -} - -impl TryFrom for QueryStructure { - type Error = TryFromError; - - fn try_from(value: protocol::QueryStructure) -> Result { - let query = value.query.ok_or("Expected query structure")?.try_into()?; - let preamble = vec_from_proto(value.preamble)?; - Ok(Self { query, preamble }) - } + pub query: PipelineStructure, + pub preamble: Vec, } #[derive(Debug)] -pub struct QueryAnnotations { } - -// helpers -fn vec_from_proto(protocol_vec: Vec) -> Result, TryFromError> -where Dst: TryFrom { - protocol_vec.into_iter().map(|x| Dst::try_from(x)).collect() +pub struct FunctionStructure { + pub arguments: Vec, + pub returns: ReturnOperation, + pub body: PipelineStructure, } -pub(super) fn expect_try_into>(x: Option) -> Result { - x.ok_or_else(|| format!("Expected {}", std::any::type_name::()))?.try_into() +#[derive(Debug)] +pub enum ReturnOperation { + Stream { variables: Vec }, + Single { selector: String, variables: Vec }, + Check {}, + Reduce { reducers: Vec }, } -pub(super)fn enum_from_proto>(as_i32: i32) -> Result { - T::try_from(as_i32).map_err(|_| "Unknown enum value for proto enum") -} +#[derive(Debug)] +pub struct QueryAnnotations {} diff --git a/rust/src/analyze/pipeline.rs b/rust/src/analyze/pipeline.rs index 1a2a8739b..f16118d1a 100644 --- a/rust/src/analyze/pipeline.rs +++ b/rust/src/analyze/pipeline.rs @@ -17,29 +17,12 @@ * under the License. */ -use typedb_protocol::analyze::{ - res as protocol, - res::query_structure::pipeline_structure as pipeline_proto -}; -use typedb_protocol::analyze::res::query_structure::pipeline_structure::pipeline_stage::sort::sort_variable::SortDirection; use crate::analyze::conjunction::{Conjunction, ConjunctionID, Reducer, Variable}; -use crate::analyze::{vec_from_proto}; - #[derive(Debug)] pub struct PipelineStructure { - conjunctions: Vec, - stages: Vec, -} - -impl TryFrom for PipelineStructure { - type Error = crate::analyze::TryFromError; - - fn try_from(value: protocol::query_structure::PipelineStructure) -> Result { - let conjunctions = vec_from_proto(value.conjunctions)?; - let stages = vec_from_proto(value.stages)?; - Ok(Self { conjunctions, stages }) - } + pub conjunctions: Vec, + pub stages: Vec, } #[derive(Debug)] @@ -60,69 +43,8 @@ pub enum PipelineStage { #[derive(Debug)] pub struct ReduceAssignment { - assigned: Variable, - reducer: Reducer, -} - -impl TryFrom for ReduceAssignment { - type Error = crate::analyze::TryFromError; - - fn try_from(value: pipeline_proto::pipeline_stage::reduce::ReduceAssign) -> Result { - Ok(Self { - assigned: value.assigned.ok_or("expected assigned")?.try_into()?, - reducer: value.reducer.ok_or("expected reducer")?.try_into()?, - }) - } -} - -impl TryFrom for PipelineStage { - type Error = crate::analyze::TryFromError; - - fn try_from(value: pipeline_proto::PipelineStage) -> Result { - use pipeline_proto::{pipeline_stage as stage_proto, pipeline_stage::Stage as StageProto}; - let stage = match value.stage.ok_or("expected stage")? { - StageProto::Match(stage_proto::Match { block }) => { - Self::Match { block: ConjunctionID(block as usize) } - }, - StageProto::Insert(stage_proto::Insert { block }) => { - Self::Insert { block: ConjunctionID(block as usize) } - } - StageProto::Put(stage_proto::Put { block }) => { - Self::Put { block: ConjunctionID(block as usize) } - } - StageProto::Update(stage_proto::Update { block }) => { - Self::Update { block: ConjunctionID(block as usize) } - } - StageProto::Delete(stage_proto::Delete { block, deleted_variables }) => { - let deleted_variables = vec_from_proto(deleted_variables)?; - Self::Delete { block: ConjunctionID(block as usize), deleted_variables } - } - StageProto::Select(stage_proto::Select { variables }) => { - Self::Select { variables: vec_from_proto(variables)? } - } - StageProto::Sort(stage_proto::Sort { sort_variables }) => { - Self::Sort { variables: vec_from_proto(sort_variables)? } - } - StageProto::Require(stage_proto::Require { variables }) => { - Self::Require { variables: vec_from_proto(variables)? } - } - StageProto::Offset(stage_proto::Offset { offset }) => { - Self::Offset { offset } - } - StageProto::Limit(stage_proto::Limit { limit }) => { - Self::Limit { limit } - } - StageProto::Distinct(stage_proto::Distinct {}) => { - Self::Distinct - } - StageProto::Reduce(stage_proto::Reduce { reducers, groupby }) => { - let reducers = vec_from_proto(reducers)?; - let groupby = vec_from_proto(groupby)?; - Self::Reduce { reducers, groupby } - } - }; - Ok(stage) - } + pub assigned: Variable, + pub reducer: Reducer, } #[derive(Debug)] @@ -131,23 +53,8 @@ pub struct SortVariable { pub order: SortOrder, } -impl TryFrom for SortVariable { - type Error = crate::analyze::TryFromError; - - fn try_from(value: pipeline_proto::pipeline_stage::sort::SortVariable) -> Result { - use pipeline_proto::pipeline_stage::sort::sort_variable::SortDirection; - Ok(Self { - variable: value.variable.ok_or("expected variable")?.try_into()?, - order: match SortDirection::try_from(value.direction).map_err(|_| "expected sort direction")? { - SortDirection::Asc => SortOrder::Ascending, - SortDirection::Desc => SortOrder::Descending, - } - }) - } -} - #[derive(Debug)] pub enum SortOrder { Ascending, Descending, -} \ No newline at end of file +} diff --git a/rust/src/common/error.rs b/rust/src/common/error.rs index 207376352..0e7fad58d 100644 --- a/rust/src/common/error.rs +++ b/rust/src/common/error.rs @@ -116,6 +116,14 @@ macro_rules! error_messages { }; } +error_messages! { AnalyzeError + code: "ANZ", type: "Analyze Error", + MissingResponseField { field: &'static str } = + 1: "Missing field in message received from server: '{field}'. This is either a version compatibility issue or a bug.", + UnknownEnumValue { enum_name: &'static str, value: i32 } = + 2: "Value '{value}' is out of bounds for enum '{enum_name}'. This is either a version compatibility issue or a bug.", +} + error_messages! { ConnectionError code: "CXN", type: "Connection Error", RPCMethodUnavailable { message: String } = @@ -277,6 +285,7 @@ impl fmt::Debug for ServerError { /// Represents errors encountered during operation. #[derive(Clone, Debug, PartialEq, Eq)] pub enum Error { + Analyze(AnalyzeError), Connection(ConnectionError), Concept(ConceptError), Migration(MigrationError), @@ -288,6 +297,7 @@ pub enum Error { impl Error { pub fn code(&self) -> String { match self { + Self::Analyze(error) => error.format_code(), Self::Connection(error) => error.format_code(), Self::Concept(error) => error.format_code(), Self::Migration(error) => error.format_code(), @@ -299,6 +309,7 @@ impl Error { pub fn message(&self) -> String { match self { + Self::Analyze(error) => error.message(), Self::Connection(error) => error.message(), Self::Concept(error) => error.message(), Self::Migration(error) => error.message(), @@ -341,6 +352,7 @@ impl Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { + Self::Analyze(error) => write!(f, "{error}"), Self::Connection(error) => write!(f, "{error}"), Self::Concept(error) => write!(f, "{error}"), Self::Migration(error) => write!(f, "{error}"), @@ -354,6 +366,7 @@ impl fmt::Display for Error { impl StdError for Error { fn source(&self) -> Option<&(dyn StdError + 'static)> { match self { + Self::Analyze(error) => Some(error), Self::Connection(error) => Some(error), Self::Concept(error) => Some(error), Self::Migration(error) => Some(error), @@ -364,6 +377,12 @@ impl StdError for Error { } } +impl From for Error { + fn from(error: AnalyzeError) -> Self { + Self::Analyze(error) + } +} + impl From for Error { fn from(error: ConnectionError) -> Self { Self::Connection(error) diff --git a/rust/src/concept/type_.rs b/rust/src/concept/type_.rs index aba61882c..c51f221a9 100644 --- a/rust/src/concept/type_.rs +++ b/rust/src/concept/type_.rs @@ -21,6 +21,14 @@ use std::fmt::{Debug, Display, Formatter}; use super::ValueType; +#[derive(Clone, Debug, PartialEq)] +pub enum Type { + EntityType(EntityType), + RelationType(RelationType), + AttributeType(AttributeType), + RoleType(RoleType), +} + /// Entity types represent the classification of independent objects in the data model /// of the business domain. #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/rust/src/connection/message.rs b/rust/src/connection/message.rs index b0463310e..8cdee3662 100644 --- a/rust/src/connection/message.rs +++ b/rust/src/connection/message.rs @@ -25,6 +25,7 @@ use typedb_protocol::{database, database_manager, migration::Item, transaction}; use uuid::Uuid; use crate::{ + analyze::AnalyzeResponse, answer::{ concept_document::{ConceptDocumentHeader, Node}, concept_row::ConceptRowHeader, @@ -36,7 +37,6 @@ use crate::{ info::UserInfo, Credentials, QueryOptions, TransactionOptions, TransactionType, }; -use crate::analyze::AnalyzeResponse; #[derive(Debug)] pub(super) enum Request { diff --git a/rust/src/connection/network/proto/analyze.rs b/rust/src/connection/network/proto/analyze.rs new file mode 100644 index 000000000..ebb639150 --- /dev/null +++ b/rust/src/connection/network/proto/analyze.rs @@ -0,0 +1,340 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use typedb_protocol::{ + analyze::{ + res as analyze_proto, + res::{ + query_structure, + query_structure::{ + pipeline_structure, pipeline_structure::pipeline_stage::sort::sort_variable::SortDirection, + }, + }, + }, + conjunction_structure, + conjunction_structure::StructureConstraint, + ConjunctionStructure, +}; + +use crate::{ + analyze::{ + conjunction::{ + Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, LabelVertex, Reducer, + Variable, + }, + pipeline::{PipelineStage, PipelineStructure, ReduceAssignment, SortOrder, SortVariable}, + FunctionStructure, QueryStructure, ReturnOperation, + }, + common::Result, + concept, + concept::{type_, Kind, Value}, + connection::network::proto::TryFromProto, + error::AnalyzeError, +}; + +pub(super) fn expect_try_into>(x: Option, field: &'static str) -> Result { + Dst::try_from_proto(x.ok_or_else(|| crate::Error::Analyze(AnalyzeError::MissingResponseField { field }))?) +} + +fn vec_from_proto(protocol_vec: Vec) -> Result> +where + Dst: TryFromProto, +{ + protocol_vec.into_iter().map(|x| Dst::try_from_proto(x)).collect() +} + +fn enum_from_proto>(as_i32: i32) -> Result { + T::try_from(as_i32) + .map_err(|_| AnalyzeError::UnknownEnumValue { enum_name: std::any::type_name::(), value: as_i32 }.into()) +} + +impl TryFromProto for QueryStructure { + fn try_from_proto(value: analyze_proto::QueryStructure) -> Result { + let query = expect_try_into(value.query, "QueryStructure.query")?; + let preamble = vec_from_proto(value.preamble)?; + Ok(Self { query, preamble }) + } +} + +impl TryFromProto for FunctionStructure { + fn try_from_proto(value: query_structure::FunctionStructure) -> Result { + let body = expect_try_into(value.body, "FunctionStructure.body")?; + let returns = expect_try_into(value.returns, "FunctionStructure.returns")?; + let arguments = vec_from_proto(value.arguments)?; + Ok(Self { arguments, returns, body }) + } +} + +impl TryFromProto for ReturnOperation { + fn try_from_proto(value: query_structure::function_structure::Returns) -> Result { + use typedb_protocol::analyze::res::query_structure::function_structure::Returns; + let returns = match value { + Returns::Stream(stream) => Self::Stream { variables: vec_from_proto(stream.variables)? }, + Returns::Single(single) => { + Self::Single { selector: single.selector, variables: vec_from_proto(single.variables)? } + } + Returns::Check(_check) => Self::Check {}, + Returns::Reduce(reduce) => Self::Reduce { reducers: vec_from_proto(reduce.reducers)? }, + }; + Ok(returns) + } +} + +impl TryFromProto for PipelineStructure { + fn try_from_proto(value: query_structure::PipelineStructure) -> Result { + let conjunctions = vec_from_proto(value.conjunctions)?; + let stages = vec_from_proto(value.stages)?; + Ok(Self { conjunctions, stages }) + } +} + +impl TryFromProto for PipelineStage { + fn try_from_proto(value: pipeline_structure::PipelineStage) -> Result { + use pipeline_structure::{pipeline_stage as stage_proto, pipeline_stage::Stage as StageProto}; + let unwrapped = value.stage.ok_or_else(|| { + crate::Error::Analyze(AnalyzeError::MissingResponseField { field: "PipelineStage.stage" }) + })?; + let stage = match unwrapped { + StageProto::Match(stage_proto::Match { block }) => Self::Match { block: ConjunctionID(block as usize) }, + StageProto::Insert(stage_proto::Insert { block }) => Self::Insert { block: ConjunctionID(block as usize) }, + StageProto::Put(stage_proto::Put { block }) => Self::Put { block: ConjunctionID(block as usize) }, + StageProto::Update(stage_proto::Update { block }) => Self::Update { block: ConjunctionID(block as usize) }, + StageProto::Delete(stage_proto::Delete { block, deleted_variables }) => { + let deleted_variables = vec_from_proto(deleted_variables)?; + Self::Delete { block: ConjunctionID(block as usize), deleted_variables } + } + StageProto::Select(stage_proto::Select { variables }) => { + Self::Select { variables: vec_from_proto(variables)? } + } + StageProto::Sort(stage_proto::Sort { sort_variables }) => { + Self::Sort { variables: vec_from_proto(sort_variables)? } + } + StageProto::Require(stage_proto::Require { variables }) => { + Self::Require { variables: vec_from_proto(variables)? } + } + StageProto::Offset(stage_proto::Offset { offset }) => Self::Offset { offset }, + StageProto::Limit(stage_proto::Limit { limit }) => Self::Limit { limit }, + StageProto::Distinct(stage_proto::Distinct {}) => Self::Distinct, + StageProto::Reduce(stage_proto::Reduce { reducers, groupby }) => { + let reducers = vec_from_proto(reducers)?; + let groupby = vec_from_proto(groupby)?; + Self::Reduce { reducers, groupby } + } + }; + Ok(stage) + } +} + +impl TryFromProto for ReduceAssignment { + fn try_from_proto(value: pipeline_structure::pipeline_stage::reduce::ReduceAssign) -> Result { + Ok(Self { + assigned: expect_try_into(value.assigned, "ReduceAssign.assigned")?, + reducer: expect_try_into(value.reducer, "ReduceAssign.reducer")?, + }) + } +} + +impl TryFromProto for Reducer { + fn try_from_proto(value: query_structure::Reducer) -> Result { + Ok(Self { variables: vec_from_proto(value.variables)?, reducer: value.reducer }) + } +} + +impl TryFromProto for Constraint { + fn try_from_proto(value: StructureConstraint) -> Result { + use conjunction_structure::{ + structure_constraint as constraint_proto, structure_constraint::Constraint as ConstraintProto, + }; + let unwrapped = value.constraint.ok_or_else(|| { + crate::Error::Analyze(AnalyzeError::MissingResponseField { field: "StructureConstraint.constraint" }) + })?; + let constraint = match unwrapped { + ConstraintProto::Or(constraint_proto::Or { branches }) => { + let branches = branches.iter().map(|branch| ConjunctionID(*branch as usize)).collect(); + Constraint::Or { branches } + } + ConstraintProto::Not(constraint_proto::Not { conjunction }) => { + Constraint::Not { conjunction: ConjunctionID(conjunction as usize) } + } + ConstraintProto::Try(constraint_proto::Try { conjunction }) => { + Constraint::Try { conjunction: ConjunctionID(conjunction as usize) } + } + ConstraintProto::Isa(constraint_proto::Isa { thing: instance, r#type, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; + Constraint::Isa { + instance: expect_try_into(instance, "structure_constraint::Isa.instance")?, + r#type: expect_try_into(r#type, "structure_constraint::Isa.type")?, + exactness: ConstraintExactness::try_from_proto(exactness_proto)?, + } + } + ConstraintProto::Has(constraint_proto::Has { owner, attribute, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; + Constraint::Has { + owner: expect_try_into(owner, "structure_constraint::Has.owner")?, + attribute: expect_try_into(attribute, "structure_constraint::Has.attribute")?, + exactness: ConstraintExactness::try_from_proto(exactness_proto)?, + } + } + ConstraintProto::Links(constraint_proto::Links { relation, player, role, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; + Constraint::Links { + relation: expect_try_into(relation, "structure_constraint::Links.relation")?, + player: expect_try_into(player, "structure_constraint::Links.player")?, + role: expect_try_into(role, "structure_constraint::Links.role")?, + exactness: ConstraintExactness::try_from_proto(exactness_proto)?, + } + } + ConstraintProto::Kind(constraint_proto::Kind { kind, r#type }) => Constraint::Kind { + kind: Kind::try_from_proto(kind)?, + r#type: expect_try_into(r#type, "structure_constraint::Kind.kind")?, + }, + ConstraintProto::Sub(constraint_proto::Sub { subtype, supertype, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; + Constraint::Sub { + subtype: expect_try_into(subtype, "structure_constraint::Sub.subtype")?, + supertype: expect_try_into(supertype, "structure_constraint::Sub.supertype")?, + exactness: ConstraintExactness::try_from_proto(exactness_proto)?, + } + } + ConstraintProto::Owns(constraint_proto::Owns { owner, attribute, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; + Constraint::Owns { + owner: expect_try_into(owner, "structure_constraint::Owns.owner")?, + attribute: expect_try_into(attribute, "structure_constraint::Owns.attribute")?, + exactness: ConstraintExactness::try_from_proto(exactness_proto)?, + } + } + ConstraintProto::Relates(constraint_proto::Relates { relation, role, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; + Constraint::Relates { + relation: expect_try_into(relation, "structure_constraint::Relates.relation")?, + role: expect_try_into(role, "structure_constraint::Relates.role")?, + exactness: ConstraintExactness::try_from_proto(exactness_proto)?, + } + } + ConstraintProto::Plays(constraint_proto::Plays { player, role, exactness }) => { + let exactness_proto = enum_from_proto::(exactness)?; + Constraint::Plays { + player: expect_try_into(player, "structure_constraint::Plays.player")?, + role: expect_try_into(role, "structure_constraint::Plays.role")?, + exactness: ConstraintExactness::try_from_proto(exactness_proto)?, + } + } + ConstraintProto::Value(constraint_proto::Value { attribute_type, value_type }) => Constraint::Value { + attribute_type: expect_try_into(attribute_type, "structure_constraint::Value.attribute_type")?, + value_type: expect_try_into(value_type, "structure_constraint::Value.value_type")?, + }, + ConstraintProto::Label(constraint_proto::Label { r#type, label }) => { + Constraint::Label { r#type: expect_try_into(r#type, "structure_constraint::Label.type")?, label } + } + ConstraintProto::Comparison(constraint_proto::Comparison { lhs, rhs, comparator }) => { + let comparator = + enum_from_proto::(comparator)?; + Constraint::Comparison { + lhs: expect_try_into(lhs, "structure_constraint::Comparison.lhs")?, + rhs: expect_try_into(rhs, "structure_constraint::Comparison.rhs")?, + comparator: comparator.as_str_name().to_owned(), + } + } + ConstraintProto::Expression(constraint_proto::Expression { assigned, arguments, text }) => { + Constraint::Expression { + assigned: vec_from_proto(assigned)?, + arguments: vec_from_proto(arguments)?, + text, + } + } + ConstraintProto::FunctionCall(constraint_proto::FunctionCall { name, assigned, arguments }) => { + Constraint::FunctionCall { + name, + assigned: vec_from_proto(assigned)?, + arguments: vec_from_proto(arguments)?, + } + } + ConstraintProto::Is(constraint_proto::Is { lhs, rhs }) => Constraint::Is { + lhs: expect_try_into(lhs, "structure_constraint::Is.lhs")?, + rhs: expect_try_into(rhs, "structure_constraint::Is.rhs")?, + }, + ConstraintProto::Iid(constraint_proto::Iid { concept, iid }) => { + Constraint::Iid { concept: expect_try_into(concept, "structure_constraint::Iid.concept")?, iid } + } + }; + Ok(constraint) + } +} + +impl TryFromProto for Conjunction { + fn try_from_proto(proto: ConjunctionStructure) -> Result { + Ok(Self { constraints: vec_from_proto(proto.constraints)? }) + } +} + +impl TryFromProto for SortVariable { + fn try_from_proto(value: pipeline_structure::pipeline_stage::sort::SortVariable) -> Result { + use pipeline_structure::pipeline_stage::sort::sort_variable::SortDirection; + Ok(Self { + variable: expect_try_into(value.variable, "SortVariable.variable")?, + order: match enum_from_proto(value.direction)? { + SortDirection::Asc => SortOrder::Ascending, + SortDirection::Desc => SortOrder::Descending, + }, + }) + } +} + +impl TryFromProto for LabelVertex { + fn try_from_proto(value: conjunction_structure::structure_vertex::Label) -> Result { + use conjunction_structure::structure_vertex::label::Label as LabelProto; + match value.label { + Some(LabelProto::FailedInference(label)) => Ok(LabelVertex::Unresolved(label)), + Some(LabelProto::Resolved(type_proto)) => { + let type_ = type_::Type::try_from_proto(type_proto)?; + Ok(LabelVertex::Resolved(type_)) + } + None => Err(AnalyzeError::MissingResponseField { field: "LabelVertex.label" }.into()), + } + } +} + +impl TryFromProto for ConstraintVertex { + fn try_from_proto(value: conjunction_structure::StructureVertex) -> Result { + use conjunction_structure::structure_vertex::Vertex; + match value.vertex { + Some(Vertex::Variable(variable)) => Ok(ConstraintVertex::Variable(Variable::try_from_proto(variable)?)), + Some(Vertex::Label(label)) => Ok(ConstraintVertex::Label(LabelVertex::try_from_proto(label)?)), + Some(Vertex::Value(value)) => Ok(ConstraintVertex::Value(Value::try_from_proto(value)?)), + None => Err(AnalyzeError::MissingResponseField { field: "StructureVertex.vertex" }.into()), + } + } +} + +impl TryFromProto for ConstraintExactness { + fn try_from_proto(value: conjunction_structure::structure_constraint::ConstraintExactness) -> Result { + use conjunction_structure::structure_constraint::ConstraintExactness as ConstraintExactnessProto; + Ok(match value { + ConstraintExactnessProto::Exact => ConstraintExactness::Exact, + ConstraintExactnessProto::Subtypes => ConstraintExactness::Subtypes, + }) + } +} + +impl TryFromProto for Variable { + fn try_from_proto(value: conjunction_structure::Variable) -> Result { + Ok(Self(value.id)) + } +} diff --git a/rust/src/connection/network/proto/concept.rs b/rust/src/connection/network/proto/concept.rs index fb4c3c4c3..464cbc90b 100644 --- a/rust/src/connection/network/proto/concept.rs +++ b/rust/src/connection/network/proto/concept.rs @@ -32,13 +32,15 @@ use typedb_protocol::{ Attribute as AttributeProto, AttributeType as AttributeTypeProto, Concept as ConceptProto, ConceptDocument as ConceptDocumentProto, ConceptRow as ConceptRowProto, Entity as EntityProto, EntityType as EntityTypeProto, Relation as RelationProto, RelationType as RelationTypeProto, - RoleType as RoleTypeProto, Value as ValueProto, ValueType as ValueTypeStructProto, + RoleType as RoleTypeProto, Type as TypeProto, Value as ValueProto, ValueType as ValueTypeStructProto, }; use super::{FromProto, TryFromProto}; use crate::{ answer::concept_document::{Leaf, Node}, concept::{ + type_, + type_::Type, value::{Decimal, TimeZone}, Attribute, AttributeType, Concept, Entity, EntityType, Kind, Relation, RelationType, RoleType, Value, ValueType, @@ -101,6 +103,28 @@ impl TryFromProto for Concept { } } +impl TryFromProto for Type { + fn try_from_proto(proto: TypeProto) -> Result { + let TypeProto { r#type: type_proto } = proto; + match type_proto { + Some(typedb_protocol::r#type::Type::EntityType(entity_type_proto)) => { + Ok(Self::EntityType(EntityType::from_proto(entity_type_proto))) + } + Some(typedb_protocol::r#type::Type::RelationType(relation_type_proto)) => { + Ok(Self::RelationType(RelationType::from_proto(relation_type_proto))) + } + Some(typedb_protocol::r#type::Type::AttributeType(attribute_type_proto)) => { + Ok(Self::AttributeType(AttributeType::from_proto(attribute_type_proto))) + } + Some(typedb_protocol::r#type::Type::RoleType(role_type_proto)) => { + Ok(Self::RoleType(RoleType::from_proto(role_type_proto))) + } + + None => Err(MissingResponseField { field: "type" }.into()), + } + } +} + impl TryFromProto for Node { fn try_from_proto(proto: concept_document::Node) -> Result { match proto.node { diff --git a/rust/src/connection/network/proto/mod.rs b/rust/src/connection/network/proto/mod.rs index bf307ee5c..cea01e2db 100644 --- a/rust/src/connection/network/proto/mod.rs +++ b/rust/src/connection/network/proto/mod.rs @@ -17,8 +17,9 @@ * under the License. */ -use crate::Result; +use crate::{analyze::TryFromError, Result}; +mod analyze; mod common; mod concept; mod database; From 6d37d311b5abe4149977ee4b09ccf1194af45579 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Sat, 27 Sep 2025 02:15:18 +0200 Subject: [PATCH 07/22] WIP: It kinda runs but stream single problems --- rust/src/analyze/conjunction.rs | 4 +- rust/src/analyze/mod.rs | 2 +- rust/src/analyze/pipeline.rs | 8 +- rust/src/concept/type_.rs | 11 + rust/src/connection/message.rs | 5 +- rust/src/connection/network/proto/analyze.rs | 47 +++- rust/src/connection/network/proto/message.rs | 6 +- rust/src/connection/transaction_stream.rs | 8 + rust/src/transaction.rs | 17 ++ rust/tests/behaviour/steps/lib.rs | 12 + rust/tests/behaviour/steps/query.rs | 55 +++- rust/tests/behaviour/steps/util.rs | 259 +++++++++++++++++++ 12 files changed, 413 insertions(+), 21 deletions(-) diff --git a/rust/src/analyze/conjunction.rs b/rust/src/analyze/conjunction.rs index 58ac28193..429722433 100644 --- a/rust/src/analyze/conjunction.rs +++ b/rust/src/analyze/conjunction.rs @@ -124,7 +124,7 @@ pub enum Constraint { }, } -#[derive(Debug)] +#[derive(Debug, Hash, Clone, Eq, PartialEq)] pub struct Variable(pub u32); #[derive(Debug)] @@ -142,6 +142,6 @@ pub enum LabelVertex { #[derive(Debug)] pub struct Reducer { - pub variables: Vec, + pub arguments: Vec, pub reducer: String, } diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs index 5508a2a56..ced9e2e35 100644 --- a/rust/src/analyze/mod.rs +++ b/rust/src/analyze/mod.rs @@ -30,7 +30,7 @@ pub mod pipeline; pub type TryFromError = &'static str; #[derive(Debug)] -pub struct AnalyzeResponse { +pub struct AnalyzedQuery { pub structure: QueryStructure, pub annotations: QueryAnnotations, } diff --git a/rust/src/analyze/pipeline.rs b/rust/src/analyze/pipeline.rs index f16118d1a..0a989ec33 100644 --- a/rust/src/analyze/pipeline.rs +++ b/rust/src/analyze/pipeline.rs @@ -17,12 +17,16 @@ * under the License. */ +use std::collections::HashMap; + use crate::analyze::conjunction::{Conjunction, ConjunctionID, Reducer, Variable}; #[derive(Debug)] pub struct PipelineStructure { pub conjunctions: Vec, pub stages: Vec, + pub variable_names: HashMap, + pub outputs: Vec, } #[derive(Debug)] @@ -38,11 +42,11 @@ pub enum PipelineStage { Offset { offset: u64 }, Limit { limit: u64 }, Distinct, - Reduce { reducers: Vec, groupby: Vec }, + Reduce { reducers: Vec, groupby: Vec }, } #[derive(Debug)] -pub struct ReduceAssignment { +pub struct ReduceAssign { pub assigned: Variable, pub reducer: Reducer, } diff --git a/rust/src/concept/type_.rs b/rust/src/concept/type_.rs index c51f221a9..b2436eae8 100644 --- a/rust/src/concept/type_.rs +++ b/rust/src/concept/type_.rs @@ -29,6 +29,17 @@ pub enum Type { RoleType(RoleType), } +impl Type { + pub fn label(&self) -> &str { + match self { + Type::EntityType(entity_type) => entity_type.label(), + Type::RelationType(relation_type) => relation_type.label(), + Type::AttributeType(attribute_type) => attribute_type.label(), + Type::RoleType(role_type) => role_type.label(), + } + } +} + /// Entity types represent the classification of independent objects in the data model /// of the business domain. #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/rust/src/connection/message.rs b/rust/src/connection/message.rs index 8cdee3662..db3713095 100644 --- a/rust/src/connection/message.rs +++ b/rust/src/connection/message.rs @@ -25,7 +25,7 @@ use typedb_protocol::{database, database_manager, migration::Item, transaction}; use uuid::Uuid; use crate::{ - analyze::AnalyzeResponse, + analyze::AnalyzedQuery, answer::{ concept_document::{ConceptDocumentHeader, Node}, concept_row::ConceptRowHeader, @@ -145,6 +145,7 @@ pub(super) enum TransactionRequest { Open { database: String, transaction_type: TransactionType, options: TransactionOptions, network_latency: Duration }, Commit, Rollback, + Analyze { query: String }, Query(QueryRequest), Stream { request_id: RequestID }, } @@ -155,7 +156,7 @@ pub(super) enum TransactionResponse { Commit, Rollback, Query(QueryResponse), - Analyze(AnalyzeResponse), + Analyze(AnalyzedQuery), Close, } diff --git a/rust/src/connection/network/proto/analyze.rs b/rust/src/connection/network/proto/analyze.rs index ebb639150..b81613e27 100644 --- a/rust/src/connection/network/proto/analyze.rs +++ b/rust/src/connection/network/proto/analyze.rs @@ -38,8 +38,8 @@ use crate::{ Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, LabelVertex, Reducer, Variable, }, - pipeline::{PipelineStage, PipelineStructure, ReduceAssignment, SortOrder, SortVariable}, - FunctionStructure, QueryStructure, ReturnOperation, + pipeline::{PipelineStage, PipelineStructure, ReduceAssign, SortOrder, SortVariable}, + AnalyzedQuery, FunctionStructure, QueryAnnotations, QueryStructure, ReturnOperation, }, common::Result, concept, @@ -64,19 +64,31 @@ fn enum_from_proto>(as_i32: i32 .map_err(|_| AnalyzeError::UnknownEnumValue { enum_name: std::any::type_name::(), value: as_i32 }.into()) } +impl TryFromProto for AnalyzedQuery { + fn try_from_proto(value: typedb_protocol::analyze::Res) -> Result { + let typedb_protocol::analyze::Res { structure, annotations } = value; + let structure = expect_try_into(structure, "analyze.Res.structure")?; + let annotations = expect_try_into(annotations, "analyze.Res.annotations")?; + Ok(Self { structure, annotations }) + } +} + +// Structure impl TryFromProto for QueryStructure { fn try_from_proto(value: analyze_proto::QueryStructure) -> Result { - let query = expect_try_into(value.query, "QueryStructure.query")?; - let preamble = vec_from_proto(value.preamble)?; + let analyze_proto::QueryStructure { query, preamble } = value; + let query = expect_try_into(query, "QueryStructure.query")?; + let preamble = vec_from_proto(preamble)?; Ok(Self { query, preamble }) } } impl TryFromProto for FunctionStructure { fn try_from_proto(value: query_structure::FunctionStructure) -> Result { - let body = expect_try_into(value.body, "FunctionStructure.body")?; - let returns = expect_try_into(value.returns, "FunctionStructure.returns")?; - let arguments = vec_from_proto(value.arguments)?; + let query_structure::FunctionStructure { body, returns, arguments } = value; + let body = expect_try_into(body, "FunctionStructure.body")?; + let returns = expect_try_into(returns, "FunctionStructure.returns")?; + let arguments = vec_from_proto(arguments)?; Ok(Self { arguments, returns, body }) } } @@ -98,9 +110,12 @@ impl TryFromProto for ReturnOperat impl TryFromProto for PipelineStructure { fn try_from_proto(value: query_structure::PipelineStructure) -> Result { - let conjunctions = vec_from_proto(value.conjunctions)?; - let stages = vec_from_proto(value.stages)?; - Ok(Self { conjunctions, stages }) + let query_structure::PipelineStructure { conjunctions, stages, variable_info, outputs } = value; + let conjunctions = vec_from_proto(conjunctions)?; + let stages = vec_from_proto(stages)?; + let variable_names = variable_info.into_iter().map(|(k, v)| (Variable(k), v.name)).collect(); + let outputs = vec_from_proto(outputs)?; + Ok(Self { conjunctions, stages, variable_names, outputs }) } } @@ -141,7 +156,7 @@ impl TryFromProto for PipelineStage { } } -impl TryFromProto for ReduceAssignment { +impl TryFromProto for ReduceAssign { fn try_from_proto(value: pipeline_structure::pipeline_stage::reduce::ReduceAssign) -> Result { Ok(Self { assigned: expect_try_into(value.assigned, "ReduceAssign.assigned")?, @@ -152,7 +167,7 @@ impl TryFromProto for impl TryFromProto for Reducer { fn try_from_proto(value: query_structure::Reducer) -> Result { - Ok(Self { variables: vec_from_proto(value.variables)?, reducer: value.reducer }) + Ok(Self { arguments: vec_from_proto(value.variables)?, reducer: value.reducer }) } } @@ -338,3 +353,11 @@ impl TryFromProto for Variable { Ok(Self(value.id)) } } + +// Annotations + +impl TryFromProto for QueryAnnotations { + fn try_from_proto(_value: typedb_protocol::analyze::res::QueryAnnotations) -> Result { + Ok(Self {}) // TODO + } +} diff --git a/rust/src/connection/network/proto/message.rs b/rust/src/connection/network/proto/message.rs index 3a00ba059..2da9c7436 100644 --- a/rust/src/connection/network/proto/message.rs +++ b/rust/src/connection/network/proto/message.rs @@ -26,6 +26,7 @@ use uuid::Uuid; use super::{FromProto, IntoProto, TryFromProto, TryIntoProto}; use crate::{ + analyze::AnalyzedQuery, answer::{concept_document::ConceptDocumentHeader, concept_row::ConceptRowHeader, QueryType}, common::{info::DatabaseInfo, RequestID, Result}, connection::message::{ @@ -186,6 +187,7 @@ impl IntoProto for TransactionRequest { } Self::Commit => transaction::req::Req::CommitReq(transaction::commit::Req {}), Self::Rollback => transaction::req::Req::RollbackReq(transaction::rollback::Req {}), + Self::Analyze { query } => transaction::req::Req::AnalyzeReq(typedb_protocol::analyze::Req { query }), Self::Query(query_request) => transaction::req::Req::QueryReq(query_request.into_proto()), Self::Stream { request_id: req_id } => { request_id = Some(req_id); @@ -397,7 +399,9 @@ impl TryFromProto for TransactionResponse { Err(ConnectionError::MissingResponseField { field: "transaction.res.query.initial_res.res" }.into()) } }, - Some(transaction::res::Res::AnalyzeRes(analyze_resp)) => todo!(), + Some(transaction::res::Res::AnalyzeRes(analyze_resp)) => { + Ok(TransactionResponse::Analyze(AnalyzedQuery::try_from_proto(analyze_resp)?)) + } None => Err(ConnectionError::MissingResponseField { field: "res" }.into()), } } diff --git a/rust/src/connection/transaction_stream.rs b/rust/src/connection/transaction_stream.rs index 44aca8275..89b06f7bc 100644 --- a/rust/src/connection/transaction_stream.rs +++ b/rust/src/connection/transaction_stream.rs @@ -24,6 +24,7 @@ use futures::{stream, StreamExt}; use super::network::transmitter::TransactionTransmitter; use crate::{ + analyze::AnalyzedQuery, answer::{concept_document::ConceptDocument, ConceptRow, QueryAnswer}, box_stream, common::{ @@ -107,6 +108,13 @@ impl TransactionStream { promisify! { require_transaction_response!(resolve!(promise), Rollback) } } + pub(crate) fn analyze(&self, query: &str) -> impl Promise<'static, Result> { + let promise = self.single(TransactionRequest::Analyze { query: query.to_owned() }); + promisify! { + require_transaction_response!(resolve!(promise), Analyze(_)) + } + } + pub(crate) fn query(&self, query: &str, options: QueryOptions) -> impl Promise<'static, Result> { let stream = self.query_stream(QueryRequest::Query { query: query.to_owned(), options }); promisify! { diff --git a/rust/src/transaction.rs b/rust/src/transaction.rs index 93c9daccb..60b5ba59a 100644 --- a/rust/src/transaction.rs +++ b/rust/src/transaction.rs @@ -20,6 +20,7 @@ use std::{fmt, pin::Pin}; use crate::{ + analyze::AnalyzedQuery, answer::QueryAnswer, common::{Promise, Result, TransactionType}, connection::TransactionStream, @@ -79,6 +80,22 @@ impl Transaction { self.transaction_stream.query(query, options) } + /// Performs a TypeQL query in this transaction. + /// + /// # Arguments + /// + /// * `query` — The TypeQL query to be executed + /// + /// # Examples + /// + /// ```rust + /// transaction.analyze_query(query) + /// ``` + pub fn analyze_query(&self, query: impl AsRef) -> impl Promise<'static, Result> { + let query = query.as_ref(); + self.transaction_stream.analyze(query) + } + /// Retrieves the transaction’s type (READ or WRITE). pub fn type_(&self) -> TransactionType { self.type_ diff --git a/rust/tests/behaviour/steps/lib.rs b/rust/tests/behaviour/steps/lib.rs index a33b5412f..55998e29a 100644 --- a/rust/tests/behaviour/steps/lib.rs +++ b/rust/tests/behaviour/steps/lib.rs @@ -105,6 +105,7 @@ pub struct Context { pub temp_dir: Option, pub transactions: VecDeque, pub background_transactions: VecDeque, + pub analyzed: Option, pub answer: Option, pub answer_type: Option, pub answer_query_type: Option, @@ -328,6 +329,15 @@ impl Context { } } + pub fn set_analyzed(&mut self, analyzed: TypeDBResult) -> TypeDBResult { + self.analyzed = Some(analyzed?); + Ok(()) + } + + pub fn get_analyzed(&mut self) -> Option<&AnalyzedQuery> { + self.analyzed.as_ref() + } + pub fn set_answer(&mut self, answer: TypeDBResult) -> TypeDBResult { let answer = answer?; self.answer_query_type = Some(answer.get_query_type()); @@ -489,6 +499,7 @@ impl Default for Context { transactions: VecDeque::new(), background_transactions: VecDeque::new(), temp_dir: None, + analyzed: None, answer: None, answer_type: None, answer_query_type: None, @@ -519,6 +530,7 @@ macro_rules! in_background { }; } pub(crate) use in_background; +use typedb_driver::analyze::AnalyzedQuery; // Most of the drivers are error-driven, while the Rust driver returns Option::None in many cases instead. // These "fake" errors allow us to emulate error messages for generalised driver BDDs, diff --git a/rust/tests/behaviour/steps/query.rs b/rust/tests/behaviour/steps/query.rs index 5258cfd3b..a1c459618 100644 --- a/rust/tests/behaviour/steps/query.rs +++ b/rust/tests/behaviour/steps/query.rs @@ -24,6 +24,7 @@ use futures::{future::join_all, StreamExt, TryStreamExt}; use itertools::Itertools; use macro_rules_attribute::apply; use typedb_driver::{ + analyze::AnalyzedQuery, answer::{ConceptRow, QueryAnswer, JSON}, concept::{AttributeType, Concept, ConceptCategory, EntityType, RelationType, Value, ValueType}, error::ConceptError, @@ -34,7 +35,7 @@ use crate::{ assert_err, generic_step, params, params::check_boolean, util, - util::{iter_table, list_contains_json, parse_json}, + util::{functor_encoding::encode_query_structure_as_functor, iter_table, list_contains_json, parse_json}, BehaviourTestOptionalError, Context, }; @@ -49,6 +50,13 @@ pub(crate) async fn run_query( } } +pub(crate) async fn run_analyze_query( + transaction: &Transaction, + query: impl AsRef, +) -> TypeDBResult { + transaction.analyze_query(query).await +} + fn get_collected_column_names(concept_row: &ConceptRow) -> Vec { concept_row.get_column_names().into_iter().cloned().collect() } @@ -981,3 +989,48 @@ pub async fn answer_contains_document( &format!("Concept documents: {:?}", concept_documents), ); } + +#[apply(generic_step)] +#[step(expr = r"get answers of typeql analyze query")] +pub async fn get_answers_of_typeql_analyze_query(context: &mut Context, step: &Step) { + context.cleanup_answers().await; + context.set_analyzed(run_analyze_query(context.transaction(), step.docstring().unwrap()).await).unwrap(); +} + +#[apply(generic_step)] +#[step(expr = r"analyzed query pipeline structure is:")] +pub async fn analyzed_query_pipeline_structure_is(context: &mut Context, step: &Step) { + let expected_functor = step.docstring().unwrap(); + let analyzed = context.get_analyzed().unwrap(); + let (actual_functor, _preamble) = encode_query_structure_as_functor(&analyzed.structure); + assert_eq!(normalize_functor_for_compare(&actual_functor), normalize_functor_for_compare(expected_functor)); +} + +#[apply(generic_step)] +#[step(expr = r"analyzed query preamble contains:")] +async fn analyzed_query_preamble_contains(context: &mut Context, step: &Step) { + let expected_functor = step.docstring().unwrap(); + let analyzed = context.get_analyzed().unwrap(); + let (_pipeline, preamble_functors) = encode_query_structure_as_functor(&analyzed.structure); + + assert!( + preamble_functors.iter().any(|actual_functor| { + normalize_functor_for_compare(actual_functor) == normalize_functor_for_compare(expected_functor) + }), + "Looking for\n\t{}\nin any of:\n\t{}", + normalize_functor_for_compare(expected_functor), + preamble_functors.iter().map(|s| normalize_functor_for_compare(s)).join("\n\t") + ); +} + +#[apply(generic_step)] +#[step(expr = r"analyzed query annotations is:")] +async fn analyzed_query_annotations_is(context: &mut Context, step: &Step) { + todo!() +} + +fn normalize_functor_for_compare(functor: &String) -> String { + let mut normalized = functor.to_lowercase(); + normalized.retain(|c| !c.is_whitespace()); + normalized +} diff --git a/rust/tests/behaviour/steps/util.rs b/rust/tests/behaviour/steps/util.rs index 84ae730ae..31d81d163 100644 --- a/rust/tests/behaviour/steps/util.rs +++ b/rust/tests/behaviour/steps/util.rs @@ -223,3 +223,262 @@ async fn file_write(context: &mut Context, file_name: String, step: &Step) { let path = context.get_full_file_path(&file_name); write_file(path, data.as_bytes()); } + +#[cfg(debug_assertions)] +pub mod functor_encoding { + use itertools::Itertools; + + type FunctorContext = PipelineStructure; + + pub trait FunctorEncoded { + fn encode_as_functor(&self, context: &FunctorContext) -> String; + } + + pub mod functor_macros { + macro_rules! encode_args { + ($context:ident, { $( $arg:ident, )* } ) => { + { + let arr: Vec<&dyn FunctorEncoded> = vec![ $($arg,)* ]; + arr.into_iter().map(|s| s.encode_as_functor($context)).join(", ") + } + } + } + macro_rules! encode_functor_impl { + ($context:ident, $func:ident $args:tt) => { + std::format!("{}({})", std::stringify!($func), functor_macros::encode_args!($context, $args)) + }; + } + + macro_rules! add_ignored_fields { + ($qualified:path { $( $arg:ident, )* }) => { + $qualified { $( $arg, )* .. } + }; + } + + macro_rules! encode_functor { + ($context:ident, $what:ident as struct $struct_name:ident $fields:tt) => { + functor_macros::encode_functor!($context, $what => [ $struct_name => $struct_name $fields, ]) + }; + ($context:ident, $what:ident as struct $struct_name:ident $fields:tt named $renamed:ident ) => { + functor_macros::encode_functor!($context, $what => [ $struct_name => $renamed $fields, ]) + }; + ($context:ident, $what:ident as enum $enum_name:ident [ $($variant:ident $fields:tt |)* ]) => { + functor_macros::encode_functor!($context, $what => [ $( $enum_name::$variant => $variant $fields ,)* ]) + }; + ($context:ident, $what:ident => [ $($qualified:path => $func:ident $fields:tt, )* ]) => { + match $what { + $( functor_macros::add_ignored_fields!($qualified $fields) => { + functor_macros::encode_functor_impl!($context, $func $fields) + })* + } + }; + } + + macro_rules! impl_functor_for_impl { + ($which:ident => |$self:ident, $context:ident| $block:block) => { + impl FunctorEncoded for $which { + fn encode_as_functor($self: &Self, $context: &FunctorContext) -> String { + $block + } + } + }; + } + + macro_rules! impl_functor_for { + (struct $struct_name:ident $fields:tt) => { + functor_macros::impl_functor_for!(struct $struct_name $fields named $struct_name); + }; + (struct $struct_name:ident $fields:tt named $renamed:ident) => { + functor_macros::impl_functor_for_impl!($struct_name => |self, context| { + functor_macros::encode_functor!(context, self as struct $struct_name $fields named $renamed) + }); + }; + (enum $enum_name:ident [ $($func:ident $fields:tt |)* ]) => { + functor_macros::impl_functor_for_impl!($enum_name => |self, context| { + functor_macros::encode_functor!(context, self as enum $enum_name [ $($func $fields |)* ]) + }); + }; + (primitive $primitive:ident) => { + functor_macros::impl_functor_for_impl!($primitive => |self, _context| { self.to_string() }); + }; + } + pub(crate) use add_ignored_fields; + pub(crate) use encode_args; + pub(crate) use encode_functor; + pub(crate) use encode_functor_impl; + pub(crate) use impl_functor_for; + pub(crate) use impl_functor_for_impl; + } + + functor_macros::impl_functor_for!(primitive String); + functor_macros::impl_functor_for!(primitive u64); + impl FunctorEncoded for Vec { + fn encode_as_functor(&self, context: &FunctorContext) -> String { + std::format!("[{}]", self.iter().map(|v| v.encode_as_functor(context)).join(", ")) + } + } + + impl FunctorEncoded for Option { + fn encode_as_functor(&self, context: &FunctorContext) -> String { + self.as_ref().map(|inner| inner.encode_as_functor(context)).unwrap_or("".to_owned()) + } + } + + use typedb_driver::{ + analyze::{ + conjunction::{ + Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, LabelVertex, Reducer, + Variable, + }, + pipeline::{PipelineStage, PipelineStructure, ReduceAssign, SortOrder, SortVariable}, + FunctionStructure, QueryStructure, ReturnOperation, + }, + concept::Value, + }; + + use crate::util::functor_encoding::functor_macros::{encode_functor, encode_functor_impl}; + + functor_macros::impl_functor_for!(struct ReduceAssign { assigned, reducer, } named ReduceAssign); + functor_macros::impl_functor_for!(struct Reducer { reducer, arguments, } named Reducer); + functor_macros::impl_functor_for!(enum PipelineStage [ + Match { block, } | + Insert { block, } | + Delete { deleted_variables, block, } | + Put { block, } | + Update { block, } | + Select { variables, } | + Sort { variables, } | + Offset { offset, } | + Limit { limit, } | + Require { variables, } | + Distinct { } | + Reduce { reducers, groupby, } | // TODO + ]); + + macro_rules! encode_functor_impl_exactness { + ($context:ident, $exactness:ident, $variant:ident $exactVariant:ident $fields:tt ) => { + match $exactness { + ConstraintExactness::Exact => encode_functor_impl!($context, $exactVariant $fields), + ConstraintExactness::Subtypes => encode_functor_impl!($context, $variant $fields), + } + }; + } + impl FunctorEncoded for Constraint { + fn encode_as_functor(self: &Self, context: &FunctorContext) -> String { + match self { + Self::Isa { instance, r#type, exactness } => { + encode_functor_impl_exactness!(context, exactness, Isa IsaExact { instance, r#type, }) + } + Self::Has { owner, attribute, exactness } => { + encode_functor_impl_exactness!(context, exactness, Has HasExact { owner, attribute, }) + } + Self::Links { relation, player, role, exactness } => { + encode_functor_impl_exactness!(context, exactness, Links LinksExact { relation, player, role, } ) + } + Self::Sub { subtype, supertype, exactness } => { + encode_functor_impl_exactness!(context, exactness, Sub SubExact { subtype, supertype, } ) + } + Self::Owns { owner, attribute, exactness } => { + encode_functor_impl_exactness!(context, exactness, Owns OwnsExact { owner, attribute, } ) + } + Self::Relates { relation, role, exactness } => { + encode_functor_impl_exactness!(context, exactness, Relates RelatesExact { relation, role, } ) + } + Self::Plays { player, role, exactness } => { + encode_functor_impl_exactness!(context, exactness, Plays PlaysExact { player, role, } ) + } + Self::FunctionCall { name, assigned, arguments } => { + encode_functor_impl!(context, FunctionCall { name, assigned, arguments }) + } + Self::Expression { text, assigned, arguments } => { + encode_functor_impl!(context, Expression { text, assigned, arguments }) + } + Self::Is { lhs, rhs } => { + encode_functor_impl!(context, Is { lhs, rhs }) + } + Self::Iid { concept, iid } => { + let iid_str = format!("0x{}", iid.iter().map(|x| format!("{:02X}", x)).join("")); + let iid_ref = &iid_str; + encode_functor_impl!(context, Iid { concept, iid_ref }) + } + Self::Comparison { lhs, rhs, comparator } => { + encode_functor_impl!(context, Comparison { lhs, rhs, comparator }) + } + Self::Kind { kind, r#type } => { + let kind_str = kind.name().to_owned(); + let kind_ref = &kind_str; + encode_functor_impl!(context, Kind { kind_ref, r#type }) + } + Self::Label { r#type, label } => { + encode_functor_impl!(context, Label { r#type, label }) + } + Self::Value { attribute_type, value_type } => { + let value_type_sr = value_type.name().to_owned(); + let value_type_ref = &value_type_sr; + encode_functor_impl!(context, Value { attribute_type, value_type_ref }) + } + Self::Or { branches } => { + encode_functor_impl!(context, Or { branches }) + } + Self::Not { conjunction } => { + encode_functor_impl!(context, Not { conjunction }) + } + Self::Try { conjunction } => { + encode_functor_impl!(context, Try { conjunction }) + } + } + } + } + + functor_macros::impl_functor_for_impl!(ConstraintVertex => |self, context| { + match self { + ConstraintVertex::Variable(id) => { id.encode_as_functor(context) } + ConstraintVertex::Label(LabelVertex::Resolved(r#type)) => { r#type.label().to_owned().encode_as_functor(context) } + ConstraintVertex::Label(LabelVertex::Unresolved(label))=> { label.encode_as_functor(context) } + ConstraintVertex::Value(v) => { + match v { + Value::String(s) => std::format!("\"{}\"", s.to_string()), + other => other.to_string(), + } + } + } + }); + // + macro_rules! impl_functor_for_multi { + (|$self:ident, $context:ident| [ $( $type_name:ident => $block:block )* ]) => { + $ (functor_macros::impl_functor_for_impl!($type_name => |$self, $context| $block); )* + }; + } + impl_functor_for_multi!(|self, context| [ + Variable => { format!("${}", context.variable_names.get(self).as_ref().map(|v| v.as_str()).unwrap_or("_")) } + ConjunctionID => { context.conjunctions[self.0 as usize].encode_as_functor(context) } + Conjunction => { let Conjunction { constraints } = self; constraints.encode_as_functor(context) } + PipelineStructure => { let pipeline = &self.stages; functor_macros::encode_functor_impl!(self, Pipeline { pipeline, }) } + FunctionStructure => { + let FunctionStructure { arguments, returns, body } = self; + let context = body; + functor_macros::encode_functor_impl!(context, Function { arguments, returns, body, }) + } + SortVariable => { + let Self { order, variable } = self; + match order { + SortOrder::Ascending => functor_macros::encode_functor_impl!(context, Asc { variable, }), + SortOrder::Descending => functor_macros::encode_functor_impl!(context, Desc { variable, }), + } + } + ]); + // + functor_macros::impl_functor_for!(enum ReturnOperation [ + Stream { variables, } | + Single { selector, variables, } | + Check { } | + Reduce {} | + ]); + + pub fn encode_query_structure_as_functor(structure: &QueryStructure) -> (String, Vec) { + let pipeline = &structure.query; + let query = pipeline.encode_as_functor(pipeline); + let preamble = structure.preamble.iter().map(|func| func.encode_as_functor(&func.body)).collect(); + (query, preamble) + } +} From c61788217cdaa6fe1593f9206da7942b98751f9f Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Sat, 27 Sep 2025 02:47:00 +0200 Subject: [PATCH 08/22] Tests work except for some weird transaction closing --- dependencies/typedb/repositories.bzl | 2 +- rust/src/analyze/conjunction.rs | 29 +++++++- rust/src/common/error.rs | 2 + rust/src/connection/network/proto/analyze.rs | 39 +++++++--- rust/src/connection/transaction_stream.rs | 15 +++- rust/tests/behaviour/steps/util.rs | 75 +++++++++----------- 6 files changed, 106 insertions(+), 56 deletions(-) diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index c7d5f44f7..238676a93 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -35,5 +35,5 @@ def typedb_behaviour(): git_repository( name = "typedb_behaviour", remote = "https://github.com/krishnangovindraj/typedb-behaviour", - commit = "a6a85a75cbce32ad9953df587630afe2929c5b9e", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour + commit = "bf0cc1f864d84088d8a2f7a6e93145677933fc4a", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour ) diff --git a/rust/src/analyze/conjunction.rs b/rust/src/analyze/conjunction.rs index 429722433..e298c411b 100644 --- a/rust/src/analyze/conjunction.rs +++ b/rust/src/analyze/conjunction.rs @@ -97,7 +97,7 @@ pub enum Constraint { Comparison { lhs: ConstraintVertex, rhs: ConstraintVertex, - comparator: String, + comparator: Comparator, }, Kind { kind: concept::Kind, @@ -145,3 +145,30 @@ pub struct Reducer { pub arguments: Vec, pub reducer: String, } + +#[derive(Debug)] +pub enum Comparator { + Equal, + NotEqual, + LessThan, + LessOrEqual, + Greater, + GreaterOrEqual, + Like, + Contains +} + +impl Comparator { + pub fn symbol(&self) -> &'static str { + match self { + Comparator::Equal => "==", + Comparator::NotEqual => "!=", + Comparator::LessThan => "<", + Comparator::LessOrEqual => "<=", + Comparator::Greater => ">", + Comparator::GreaterOrEqual => ">=", + Comparator::Like => "Like", + Comparator::Contains => "Contains", + } + } +} diff --git a/rust/src/common/error.rs b/rust/src/common/error.rs index 0e7fad58d..5a5deead0 100644 --- a/rust/src/common/error.rs +++ b/rust/src/common/error.rs @@ -198,6 +198,8 @@ error_messages! { ConnectionError 35: "TLS connections can only be enabled when connecting to HTTPS endpoints, for example using 'https://:port'. Please modify the address, or disable TLS (WARNING: this will send passwords over plaintext).", NonTlsConnectionWithHttps = 36: "Connecting to an https endpoint requires enabling TLS in driver options.", + AnalyzeQueryNoResponse = + 37: "Didn't receive any server responses for the analyze query.", } error_messages! { ConceptError diff --git a/rust/src/connection/network/proto/analyze.rs b/rust/src/connection/network/proto/analyze.rs index b81613e27..10821d41a 100644 --- a/rust/src/connection/network/proto/analyze.rs +++ b/rust/src/connection/network/proto/analyze.rs @@ -47,6 +47,7 @@ use crate::{ connection::network::proto::TryFromProto, error::AnalyzeError, }; +use crate::analyze::conjunction::Comparator; pub(super) fn expect_try_into>(x: Option, field: &'static str) -> Result { Dst::try_from_proto(x.ok_or_else(|| crate::Error::Analyze(AnalyzeError::MissingResponseField { field }))?) @@ -264,7 +265,7 @@ impl TryFromProto for Constraint { Constraint::Comparison { lhs: expect_try_into(lhs, "structure_constraint::Comparison.lhs")?, rhs: expect_try_into(rhs, "structure_constraint::Comparison.rhs")?, - comparator: comparator.as_str_name().to_owned(), + comparator: Comparator::try_from_proto(comparator)?, } } ConstraintProto::Expression(constraint_proto::Expression { assigned, arguments, text }) => { @@ -299,6 +300,32 @@ impl TryFromProto for Conjunction { } } +impl TryFromProto for Comparator { + fn try_from_proto(value: conjunction_structure::structure_constraint::comparison::Comparator) -> Result { + use conjunction_structure::structure_constraint::comparison::Comparator as ComparatorProto; + Ok(match value { + ComparatorProto::Equal => Comparator::Equal, + ComparatorProto::NotEqual => Comparator::NotEqual, + ComparatorProto::Less => Comparator::LessThan, + ComparatorProto::LessOrEqual => Comparator::LessOrEqual, + ComparatorProto::Greater => Comparator::Greater, + ComparatorProto::GreaterOrEqual => Comparator::GreaterOrEqual, + ComparatorProto::Like => Comparator::Like, + ComparatorProto::Contains => Comparator::Contains, + }) + } +} + +impl TryFromProto for ConstraintExactness { + fn try_from_proto(value: conjunction_structure::structure_constraint::ConstraintExactness) -> Result { + use conjunction_structure::structure_constraint::ConstraintExactness as ConstraintExactnessProto; + Ok(match value { + ConstraintExactnessProto::Exact => ConstraintExactness::Exact, + ConstraintExactnessProto::Subtypes => ConstraintExactness::Subtypes, + }) + } +} + impl TryFromProto for SortVariable { fn try_from_proto(value: pipeline_structure::pipeline_stage::sort::SortVariable) -> Result { use pipeline_structure::pipeline_stage::sort::sort_variable::SortDirection; @@ -338,16 +365,6 @@ impl TryFromProto for ConstraintVertex { } } -impl TryFromProto for ConstraintExactness { - fn try_from_proto(value: conjunction_structure::structure_constraint::ConstraintExactness) -> Result { - use conjunction_structure::structure_constraint::ConstraintExactness as ConstraintExactnessProto; - Ok(match value { - ConstraintExactnessProto::Exact => ConstraintExactness::Exact, - ConstraintExactnessProto::Subtypes => ConstraintExactness::Subtypes, - }) - } -} - impl TryFromProto for Variable { fn try_from_proto(value: conjunction_structure::Variable) -> Result { Ok(Self(value.id)) diff --git a/rust/src/connection/transaction_stream.rs b/rust/src/connection/transaction_stream.rs index 89b06f7bc..832a96084 100644 --- a/rust/src/connection/transaction_stream.rs +++ b/rust/src/connection/transaction_stream.rs @@ -109,9 +109,20 @@ impl TransactionStream { } pub(crate) fn analyze(&self, query: &str) -> impl Promise<'static, Result> { - let promise = self.single(TransactionRequest::Analyze { query: query.to_owned() }); + let stream = self.stream(TransactionRequest::Analyze { query: query.to_owned() }); promisify! { - require_transaction_response!(resolve!(promise), Analyze(_)) + let mut stream = stream?; + #[cfg(feature = "sync")] + let response = stream.next(); + + #[cfg(not(feature = "sync"))] + let response: Option> = stream.next().await; + + match response { + None => Err(ConnectionError::AnalyzeQueryNoResponse.into()), + Some(Ok(TransactionResponse::Analyze(analyzed_query))) => Ok(analyzed_query), + other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), + } } } diff --git a/rust/tests/behaviour/steps/util.rs b/rust/tests/behaviour/steps/util.rs index 31d81d163..d65dd52e1 100644 --- a/rust/tests/behaviour/steps/util.rs +++ b/rust/tests/behaviour/steps/util.rs @@ -224,6 +224,7 @@ async fn file_write(context: &mut Context, file_name: String, step: &Step) { write_file(path, data.as_bytes()); } + #[cfg(debug_assertions)] pub mod functor_encoding { use itertools::Itertools; @@ -324,18 +325,9 @@ pub mod functor_encoding { } } - use typedb_driver::{ - analyze::{ - conjunction::{ - Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, LabelVertex, Reducer, - Variable, - }, - pipeline::{PipelineStage, PipelineStructure, ReduceAssign, SortOrder, SortVariable}, - FunctionStructure, QueryStructure, ReturnOperation, - }, - concept::Value, - }; - + use typedb_driver::analyze::{conjunction::{Constraint, Conjunction, ConjunctionID, ConstraintVertex, LabelVertex, Reducer, Variable}, FunctionStructure, pipeline::{PipelineStructure, PipelineStage, SortVariable, SortOrder, ReduceAssign}, QueryStructure, ReturnOperation}; + use typedb_driver::analyze::conjunction::{Comparator, ConstraintExactness}; + use typedb_driver::concept::Value; use crate::util::functor_encoding::functor_macros::{encode_functor, encode_functor_impl}; functor_macros::impl_functor_for!(struct ReduceAssign { assigned, reducer, } named ReduceAssign); @@ -366,65 +358,65 @@ pub mod functor_encoding { impl FunctorEncoded for Constraint { fn encode_as_functor(self: &Self, context: &FunctorContext) -> String { match self { - Self::Isa { instance, r#type, exactness } => { + Self::Isa { instance, r#type, exactness } => { encode_functor_impl_exactness!(context, exactness, Isa IsaExact { instance, r#type, }) } - Self::Has { owner, attribute, exactness } => { + Self::Has { owner, attribute, exactness } => { encode_functor_impl_exactness!(context, exactness, Has HasExact { owner, attribute, }) } - Self::Links { relation, player, role, exactness } => { + Self::Links { relation, player, role, exactness } => { encode_functor_impl_exactness!(context, exactness, Links LinksExact { relation, player, role, } ) } - Self::Sub { subtype, supertype, exactness } => { + Self::Sub { subtype, supertype, exactness } => { encode_functor_impl_exactness!(context, exactness, Sub SubExact { subtype, supertype, } ) } - Self::Owns { owner, attribute, exactness } => { + Self::Owns { owner, attribute, exactness } => { encode_functor_impl_exactness!(context, exactness, Owns OwnsExact { owner, attribute, } ) } - Self::Relates { relation, role, exactness } => { + Self::Relates { relation, role, exactness } => { encode_functor_impl_exactness!(context, exactness, Relates RelatesExact { relation, role, } ) } - Self::Plays { player, role, exactness } => { + Self::Plays { player, role, exactness } => { encode_functor_impl_exactness!(context, exactness, Plays PlaysExact { player, role, } ) } - Self::FunctionCall { name, assigned, arguments } => { - encode_functor_impl!(context, FunctionCall { name, assigned, arguments }) + Self::FunctionCall { name, assigned, arguments, } => { + encode_functor_impl!(context, FunctionCall { name, assigned, arguments, }) } - Self::Expression { text, assigned, arguments } => { - encode_functor_impl!(context, Expression { text, assigned, arguments }) + Self::Expression { text, assigned, arguments, } => { + encode_functor_impl!(context, Expression { text, assigned, arguments, }) } - Self::Is { lhs, rhs } => { - encode_functor_impl!(context, Is { lhs, rhs }) + Self::Is { lhs, rhs, } => { + encode_functor_impl!(context, Is { lhs, rhs, }) } - Self::Iid { concept, iid } => { + Self::Iid { concept, iid, } => { let iid_str = format!("0x{}", iid.iter().map(|x| format!("{:02X}", x)).join("")); let iid_ref = &iid_str; - encode_functor_impl!(context, Iid { concept, iid_ref }) + encode_functor_impl!(context, Iid { concept, iid_ref, }) } - Self::Comparison { lhs, rhs, comparator } => { - encode_functor_impl!(context, Comparison { lhs, rhs, comparator }) + Self::Comparison { lhs, rhs, comparator, } => { + encode_functor_impl!(context, Comparison { lhs, rhs, comparator, }) } - Self::Kind { kind, r#type } => { + Self::Kind { kind, r#type, } => { let kind_str = kind.name().to_owned(); let kind_ref = &kind_str; - encode_functor_impl!(context, Kind { kind_ref, r#type }) + encode_functor_impl!(context, Kind { kind_ref, r#type, }) } - Self::Label { r#type, label } => { - encode_functor_impl!(context, Label { r#type, label }) + Self::Label { r#type, label, } => { + encode_functor_impl!(context, Label { r#type, label, }) } - Self::Value { attribute_type, value_type } => { + Self::Value { attribute_type, value_type, } => { let value_type_sr = value_type.name().to_owned(); let value_type_ref = &value_type_sr; - encode_functor_impl!(context, Value { attribute_type, value_type_ref }) + encode_functor_impl!(context, Value { attribute_type, value_type_ref, }) } - Self::Or { branches } => { - encode_functor_impl!(context, Or { branches }) + Self::Or { branches, } => { + encode_functor_impl!(context, Or { branches, }) } - Self::Not { conjunction } => { - encode_functor_impl!(context, Not { conjunction }) + Self::Not { conjunction, } => { + encode_functor_impl!(context, Not { conjunction, }) } - Self::Try { conjunction } => { - encode_functor_impl!(context, Try { conjunction }) + Self::Try { conjunction, } => { + encode_functor_impl!(context, Try { conjunction, }) } } } @@ -451,6 +443,7 @@ pub mod functor_encoding { } impl_functor_for_multi!(|self, context| [ Variable => { format!("${}", context.variable_names.get(self).as_ref().map(|v| v.as_str()).unwrap_or("_")) } + Comparator => { format!("{}", self.symbol()) } ConjunctionID => { context.conjunctions[self.0 as usize].encode_as_functor(context) } Conjunction => { let Conjunction { constraints } = self; constraints.encode_as_functor(context) } PipelineStructure => { let pipeline = &self.stages; functor_macros::encode_functor_impl!(self, Pipeline { pipeline, }) } From b2470efa2d86007d552d92cb5b7c62ea5efc1976 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Mon, 29 Sep 2025 12:44:19 +0200 Subject: [PATCH 09/22] Bump protocol though no real changes --- dependencies/typedb/repositories.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index 238676a93..17bee6080 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -27,8 +27,8 @@ def typedb_dependencies(): def typedb_protocol(): git_repository( name = "typedb_protocol", - remote = "https://github.com/krishnangovindraj/typedb-protocol", - commit = "9fba4c5c8105594053ab6b5fea01117e144b7de6", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol + remote = "https://github.com/typedb/typedb-protocol", + commit = "daa9860d1acfff61a17d8762397e72a20aa6af8d", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol ) def typedb_behaviour(): From 1152ada7d95c8f7e05c069baed82c7650f084c5d Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Thu, 2 Oct 2025 18:41:04 +0200 Subject: [PATCH 10/22] OH GOD SO BUGGY --- Cargo.lock | 2 +- dependencies/typedb/repositories.bzl | 12 ++++-- rust/Cargo.toml | 2 +- rust/src/connection/message.rs | 9 ++++- rust/src/connection/network/proto/analyze.rs | 39 +++++++++++++++----- rust/src/connection/network/proto/message.rs | 3 +- rust/src/connection/transaction_stream.rs | 12 +++++- 7 files changed, 59 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e86c5342b..f4d733029 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2829,7 +2829,7 @@ dependencies = [ [[package]] name = "typedb-protocol" version = "0.0.0" -source = "git+https://github.com/typedb/typedb-protocol?rev=9fba4c5c8105594053ab6b5fea01117e144b7de6#9fba4c5c8105594053ab6b5fea01117e144b7de6" +source = "git+https://github.com/typedb/typedb-protocol?rev=8e7077e4562bc0d6e8b4b64b400544615dfa447e#8e7077e4562bc0d6e8b4b64b400544615dfa447e" dependencies = [ "prost", "tonic", diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index 17bee6080..1668ddf58 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -28,12 +28,16 @@ def typedb_protocol(): git_repository( name = "typedb_protocol", remote = "https://github.com/typedb/typedb-protocol", - commit = "daa9860d1acfff61a17d8762397e72a20aa6af8d", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol + commit = "8e7077e4562bc0d6e8b4b64b400544615dfa447e", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol ) def typedb_behaviour(): - git_repository( + native.local_repository( name = "typedb_behaviour", - remote = "https://github.com/krishnangovindraj/typedb-behaviour", - commit = "bf0cc1f864d84088d8a2f7a6e93145677933fc4a", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour + path = "../typedb-behaviour", ) +# git_repository( +# name = "typedb_behaviour", +# remote = "https://github.com/krishnangovindraj/typedb-behaviour", +# commit = "bf0cc1f864d84088d8a2f7a6e93145677933fc4a", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour +# ) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6496211bf..5d6dd396e 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -65,7 +65,7 @@ [dependencies.typedb-protocol] features = [] - rev = "9fba4c5c8105594053ab6b5fea01117e144b7de6" + rev = "8e7077e4562bc0d6e8b4b64b400544615dfa447e" git = "https://github.com/typedb/typedb-protocol" default-features = false diff --git a/rust/src/connection/message.rs b/rust/src/connection/message.rs index db3713095..07f2ff9c0 100644 --- a/rust/src/connection/message.rs +++ b/rust/src/connection/message.rs @@ -156,10 +156,17 @@ pub(super) enum TransactionResponse { Commit, Rollback, Query(QueryResponse), - Analyze(AnalyzedQuery), + Analyze(AnalyzeResponse), Close, } +#[derive(Debug)] +pub(super) enum AnalyzeResponse { + Ok(AnalyzedQuery), + Err(ServerError), +} + + #[derive(Debug)] pub(super) enum QueryRequest { Query { query: String, options: QueryOptions }, diff --git a/rust/src/connection/network/proto/analyze.rs b/rust/src/connection/network/proto/analyze.rs index 10821d41a..5cf665d7c 100644 --- a/rust/src/connection/network/proto/analyze.rs +++ b/rust/src/connection/network/proto/analyze.rs @@ -18,9 +18,9 @@ */ use typedb_protocol::{ - analyze::{ - res as analyze_proto, - res::{ + analyze::res::{ + analyzed_query as analyze_proto, + analyzed_query::{ query_structure, query_structure::{ pipeline_structure, pipeline_structure::pipeline_stage::sort::sort_variable::SortDirection, @@ -42,12 +42,14 @@ use crate::{ AnalyzedQuery, FunctionStructure, QueryAnnotations, QueryStructure, ReturnOperation, }, common::Result, - concept, concept::{type_, Kind, Value}, connection::network::proto::TryFromProto, error::AnalyzeError, }; use crate::analyze::conjunction::Comparator; +use crate::connection::message::AnalyzeResponse; +use crate::connection::network::proto::FromProto; +use crate::error::ServerError; pub(super) fn expect_try_into>(x: Option, field: &'static str) -> Result { Dst::try_from_proto(x.ok_or_else(|| crate::Error::Analyze(AnalyzeError::MissingResponseField { field }))?) @@ -65,9 +67,26 @@ fn enum_from_proto>(as_i32: i32 .map_err(|_| AnalyzeError::UnknownEnumValue { enum_name: std::any::type_name::(), value: as_i32 }.into()) } -impl TryFromProto for AnalyzedQuery { - fn try_from_proto(value: typedb_protocol::analyze::Res) -> Result { - let typedb_protocol::analyze::Res { structure, annotations } = value; +impl TryFromProto for AnalyzeResponse { + fn try_from_proto(proto: typedb_protocol::analyze::Res) -> Result { + expect_try_into(proto.result, "analyze.Res.result") + } +} + +impl TryFromProto for AnalyzeResponse { + fn try_from_proto(proto: typedb_protocol::analyze::res::Result) -> Result { + use typedb_protocol::analyze::res::Result as ResultProto; + let result = match proto { + ResultProto::Ok(analyzed_query) => AnalyzeResponse::Ok(AnalyzedQuery::try_from_proto(analyzed_query)?), + ResultProto::Err(err) => AnalyzeResponse::Err(ServerError::from_proto(err)), + }; + Ok(result) + } +} + +impl TryFromProto for AnalyzedQuery { + fn try_from_proto(value: typedb_protocol::analyze::res::AnalyzedQuery) -> Result { + let typedb_protocol::analyze::res::AnalyzedQuery { structure, annotations } = value; let structure = expect_try_into(structure, "analyze.Res.structure")?; let annotations = expect_try_into(annotations, "analyze.Res.annotations")?; Ok(Self { structure, annotations }) @@ -96,7 +115,7 @@ impl TryFromProto for FunctionStructure { impl TryFromProto for ReturnOperation { fn try_from_proto(value: query_structure::function_structure::Returns) -> Result { - use typedb_protocol::analyze::res::query_structure::function_structure::Returns; + use analyze_proto::query_structure::function_structure::Returns; let returns = match value { Returns::Stream(stream) => Self::Stream { variables: vec_from_proto(stream.variables)? }, Returns::Single(single) => { @@ -373,8 +392,8 @@ impl TryFromProto for Variable { // Annotations -impl TryFromProto for QueryAnnotations { - fn try_from_proto(_value: typedb_protocol::analyze::res::QueryAnnotations) -> Result { +impl TryFromProto for QueryAnnotations { + fn try_from_proto(_value: analyze_proto::QueryAnnotations) -> Result { Ok(Self {}) // TODO } } diff --git a/rust/src/connection/network/proto/message.rs b/rust/src/connection/network/proto/message.rs index 2da9c7436..df2dd99f1 100644 --- a/rust/src/connection/network/proto/message.rs +++ b/rust/src/connection/network/proto/message.rs @@ -37,6 +37,7 @@ use crate::{ info::UserInfo, Credentials, }; +use crate::connection::message::AnalyzeResponse; impl TryIntoProto for Request { fn try_into_proto(self) -> Result { @@ -400,7 +401,7 @@ impl TryFromProto for TransactionResponse { } }, Some(transaction::res::Res::AnalyzeRes(analyze_resp)) => { - Ok(TransactionResponse::Analyze(AnalyzedQuery::try_from_proto(analyze_resp)?)) + Ok(TransactionResponse::Analyze(AnalyzeResponse::try_from_proto(analyze_resp)?)) } None => Err(ConnectionError::MissingResponseField { field: "res" }.into()), } diff --git a/rust/src/connection/transaction_stream.rs b/rust/src/connection/transaction_stream.rs index 832a96084..18f2d14a1 100644 --- a/rust/src/connection/transaction_stream.rs +++ b/rust/src/connection/transaction_stream.rs @@ -35,6 +35,8 @@ use crate::{ error::{ConnectionError, InternalError}, promisify, resolve, Error, QueryOptions, TransactionOptions, TransactionType, }; +use crate::connection::message::AnalyzeResponse; +use crate::error::{AnalyzeError, ServerError}; macro_rules! require_transaction_response { ($response:expr, $variant:ident(_)) => { @@ -120,8 +122,14 @@ impl TransactionStream { match response { None => Err(ConnectionError::AnalyzeQueryNoResponse.into()), - Some(Ok(TransactionResponse::Analyze(analyzed_query))) => Ok(analyzed_query), - other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), + Some(Ok(TransactionResponse::Analyze(response))) => { + match response { + AnalyzeResponse::Ok(analyzed) => Ok(analyzed), + AnalyzeResponse::Err(error) => Err(error.into()), + } + } + Some(Ok(other)) => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), + Some(Err(err)) => Err(err), } } } From 751b785a6742fc112600288824f4d89abd0882f1 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Thu, 2 Oct 2025 20:39:29 +0200 Subject: [PATCH 11/22] Need to implement steps --- dependencies/typedb/repositories.bzl | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index 1668ddf58..f81642091 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -32,12 +32,8 @@ def typedb_protocol(): ) def typedb_behaviour(): - native.local_repository( + git_repository( name = "typedb_behaviour", - path = "../typedb-behaviour", + remote = "https://github.com/krishnangovindraj/typedb-behaviour", + commit = "d44c301de91f84367e1a196b55978be7d8079f51", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour ) -# git_repository( -# name = "typedb_behaviour", -# remote = "https://github.com/krishnangovindraj/typedb-behaviour", -# commit = "bf0cc1f864d84088d8a2f7a6e93145677933fc4a", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour -# ) From ba879002bee01177e06d1e22c2e8754b38604703 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Fri, 3 Oct 2025 01:34:20 +0200 Subject: [PATCH 12/22] Implement it all --- dependencies/typedb/repositories.bzl | 2 +- rust/src/analyze/annotations.rs | 66 +++++++ rust/src/analyze/conjunction.rs | 2 +- rust/src/analyze/mod.rs | 8 +- rust/src/connection/network/proto/analyze.rs | 102 ++++++++-- rust/tests/behaviour/steps/query.rs | 43 +++- rust/tests/behaviour/steps/util.rs | 197 ++++++++++++++++--- 7 files changed, 376 insertions(+), 44 deletions(-) create mode 100644 rust/src/analyze/annotations.rs diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index f81642091..8adc1a2f2 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -35,5 +35,5 @@ def typedb_behaviour(): git_repository( name = "typedb_behaviour", remote = "https://github.com/krishnangovindraj/typedb-behaviour", - commit = "d44c301de91f84367e1a196b55978be7d8079f51", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour + commit = "92d5dc578fd087974173ed926809f5c425de543b", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour ) diff --git a/rust/src/analyze/annotations.rs b/rust/src/analyze/annotations.rs new file mode 100644 index 000000000..e41b63cd6 --- /dev/null +++ b/rust/src/analyze/annotations.rs @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use std::{ + collections::BTreeMap, + vec::Vec, +}; +use std::collections::HashMap; + +use crate::analyze::conjunction::Variable; +use crate::concept::type_::Type; +use crate::concept::ValueType; + +#[derive(Debug)] +pub struct PipelineAnnotations { + pub conjunction_annotations: Vec, +} + +#[derive(Debug)] +pub struct FunctionAnnotations { + pub arguments: Vec, + pub returns: FunctionReturnAnnotations, + pub body: PipelineAnnotations, +} + +#[derive(Debug)] +pub enum FunctionReturnAnnotations { + Stream(Vec), + Single(Vec), +} + +#[derive(Debug)] +pub enum FetchAnnotations { + List(Box), + Leaf(Vec), + Object(HashMap), +} + +#[derive(Debug)] +pub struct ConjunctionAnnotations { + pub variable_annotations: HashMap, +} + +#[derive(Debug)] +pub enum VariableAnnotations { + Thing(Vec), + Type(Vec), + Value(ValueType) +} + diff --git a/rust/src/analyze/conjunction.rs b/rust/src/analyze/conjunction.rs index e298c411b..4b97be48e 100644 --- a/rust/src/analyze/conjunction.rs +++ b/rust/src/analyze/conjunction.rs @@ -22,7 +22,7 @@ use crate::{ concept::{type_, ValueType}, }; -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct ConjunctionID(pub usize); #[derive(Debug)] diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs index ced9e2e35..7c42ccbb2 100644 --- a/rust/src/analyze/mod.rs +++ b/rust/src/analyze/mod.rs @@ -23,9 +23,11 @@ use crate::analyze::{ conjunction::{Reducer, Variable}, pipeline::PipelineStructure, }; +use crate::analyze::annotations::{FetchAnnotations, FunctionAnnotations, PipelineAnnotations}; pub mod conjunction; pub mod pipeline; +pub mod annotations; pub type TryFromError = &'static str; @@ -57,4 +59,8 @@ pub enum ReturnOperation { } #[derive(Debug)] -pub struct QueryAnnotations {} +pub struct QueryAnnotations { + pub query: PipelineAnnotations, + pub preamble: Vec, + pub fetch: Option, +} diff --git a/rust/src/connection/network/proto/analyze.rs b/rust/src/connection/network/proto/analyze.rs index 5cf665d7c..2b52ed297 100644 --- a/rust/src/connection/network/proto/analyze.rs +++ b/rust/src/connection/network/proto/analyze.rs @@ -17,20 +17,16 @@ * under the License. */ -use typedb_protocol::{ - analyze::res::{ - analyzed_query as analyze_proto, - analyzed_query::{ - query_structure, - query_structure::{ - pipeline_structure, pipeline_structure::pipeline_stage::sort::sort_variable::SortDirection, - }, - }, +use std::collections::HashMap; +use typedb_protocol::{analyze::res::{ + analyzed_query as analyze_proto, + analyzed_query::{ + query_structure, + query_structure::pipeline_structure }, - conjunction_structure, - conjunction_structure::StructureConstraint, - ConjunctionStructure, -}; +}, conjunction_structure, conjunction_structure::StructureConstraint, ConjunctionStructure}; +use typedb_protocol::analyze::res::analyzed_query::query_annotations::fetch_annotations::Node; +use typedb_protocol::analyze::res::analyzed_query::query_annotations::variable_annotations::Annotations; use crate::{ analyze::{ @@ -46,7 +42,9 @@ use crate::{ connection::network::proto::TryFromProto, error::AnalyzeError, }; +use crate::analyze::annotations::{ConjunctionAnnotations, FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, PipelineAnnotations, VariableAnnotations}; use crate::analyze::conjunction::Comparator; +use crate::concept::ValueType; use crate::connection::message::AnalyzeResponse; use crate::connection::network::proto::FromProto; use crate::error::ServerError; @@ -393,7 +391,81 @@ impl TryFromProto for Variable { // Annotations impl TryFromProto for QueryAnnotations { - fn try_from_proto(_value: analyze_proto::QueryAnnotations) -> Result { - Ok(Self {}) // TODO + fn try_from_proto(proto: analyze_proto::QueryAnnotations) -> Result { + let query = expect_try_into(proto.query, "QueryAnnotations.query")?; + let preamble = vec_from_proto(proto.preamble)?; + let fetch = proto.fetch.map(|fetch| FetchAnnotations::try_from_proto(fetch)).transpose()?; + Ok(Self { query, preamble, fetch}) + } +} + +impl TryFromProto for FunctionAnnotations { + fn try_from_proto(proto: analyze_proto::query_annotations::FunctionAnnotations) -> Result { + let arguments = vec_from_proto(proto.arguments)?; + let returns_types = vec_from_proto(proto.returns)?; + let returns = match proto.returns_stream { + true => FunctionReturnAnnotations::Stream(returns_types), + false => FunctionReturnAnnotations::Single(returns_types), + }; + let body = expect_try_into(proto.body, "FunctionAnnotations.body")?; + Ok(Self { arguments, returns, body }) + } +} + +impl TryFromProto for PipelineAnnotations { + fn try_from_proto(proto: analyze_proto::query_annotations::PipelineAnnotations) -> Result { + Ok(Self { conjunction_annotations: vec_from_proto(proto.conjunctions)? }) + } +} + +impl TryFromProto for ConjunctionAnnotations { + fn try_from_proto(proto: analyze_proto::query_annotations::pipeline_annotations::ConjunctionAnnotations) -> Result { + let variable_annotations = proto.variable_annotations.into_iter().map(|(id, annotations_proto)| { + Ok((Variable(id), VariableAnnotations::try_from_proto(annotations_proto)?)) + }).collect::>>()?; + Ok(Self { variable_annotations }) + } +} + +impl TryFromProto for VariableAnnotations { + fn try_from_proto(proto: analyze_proto::query_annotations::VariableAnnotations) -> Result { + let unwrapped = proto.annotations.ok_or_else(|| { + crate::Error::Analyze(AnalyzeError::MissingResponseField { field: "VariableAnnotations.annotations" }) + })?; + Ok(match unwrapped { + Annotations::Thing(types) => Self::Thing(vec_from_proto(types.types)?), + Annotations::Type(types) => Self::Type(vec_from_proto(types.types)?), + Annotations::ValueAnnotations(value_type) => { + let value_type_proto = value_type.value_type.ok_or_else(|| { + crate::Error::Analyze(AnalyzeError::MissingResponseField { + field: "Value.value_type in VariableAnnotations::ValueAnnotations" + }) + })?; + Self::Value(ValueType::from_proto(value_type_proto)) + } + }) + } +} + +impl TryFromProto for FetchAnnotations { + fn try_from_proto(proto: analyze_proto::query_annotations::FetchAnnotations) -> Result { + let unwrapped = proto.node.ok_or_else(|| { + crate::Error::Analyze(AnalyzeError::MissingResponseField { field: "FetchAnnotations.node" }) + })?; + let fetch_annotations = match unwrapped { + Node::Object(object) => { + let fields = object.annotations.into_iter().map(|(key, annotations)| { + Ok((key, FetchAnnotations::try_from_proto(annotations)?)) + }).collect::>>()?; + FetchAnnotations::Object(fields) + } + Node::List(elements) => { + FetchAnnotations::List(Box::new(FetchAnnotations::try_from_proto(*elements)?)) + } + Node::Leaf(leaf) => { + FetchAnnotations::Leaf(vec_from_proto(leaf.annotations)?) + } + }; + Ok(fetch_annotations) } } diff --git a/rust/tests/behaviour/steps/query.rs b/rust/tests/behaviour/steps/query.rs index a1c459618..0dd401e0a 100644 --- a/rust/tests/behaviour/steps/query.rs +++ b/rust/tests/behaviour/steps/query.rs @@ -38,6 +38,7 @@ use crate::{ util::{functor_encoding::encode_query_structure_as_functor, iter_table, list_contains_json, parse_json}, BehaviourTestOptionalError, Context, }; +use crate::util::functor_encoding::{encode_fetch_annotations_as_functor, encode_query_annotations_as_functor}; pub(crate) async fn run_query( transaction: &Transaction, @@ -1002,7 +1003,7 @@ pub async fn get_answers_of_typeql_analyze_query(context: &mut Context, step: &S pub async fn analyzed_query_pipeline_structure_is(context: &mut Context, step: &Step) { let expected_functor = step.docstring().unwrap(); let analyzed = context.get_analyzed().unwrap(); - let (actual_functor, _preamble) = encode_query_structure_as_functor(&analyzed.structure); + let (actual_functor, _preamble) = encode_query_structure_as_functor(&analyzed); assert_eq!(normalize_functor_for_compare(&actual_functor), normalize_functor_for_compare(expected_functor)); } @@ -1011,7 +1012,7 @@ pub async fn analyzed_query_pipeline_structure_is(context: &mut Context, step: & async fn analyzed_query_preamble_contains(context: &mut Context, step: &Step) { let expected_functor = step.docstring().unwrap(); let analyzed = context.get_analyzed().unwrap(); - let (_pipeline, preamble_functors) = encode_query_structure_as_functor(&analyzed.structure); + let (_pipeline, preamble_functors) = encode_query_structure_as_functor(&analyzed); assert!( preamble_functors.iter().any(|actual_functor| { @@ -1024,11 +1025,45 @@ async fn analyzed_query_preamble_contains(context: &mut Context, step: &Step) { } #[apply(generic_step)] -#[step(expr = r"analyzed query annotations is:")] +#[step(expr = r"analyzed query pipeline annotations are:")] async fn analyzed_query_annotations_is(context: &mut Context, step: &Step) { - todo!() + let expected_functor = step.docstring().unwrap(); + let analyzed = context.get_analyzed().unwrap(); + let (actual_functor, _preamble) = encode_query_annotations_as_functor(&analyzed); + assert_eq!(normalize_functor_for_compare(&actual_functor), normalize_functor_for_compare(expected_functor)); +} + +#[apply(generic_step)] +#[step(expr = r"analyzed preamble annotations contains:")] +async fn analyzed_preamble_annotations_contains(context: &mut Context, step: &Step) { + let expected_functor = step.docstring().unwrap(); + let analyzed = context.get_analyzed().unwrap(); + let (_pipeline, preamble_functors) = encode_query_annotations_as_functor(&analyzed); + + assert!( + preamble_functors.iter().any(|actual_functor| { + normalize_functor_for_compare(actual_functor) == normalize_functor_for_compare(expected_functor) + }), + "Looking for\n\t{}\nin any of:\n\t{}", + normalize_functor_for_compare(expected_functor), + preamble_functors.iter().map(|s| normalize_functor_for_compare(s)).join("\n\t") + ); } +#[apply(generic_step)] +#[step(expr = r"analyzed fetch annotations are:")] +async fn analyzed_fetch_annotations_are(context: &mut Context, step: &Step) { + let expected_functor = step.docstring().unwrap(); + let analyzed = context.get_analyzed().unwrap(); + let actual_functor = encode_fetch_annotations_as_functor(&analyzed); + + assert_eq!( + normalize_functor_for_compare(&actual_functor), + normalize_functor_for_compare(expected_functor) + ); +} + + fn normalize_functor_for_compare(functor: &String) -> String { let mut normalized = functor.to_lowercase(); normalized.retain(|c| !c.is_whitespace()); diff --git a/rust/tests/behaviour/steps/util.rs b/rust/tests/behaviour/steps/util.rs index d65dd52e1..dd1d52cbc 100644 --- a/rust/tests/behaviour/steps/util.rs +++ b/rust/tests/behaviour/steps/util.rs @@ -227,12 +227,16 @@ async fn file_write(context: &mut Context, file_name: String, step: &Step) { #[cfg(debug_assertions)] pub mod functor_encoding { + use std::collections::HashMap; use itertools::Itertools; - type FunctorContext = PipelineStructure; + struct FunctorContext<'a> { + structure: &'a PipelineStructure, + annotations: &'a PipelineAnnotations, + } pub trait FunctorEncoded { - fn encode_as_functor(&self, context: &FunctorContext) -> String; + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String; } pub mod functor_macros { @@ -242,7 +246,10 @@ pub mod functor_encoding { let arr: Vec<&dyn FunctorEncoded> = vec![ $($arg,)* ]; arr.into_iter().map(|s| s.encode_as_functor($context)).join(", ") } - } + }; + ($context:ident, ( $( $arg:ident, )* ) ) => { + functor_macros::encode_args!($context, { $( $arg, )* } ) + }; } macro_rules! encode_functor_impl { ($context:ident, $func:ident $args:tt) => { @@ -251,9 +258,8 @@ pub mod functor_encoding { } macro_rules! add_ignored_fields { - ($qualified:path { $( $arg:ident, )* }) => { - $qualified { $( $arg, )* .. } - }; + ($qualified:path : { $( $arg:ident, )* }) => { $qualified { $( $arg, )* .. } }; + ($qualified:path : ($( $arg:ident, )*)) => { $qualified ( $( $arg, )* .. ) }; } macro_rules! encode_functor { @@ -268,7 +274,7 @@ pub mod functor_encoding { }; ($context:ident, $what:ident => [ $($qualified:path => $func:ident $fields:tt, )* ]) => { match $what { - $( functor_macros::add_ignored_fields!($qualified $fields) => { + $( functor_macros::add_ignored_fields!($qualified : $fields) => { functor_macros::encode_functor_impl!($context, $func $fields) })* } @@ -278,7 +284,7 @@ pub mod functor_encoding { macro_rules! impl_functor_for_impl { ($which:ident => |$self:ident, $context:ident| $block:block) => { impl FunctorEncoded for $which { - fn encode_as_functor($self: &Self, $context: &FunctorContext) -> String { + fn encode_as_functor<'a>($self: &Self, $context: &FunctorContext<'a>) -> String { $block } } @@ -313,21 +319,32 @@ pub mod functor_encoding { functor_macros::impl_functor_for!(primitive String); functor_macros::impl_functor_for!(primitive u64); + + impl FunctorEncoded for HashMap { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { + std::format!("{{ {} }}", self.iter().map(|(k, v)| { + std::format!("{}: {}", k.encode_as_functor(context), v.encode_as_functor(context)) + }).sorted_by(|a,b| a.cmp(b)).join(", ")) + } + } + impl FunctorEncoded for Vec { - fn encode_as_functor(&self, context: &FunctorContext) -> String { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { std::format!("[{}]", self.iter().map(|v| v.encode_as_functor(context)).join(", ")) } } impl FunctorEncoded for Option { - fn encode_as_functor(&self, context: &FunctorContext) -> String { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { self.as_ref().map(|inner| inner.encode_as_functor(context)).unwrap_or("".to_owned()) } } - use typedb_driver::analyze::{conjunction::{Constraint, Conjunction, ConjunctionID, ConstraintVertex, LabelVertex, Reducer, Variable}, FunctionStructure, pipeline::{PipelineStructure, PipelineStage, SortVariable, SortOrder, ReduceAssign}, QueryStructure, ReturnOperation}; + use typedb_driver::analyze::{AnalyzedQuery, conjunction::{Constraint, Conjunction, ConjunctionID, ConstraintVertex, LabelVertex, Reducer, Variable}, FunctionStructure, pipeline::{PipelineStructure, PipelineStage, SortVariable, SortOrder, ReduceAssign}, QueryStructure, ReturnOperation}; + use typedb_driver::analyze::annotations::{FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, PipelineAnnotations, VariableAnnotations}; use typedb_driver::analyze::conjunction::{Comparator, ConstraintExactness}; - use typedb_driver::concept::Value; + use typedb_driver::concept::type_::Type; + use typedb_driver::concept::{Value, ValueType}; use crate::util::functor_encoding::functor_macros::{encode_functor, encode_functor_impl}; functor_macros::impl_functor_for!(struct ReduceAssign { assigned, reducer, } named ReduceAssign); @@ -356,7 +373,7 @@ pub mod functor_encoding { }; } impl FunctorEncoded for Constraint { - fn encode_as_functor(self: &Self, context: &FunctorContext) -> String { + fn encode_as_functor<'a>(self: &Self, context: &FunctorContext<'a>) -> String { match self { Self::Isa { instance, r#type, exactness } => { encode_functor_impl_exactness!(context, exactness, Isa IsaExact { instance, r#type, }) @@ -425,7 +442,7 @@ pub mod functor_encoding { functor_macros::impl_functor_for_impl!(ConstraintVertex => |self, context| { match self { ConstraintVertex::Variable(id) => { id.encode_as_functor(context) } - ConstraintVertex::Label(LabelVertex::Resolved(r#type)) => { r#type.label().to_owned().encode_as_functor(context) } + ConstraintVertex::Label(LabelVertex::Resolved(r#type)) => { r#type.encode_as_functor(context) } ConstraintVertex::Label(LabelVertex::Unresolved(label))=> { label.encode_as_functor(context) } ConstraintVertex::Value(v) => { match v { @@ -442,16 +459,22 @@ pub mod functor_encoding { }; } impl_functor_for_multi!(|self, context| [ - Variable => { format!("${}", context.variable_names.get(self).as_ref().map(|v| v.as_str()).unwrap_or("_")) } + Variable => { format!("${}", context.structure.variable_names.get(self).as_ref().map(|v| v.as_str()).unwrap_or("_")) } + Type => { self.label().to_owned().encode_as_functor(context) } Comparator => { format!("{}", self.symbol()) } - ConjunctionID => { context.conjunctions[self.0 as usize].encode_as_functor(context) } + ConjunctionID => { context.structure.conjunctions[self.0 as usize].encode_as_functor(context) } Conjunction => { let Conjunction { constraints } = self; constraints.encode_as_functor(context) } - PipelineStructure => { let pipeline = &self.stages; functor_macros::encode_functor_impl!(self, Pipeline { pipeline, }) } + PipelineStructure => { let pipeline = &self.stages; functor_macros::encode_functor_impl!(context, Pipeline { pipeline, }) } FunctionStructure => { let FunctionStructure { arguments, returns, body } = self; - let context = body; functor_macros::encode_functor_impl!(context, Function { arguments, returns, body, }) } + ValueType => { + match self { + ValueType::Struct(name) => functor_macros::encode_functor_impl!(context, Struct { name, }), + other => other.name().to_owned().encode_as_functor(context), + } + } SortVariable => { let Self { order, variable } = self; match order { @@ -468,10 +491,140 @@ pub mod functor_encoding { Reduce {} | ]); - pub fn encode_query_structure_as_functor(structure: &QueryStructure) -> (String, Vec) { - let pipeline = &structure.query; - let query = pipeline.encode_as_functor(pipeline); - let preamble = structure.preamble.iter().map(|func| func.encode_as_functor(&func.body)).collect(); + pub fn encode_query_structure_as_functor(analyzed: &AnalyzedQuery) -> (String, Vec) { + let context = FunctorContext { structure: &analyzed.structure.query, annotations: &analyzed.annotations.query }; + let query = analyzed.structure.query.encode_as_functor(&context); + let preamble = analyzed.structure.preamble.iter().zip(analyzed.annotations.preamble.iter()).map(|(func, anno)| { + let context = FunctorContext { structure: &func.body, annotations: &anno.body }; + func.encode_as_functor(&context) + }).collect(); (query, preamble) } + + // annotations + + pub fn encode_query_annotations_as_functor(analyzed: &AnalyzedQuery) -> (String, Vec) { + let context = FunctorContext { structure: &analyzed.structure.query, annotations: &analyzed.annotations.query }; + let query = analyzed.annotations.query.encode_as_functor(&context); + let preamble = analyzed.annotations.preamble.iter().zip(analyzed.structure.preamble.iter()) + .map(|(annotations, structure)| { + let context = FunctorContext { structure: &structure.body, annotations: &annotations.body }; + annotations.encode_as_functor(&context) + }).collect(); + (query, preamble) + } + + impl FunctorEncoded for PipelineAnnotations { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { + let encoded_stages = context.structure.stages.iter().map(|stage| { + match stage { + PipelineStage::Match { block } => { + let block = &BlockAnnotationToEncode(block.0); + functor_macros::encode_functor_impl!(context, Match { block, }) + }, + PipelineStage::Insert { block } => { + let block = &BlockAnnotationToEncode(block.0); + functor_macros::encode_functor_impl!(context, Insert { block, }) + } + PipelineStage::Delete { block, .. } => { + let block = &BlockAnnotationToEncode(block.0); + functor_macros::encode_functor_impl!(context, Delete { block, }) + } + PipelineStage::Put { block } => { + let block = &BlockAnnotationToEncode(block.0); + functor_macros::encode_functor_impl!(context, Put { block, }) + }, + PipelineStage::Update { block } => { + let block = &BlockAnnotationToEncode(block.0); + functor_macros::encode_functor_impl!(context, Update { block, }) + } + PipelineStage::Select { .. } => functor_macros::encode_functor_impl!(context, Select { }), + PipelineStage::Sort { .. } => functor_macros::encode_functor_impl!(context, Sort { }), + PipelineStage::Offset { .. } => functor_macros::encode_functor_impl!(context, Offset { }), + PipelineStage::Limit { .. } => functor_macros::encode_functor_impl!(context, Limit { }), + PipelineStage::Require { .. } => functor_macros::encode_functor_impl!(context, Require { }), + PipelineStage::Distinct => functor_macros::encode_functor_impl!(context, Select { }), + PipelineStage::Reduce { .. } => functor_macros::encode_functor_impl!(context, Reduce { }), + } + }).collect::>(); + let encoded_stages_ref = &encoded_stages; + encode_functor_impl!(context, Pipeline { encoded_stages_ref, })// Not ideal to encode the elements again + } + } + + functor_macros::impl_functor_for!(struct FunctionAnnotations { arguments, returns, body, } named Function); + functor_macros::impl_functor_for!(enum FunctionReturnAnnotations [ Single(annotations,) | Stream(annotations,) | ]); + + #[derive(Debug, Clone, Copy)] + struct TrunkAnnotationToEncode(usize); + + #[derive(Debug, Clone, Copy)] + struct BlockAnnotationToEncode(usize); + impl From for BlockAnnotationToEncode { + fn from(value: ConjunctionID) -> Self { + Self(value.0) + } + } + + enum SubBlockAnnotation { + Trunk { conjunction: TrunkAnnotationToEncode }, + Or { branches: Vec }, + Not { conjunction: BlockAnnotationToEncode }, + Try { conjunction: BlockAnnotationToEncode }, + } + + impl FunctorEncoded for BlockAnnotationToEncode { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { + let mut elements = vec![SubBlockAnnotation::Trunk { conjunction: TrunkAnnotationToEncode(self.0) }]; + elements.extend(context.structure.conjunctions[self.0].constraints.iter() + .filter_map(|c| match c { + Constraint::Or { branches } => { + let branches = branches.iter().copied().map_into().collect(); + Some(SubBlockAnnotation::Or { branches }) + }, + Constraint::Not { conjunction } => { + Some(SubBlockAnnotation::Not { conjunction: (*conjunction).into() }) + }, + Constraint::Try { conjunction } => { + Some(SubBlockAnnotation::Try { conjunction: (*conjunction).into() }) + }, + _ => None, + })); + elements.encode_as_functor(context) + } + } + + functor_macros::impl_functor_for!(enum SubBlockAnnotation [ Trunk { conjunction, } | Or { branches, } | Not { conjunction, } | Try { conjunction, } | ]); + functor_macros::impl_functor_for!(enum VariableAnnotations [ Thing (annotations,) | Type (annotations,) | Value (value_types,) | ]); + impl_functor_for_multi!(|self, context| [ + TrunkAnnotationToEncode => { + context.annotations.conjunction_annotations[self.0].variable_annotations.encode_as_functor(context) + } + ]); + + // Fetch + pub fn encode_fetch_annotations_as_functor(analyzed: &AnalyzedQuery) -> String { + let context = FunctorContext { + structure: &analyzed.structure.query, + annotations: &analyzed.annotations.query + }; + analyzed.annotations.fetch.encode_as_functor(&context) + } + + impl FunctorEncoded for FetchAnnotations { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { + match self { + FetchAnnotations::Leaf(value_types) => { + value_types.encode_as_functor(context) + } + FetchAnnotations::Object(possible_fields) => { + possible_fields.encode_as_functor(context) + } + FetchAnnotations::List(elements) => { + let elements_as_ref = elements.as_ref(); + encode_functor_impl!(context, List { elements_as_ref, }) + } + } + } + } } From 00999073361deba00bab7c6912eb58cdc7e2a714 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Fri, 3 Oct 2025 19:22:17 +0200 Subject: [PATCH 13/22] Bump behaviour; implement unhappy steps --- dependencies/typedb/repositories.bzl | 2 +- rust/tests/behaviour/steps/query.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index 8adc1a2f2..71cc250f9 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -35,5 +35,5 @@ def typedb_behaviour(): git_repository( name = "typedb_behaviour", remote = "https://github.com/krishnangovindraj/typedb-behaviour", - commit = "92d5dc578fd087974173ed926809f5c425de543b", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour + commit = "569004b09f36bdecec5e075f16144fbdc6176655", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour ) diff --git a/rust/tests/behaviour/steps/query.rs b/rust/tests/behaviour/steps/query.rs index 0dd401e0a..56f060cf6 100644 --- a/rust/tests/behaviour/steps/query.rs +++ b/rust/tests/behaviour/steps/query.rs @@ -998,6 +998,14 @@ pub async fn get_answers_of_typeql_analyze_query(context: &mut Context, step: &S context.set_analyzed(run_analyze_query(context.transaction(), step.docstring().unwrap()).await).unwrap(); } +#[apply(generic_step)] +#[step(expr = r"typeql analyze query{may_error}")] +async fn typeql_analyze_query_may_error(context: &mut Context, may_error: params::MayError, step: &Step) { + context.cleanup_answers().await; + let result = run_analyze_query(context.transaction(), step.docstring().unwrap()).await; + may_error.check(result); +} + #[apply(generic_step)] #[step(expr = r"analyzed query pipeline structure is:")] pub async fn analyzed_query_pipeline_structure_is(context: &mut Context, step: &Step) { From d90f9ddc59d68cf49ecf9d403e658eab382009cf Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Mon, 6 Oct 2025 12:57:35 +0200 Subject: [PATCH 14/22] Bump protocol; update for field renaming --- Cargo.lock | 2 +- dependencies/typedb/repositories.bzl | 2 +- rust/Cargo.toml | 2 +- rust/src/connection/network/proto/analyze.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4d733029..7ebd6ad05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2829,7 +2829,7 @@ dependencies = [ [[package]] name = "typedb-protocol" version = "0.0.0" -source = "git+https://github.com/typedb/typedb-protocol?rev=8e7077e4562bc0d6e8b4b64b400544615dfa447e#8e7077e4562bc0d6e8b4b64b400544615dfa447e" +source = "git+https://github.com/typedb/typedb-protocol?rev=ba56e0987b62129ce5efa2eae61ff79488b0bbfd#ba56e0987b62129ce5efa2eae61ff79488b0bbfd" dependencies = [ "prost", "tonic", diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index 71cc250f9..3449f88d1 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -28,7 +28,7 @@ def typedb_protocol(): git_repository( name = "typedb_protocol", remote = "https://github.com/typedb/typedb-protocol", - commit = "8e7077e4562bc0d6e8b4b64b400544615dfa447e", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol + commit = "ba56e0987b62129ce5efa2eae61ff79488b0bbfd", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol ) def typedb_behaviour(): diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 5d6dd396e..1e5fd12ad 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -65,7 +65,7 @@ [dependencies.typedb-protocol] features = [] - rev = "8e7077e4562bc0d6e8b4b64b400544615dfa447e" + rev = "ba56e0987b62129ce5efa2eae61ff79488b0bbfd" git = "https://github.com/typedb/typedb-protocol" default-features = false diff --git a/rust/src/connection/network/proto/analyze.rs b/rust/src/connection/network/proto/analyze.rs index 2b52ed297..80e3a5309 100644 --- a/rust/src/connection/network/proto/analyze.rs +++ b/rust/src/connection/network/proto/analyze.rs @@ -360,7 +360,7 @@ impl TryFromProto for LabelVerte fn try_from_proto(value: conjunction_structure::structure_vertex::Label) -> Result { use conjunction_structure::structure_vertex::label::Label as LabelProto; match value.label { - Some(LabelProto::FailedInference(label)) => Ok(LabelVertex::Unresolved(label)), + Some(LabelProto::Unresolved(label)) => Ok(LabelVertex::Unresolved(label)), Some(LabelProto::Resolved(type_proto)) => { let type_ = type_::Type::try_from_proto(type_proto)?; Ok(LabelVertex::Resolved(type_)) From ae37ec75a45b30fdf4b158ffceca36e4e8709ea0 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Mon, 6 Oct 2025 15:17:49 +0200 Subject: [PATCH 15/22] Bump behaviour --- Cargo.lock | 2 +- dependencies/typedb/repositories.bzl | 4 ++-- rust/Cargo.toml | 2 +- rust/src/analyze/conjunction.rs | 10 ++++---- rust/src/connection/network/proto/analyze.rs | 24 ++++++++------------ rust/tests/behaviour/steps/util.rs | 9 ++++---- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ebd6ad05..a0da26a88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2829,7 +2829,7 @@ dependencies = [ [[package]] name = "typedb-protocol" version = "0.0.0" -source = "git+https://github.com/typedb/typedb-protocol?rev=ba56e0987b62129ce5efa2eae61ff79488b0bbfd#ba56e0987b62129ce5efa2eae61ff79488b0bbfd" +source = "git+https://github.com/typedb/typedb-protocol?rev=bf987393f6eb1462846d6c62bf2ffe7ae4b6e90d#bf987393f6eb1462846d6c62bf2ffe7ae4b6e90d" dependencies = [ "prost", "tonic", diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index 3449f88d1..bf8d3e64e 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -28,12 +28,12 @@ def typedb_protocol(): git_repository( name = "typedb_protocol", remote = "https://github.com/typedb/typedb-protocol", - commit = "ba56e0987b62129ce5efa2eae61ff79488b0bbfd", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol + commit = "bf987393f6eb1462846d6c62bf2ffe7ae4b6e90d", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol ) def typedb_behaviour(): git_repository( name = "typedb_behaviour", remote = "https://github.com/krishnangovindraj/typedb-behaviour", - commit = "569004b09f36bdecec5e075f16144fbdc6176655", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour + commit = "8a0349d9c4dc7bda2d870df7dda41d395d6b1784", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour ) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 1e5fd12ad..e8c9cb025 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -65,7 +65,7 @@ [dependencies.typedb-protocol] features = [] - rev = "ba56e0987b62129ce5efa2eae61ff79488b0bbfd" + rev = "bf987393f6eb1462846d6c62bf2ffe7ae4b6e90d" git = "https://github.com/typedb/typedb-protocol" default-features = false diff --git a/rust/src/analyze/conjunction.rs b/rust/src/analyze/conjunction.rs index 4b97be48e..1f6af9313 100644 --- a/rust/src/analyze/conjunction.rs +++ b/rust/src/analyze/conjunction.rs @@ -130,14 +130,16 @@ pub struct Variable(pub u32); #[derive(Debug)] pub enum ConstraintVertex { Variable(Variable), - Label(LabelVertex), + Label(type_::Type), Value(concept::Value), + NamedRole(NamedRole), + Unresolved(String) // Error condition } #[derive(Debug)] -pub enum LabelVertex { - Resolved(type_::Type), - Unresolved(String), +pub struct NamedRole { + pub variable: Variable, + pub name: String, } #[derive(Debug)] diff --git a/rust/src/connection/network/proto/analyze.rs b/rust/src/connection/network/proto/analyze.rs index 80e3a5309..44b5a74f9 100644 --- a/rust/src/connection/network/proto/analyze.rs +++ b/rust/src/connection/network/proto/analyze.rs @@ -31,7 +31,7 @@ use typedb_protocol::analyze::res::analyzed_query::query_annotations::variable_a use crate::{ analyze::{ conjunction::{ - Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, LabelVertex, Reducer, + Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, Reducer, Variable, }, pipeline::{PipelineStage, PipelineStructure, ReduceAssign, SortOrder, SortVariable}, @@ -43,7 +43,7 @@ use crate::{ error::AnalyzeError, }; use crate::analyze::annotations::{ConjunctionAnnotations, FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, PipelineAnnotations, VariableAnnotations}; -use crate::analyze::conjunction::Comparator; +use crate::analyze::conjunction::{Comparator, NamedRole}; use crate::concept::ValueType; use crate::connection::message::AnalyzeResponse; use crate::connection::network::proto::FromProto; @@ -356,17 +356,11 @@ impl TryFromProto for So } } -impl TryFromProto for LabelVertex { - fn try_from_proto(value: conjunction_structure::structure_vertex::Label) -> Result { - use conjunction_structure::structure_vertex::label::Label as LabelProto; - match value.label { - Some(LabelProto::Unresolved(label)) => Ok(LabelVertex::Unresolved(label)), - Some(LabelProto::Resolved(type_proto)) => { - let type_ = type_::Type::try_from_proto(type_proto)?; - Ok(LabelVertex::Resolved(type_)) - } - None => Err(AnalyzeError::MissingResponseField { field: "LabelVertex.label" }.into()), - } +impl TryFromProto for NamedRole { + fn try_from_proto(proto: conjunction_structure::structure_vertex::NamedRole) -> Result { + let variable = expect_try_into(proto.variable, "NamedRole.variable")?; + let name = proto.name; + Ok(NamedRole { variable, name }) } } @@ -375,8 +369,10 @@ impl TryFromProto for ConstraintVertex { use conjunction_structure::structure_vertex::Vertex; match value.vertex { Some(Vertex::Variable(variable)) => Ok(ConstraintVertex::Variable(Variable::try_from_proto(variable)?)), - Some(Vertex::Label(label)) => Ok(ConstraintVertex::Label(LabelVertex::try_from_proto(label)?)), + Some(Vertex::Label(type_)) => Ok(ConstraintVertex::Label(type_::Type::try_from_proto(type_)?)), Some(Vertex::Value(value)) => Ok(ConstraintVertex::Value(Value::try_from_proto(value)?)), + Some(Vertex::NamedRole(role)) => Ok(ConstraintVertex::NamedRole(NamedRole::try_from_proto(role)?)), + Some(Vertex::Unresolved(label)) => Ok(ConstraintVertex::Unresolved(label)), None => Err(AnalyzeError::MissingResponseField { field: "StructureVertex.vertex" }.into()), } } diff --git a/rust/tests/behaviour/steps/util.rs b/rust/tests/behaviour/steps/util.rs index dd1d52cbc..661d0b7cc 100644 --- a/rust/tests/behaviour/steps/util.rs +++ b/rust/tests/behaviour/steps/util.rs @@ -340,9 +340,9 @@ pub mod functor_encoding { } } - use typedb_driver::analyze::{AnalyzedQuery, conjunction::{Constraint, Conjunction, ConjunctionID, ConstraintVertex, LabelVertex, Reducer, Variable}, FunctionStructure, pipeline::{PipelineStructure, PipelineStage, SortVariable, SortOrder, ReduceAssign}, QueryStructure, ReturnOperation}; + use typedb_driver::analyze::{AnalyzedQuery, conjunction::{Constraint, Conjunction, ConjunctionID, ConstraintVertex, Reducer, Variable}, FunctionStructure, pipeline::{PipelineStructure, PipelineStage, SortVariable, SortOrder, ReduceAssign}, QueryStructure, ReturnOperation}; use typedb_driver::analyze::annotations::{FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, PipelineAnnotations, VariableAnnotations}; - use typedb_driver::analyze::conjunction::{Comparator, ConstraintExactness}; + use typedb_driver::analyze::conjunction::{Comparator, ConstraintExactness, NamedRole}; use typedb_driver::concept::type_::Type; use typedb_driver::concept::{Value, ValueType}; use crate::util::functor_encoding::functor_macros::{encode_functor, encode_functor_impl}; @@ -442,8 +442,9 @@ pub mod functor_encoding { functor_macros::impl_functor_for_impl!(ConstraintVertex => |self, context| { match self { ConstraintVertex::Variable(id) => { id.encode_as_functor(context) } - ConstraintVertex::Label(LabelVertex::Resolved(r#type)) => { r#type.encode_as_functor(context) } - ConstraintVertex::Label(LabelVertex::Unresolved(label))=> { label.encode_as_functor(context) } + ConstraintVertex::Label(type_) => { type_.encode_as_functor(context) } + ConstraintVertex::Unresolved(label) => { label.encode_as_functor(context) } + ConstraintVertex::NamedRole(NamedRole { name,.. }) => { name.encode_as_functor(context) } ConstraintVertex::Value(v) => { match v { Value::String(s) => std::format!("\"{}\"", s.to_string()), From ad6573da1ed33f5b51af5ab0394ac48155796add Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Mon, 6 Oct 2025 17:49:01 +0200 Subject: [PATCH 16/22] rustfmt + rearrange --- rust/src/analyze/annotations.rs | 13 +- rust/src/analyze/conjunction.rs | 4 +- rust/src/analyze/mod.rs | 6 +- rust/src/connection/message.rs | 1 - rust/src/connection/network/proto/analyze.rs | 82 +-- rust/src/connection/network/proto/message.rs | 4 +- rust/src/connection/network/proto/mod.rs | 2 +- rust/src/connection/transaction_stream.rs | 6 +- rust/src/transaction.rs | 5 +- rust/tests/behaviour/steps/analyze.rs | 528 +++++++++++++++++++ rust/tests/behaviour/steps/lib.rs | 3 +- rust/tests/behaviour/steps/query.rs | 97 +--- rust/tests/behaviour/steps/util.rs | 406 -------------- 13 files changed, 594 insertions(+), 563 deletions(-) create mode 100644 rust/tests/behaviour/steps/analyze.rs diff --git a/rust/src/analyze/annotations.rs b/rust/src/analyze/annotations.rs index e41b63cd6..a065fafa7 100644 --- a/rust/src/analyze/annotations.rs +++ b/rust/src/analyze/annotations.rs @@ -18,14 +18,14 @@ */ use std::{ - collections::BTreeMap, + collections::{BTreeMap, HashMap}, vec::Vec, }; -use std::collections::HashMap; -use crate::analyze::conjunction::Variable; -use crate::concept::type_::Type; -use crate::concept::ValueType; +use crate::{ + analyze::conjunction::Variable, + concept::{type_::Type, ValueType}, +}; #[derive(Debug)] pub struct PipelineAnnotations { @@ -61,6 +61,5 @@ pub struct ConjunctionAnnotations { pub enum VariableAnnotations { Thing(Vec), Type(Vec), - Value(ValueType) + Value(ValueType), } - diff --git a/rust/src/analyze/conjunction.rs b/rust/src/analyze/conjunction.rs index 1f6af9313..492b3d818 100644 --- a/rust/src/analyze/conjunction.rs +++ b/rust/src/analyze/conjunction.rs @@ -133,7 +133,7 @@ pub enum ConstraintVertex { Label(type_::Type), Value(concept::Value), NamedRole(NamedRole), - Unresolved(String) // Error condition + Unresolved(String), // Error condition } #[derive(Debug)] @@ -157,7 +157,7 @@ pub enum Comparator { Greater, GreaterOrEqual, Like, - Contains + Contains, } impl Comparator { diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs index 7c42ccbb2..782043235 100644 --- a/rust/src/analyze/mod.rs +++ b/rust/src/analyze/mod.rs @@ -17,17 +17,15 @@ * under the License. */ -use futures::StreamExt; - use crate::analyze::{ + annotations::{FetchAnnotations, FunctionAnnotations, PipelineAnnotations}, conjunction::{Reducer, Variable}, pipeline::PipelineStructure, }; -use crate::analyze::annotations::{FetchAnnotations, FunctionAnnotations, PipelineAnnotations}; +pub mod annotations; pub mod conjunction; pub mod pipeline; -pub mod annotations; pub type TryFromError = &'static str; diff --git a/rust/src/connection/message.rs b/rust/src/connection/message.rs index 07f2ff9c0..ecee752e6 100644 --- a/rust/src/connection/message.rs +++ b/rust/src/connection/message.rs @@ -166,7 +166,6 @@ pub(super) enum AnalyzeResponse { Err(ServerError), } - #[derive(Debug)] pub(super) enum QueryRequest { Query { query: String, options: QueryOptions }, diff --git a/rust/src/connection/network/proto/analyze.rs b/rust/src/connection/network/proto/analyze.rs index 44b5a74f9..a868f667c 100644 --- a/rust/src/connection/network/proto/analyze.rs +++ b/rust/src/connection/network/proto/analyze.rs @@ -18,36 +18,42 @@ */ use std::collections::HashMap; -use typedb_protocol::{analyze::res::{ - analyzed_query as analyze_proto, - analyzed_query::{ - query_structure, - query_structure::pipeline_structure + +use typedb_protocol::{ + analyze::res::{ + analyzed_query as analyze_proto, + analyzed_query::{ + query_annotations::{fetch_annotations::Node, variable_annotations::Annotations}, + query_structure, + query_structure::pipeline_structure, + }, }, -}, conjunction_structure, conjunction_structure::StructureConstraint, ConjunctionStructure}; -use typedb_protocol::analyze::res::analyzed_query::query_annotations::fetch_annotations::Node; -use typedb_protocol::analyze::res::analyzed_query::query_annotations::variable_annotations::Annotations; + conjunction_structure, + conjunction_structure::StructureConstraint, + ConjunctionStructure, +}; use crate::{ analyze::{ + annotations::{ + ConjunctionAnnotations, FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, + PipelineAnnotations, VariableAnnotations, + }, conjunction::{ - Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, Reducer, - Variable, + Comparator, Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, NamedRole, + Reducer, Variable, }, pipeline::{PipelineStage, PipelineStructure, ReduceAssign, SortOrder, SortVariable}, AnalyzedQuery, FunctionStructure, QueryAnnotations, QueryStructure, ReturnOperation, }, common::Result, - concept::{type_, Kind, Value}, - connection::network::proto::TryFromProto, - error::AnalyzeError, + concept::{type_, Kind, Value, ValueType}, + connection::{ + message::AnalyzeResponse, + network::proto::{FromProto, TryFromProto}, + }, + error::{AnalyzeError, ServerError}, }; -use crate::analyze::annotations::{ConjunctionAnnotations, FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, PipelineAnnotations, VariableAnnotations}; -use crate::analyze::conjunction::{Comparator, NamedRole}; -use crate::concept::ValueType; -use crate::connection::message::AnalyzeResponse; -use crate::connection::network::proto::FromProto; -use crate::error::ServerError; pub(super) fn expect_try_into>(x: Option, field: &'static str) -> Result { Dst::try_from_proto(x.ok_or_else(|| crate::Error::Analyze(AnalyzeError::MissingResponseField { field }))?) @@ -76,7 +82,7 @@ impl TryFromProto for AnalyzeResponse { use typedb_protocol::analyze::res::Result as ResultProto; let result = match proto { ResultProto::Ok(analyzed_query) => AnalyzeResponse::Ok(AnalyzedQuery::try_from_proto(analyzed_query)?), - ResultProto::Err(err) => AnalyzeResponse::Err(ServerError::from_proto(err)), + ResultProto::Err(err) => AnalyzeResponse::Err(ServerError::from_proto(err)), }; Ok(result) } @@ -391,7 +397,7 @@ impl TryFromProto for QueryAnnotations { let query = expect_try_into(proto.query, "QueryAnnotations.query")?; let preamble = vec_from_proto(proto.preamble)?; let fetch = proto.fetch.map(|fetch| FetchAnnotations::try_from_proto(fetch)).transpose()?; - Ok(Self { query, preamble, fetch}) + Ok(Self { query, preamble, fetch }) } } @@ -414,11 +420,17 @@ impl TryFromProto for Pip } } -impl TryFromProto for ConjunctionAnnotations { - fn try_from_proto(proto: analyze_proto::query_annotations::pipeline_annotations::ConjunctionAnnotations) -> Result { - let variable_annotations = proto.variable_annotations.into_iter().map(|(id, annotations_proto)| { - Ok((Variable(id), VariableAnnotations::try_from_proto(annotations_proto)?)) - }).collect::>>()?; +impl TryFromProto + for ConjunctionAnnotations +{ + fn try_from_proto( + proto: analyze_proto::query_annotations::pipeline_annotations::ConjunctionAnnotations, + ) -> Result { + let variable_annotations = proto + .variable_annotations + .into_iter() + .map(|(id, annotations_proto)| Ok((Variable(id), VariableAnnotations::try_from_proto(annotations_proto)?))) + .collect::>>()?; Ok(Self { variable_annotations }) } } @@ -434,7 +446,7 @@ impl TryFromProto for Var Annotations::ValueAnnotations(value_type) => { let value_type_proto = value_type.value_type.ok_or_else(|| { crate::Error::Analyze(AnalyzeError::MissingResponseField { - field: "Value.value_type in VariableAnnotations::ValueAnnotations" + field: "Value.value_type in VariableAnnotations::ValueAnnotations", }) })?; Self::Value(ValueType::from_proto(value_type_proto)) @@ -450,17 +462,15 @@ impl TryFromProto for FetchA })?; let fetch_annotations = match unwrapped { Node::Object(object) => { - let fields = object.annotations.into_iter().map(|(key, annotations)| { - Ok((key, FetchAnnotations::try_from_proto(annotations)?)) - }).collect::>>()?; + let fields = object + .annotations + .into_iter() + .map(|(key, annotations)| Ok((key, FetchAnnotations::try_from_proto(annotations)?))) + .collect::>>()?; FetchAnnotations::Object(fields) } - Node::List(elements) => { - FetchAnnotations::List(Box::new(FetchAnnotations::try_from_proto(*elements)?)) - } - Node::Leaf(leaf) => { - FetchAnnotations::Leaf(vec_from_proto(leaf.annotations)?) - } + Node::List(elements) => FetchAnnotations::List(Box::new(FetchAnnotations::try_from_proto(*elements)?)), + Node::Leaf(leaf) => FetchAnnotations::Leaf(vec_from_proto(leaf.annotations)?), }; Ok(fetch_annotations) } diff --git a/rust/src/connection/network/proto/message.rs b/rust/src/connection/network/proto/message.rs index df2dd99f1..dae42b5cb 100644 --- a/rust/src/connection/network/proto/message.rs +++ b/rust/src/connection/network/proto/message.rs @@ -26,18 +26,16 @@ use uuid::Uuid; use super::{FromProto, IntoProto, TryFromProto, TryIntoProto}; use crate::{ - analyze::AnalyzedQuery, answer::{concept_document::ConceptDocumentHeader, concept_row::ConceptRowHeader, QueryType}, common::{info::DatabaseInfo, RequestID, Result}, connection::message::{ - DatabaseExportResponse, DatabaseImportRequest, QueryRequest, QueryResponse, Request, Response, + AnalyzeResponse, DatabaseExportResponse, DatabaseImportRequest, QueryRequest, QueryResponse, Request, Response, TransactionRequest, TransactionResponse, }, error::{ConnectionError, InternalError, ServerError}, info::UserInfo, Credentials, }; -use crate::connection::message::AnalyzeResponse; impl TryIntoProto for Request { fn try_into_proto(self) -> Result { diff --git a/rust/src/connection/network/proto/mod.rs b/rust/src/connection/network/proto/mod.rs index cea01e2db..91b9910a2 100644 --- a/rust/src/connection/network/proto/mod.rs +++ b/rust/src/connection/network/proto/mod.rs @@ -17,7 +17,7 @@ * under the License. */ -use crate::{analyze::TryFromError, Result}; +use crate::Result; mod analyze; mod common; diff --git a/rust/src/connection/transaction_stream.rs b/rust/src/connection/transaction_stream.rs index 18f2d14a1..20c2de0c9 100644 --- a/rust/src/connection/transaction_stream.rs +++ b/rust/src/connection/transaction_stream.rs @@ -31,12 +31,10 @@ use crate::{ stream::{BoxStream, Stream}, Promise, Result, }, - connection::message::{QueryRequest, QueryResponse, TransactionRequest, TransactionResponse}, - error::{ConnectionError, InternalError}, + connection::message::{AnalyzeResponse, QueryRequest, QueryResponse, TransactionRequest, TransactionResponse}, + error::{AnalyzeError, ConnectionError, InternalError, ServerError}, promisify, resolve, Error, QueryOptions, TransactionOptions, TransactionType, }; -use crate::connection::message::AnalyzeResponse; -use crate::error::{AnalyzeError, ServerError}; macro_rules! require_transaction_response { ($response:expr, $variant:ident(_)) => { diff --git a/rust/src/transaction.rs b/rust/src/transaction.rs index 60b5ba59a..277a4d117 100644 --- a/rust/src/transaction.rs +++ b/rust/src/transaction.rs @@ -80,11 +80,12 @@ impl Transaction { self.transaction_stream.query(query, options) } - /// Performs a TypeQL query in this transaction. + /// Analyzes a TypeQL query in this transaction, + /// returning the translated structure & inferred types. /// /// # Arguments /// - /// * `query` — The TypeQL query to be executed + /// * `query` — The TypeQL query to be analyzed /// /// # Examples /// diff --git a/rust/tests/behaviour/steps/analyze.rs b/rust/tests/behaviour/steps/analyze.rs new file mode 100644 index 000000000..366451aac --- /dev/null +++ b/rust/tests/behaviour/steps/analyze.rs @@ -0,0 +1,528 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use cucumber::gherkin::Step; +use itertools::Itertools; +use macro_rules_attribute::apply; +use typedb_driver::{analyze::AnalyzedQuery, Transaction, Result as TypeDBResult}; +use crate::{Context, params, generic_step}; +use crate::analyze::functor_encoding::{encode_fetch_annotations_as_functor, encode_query_annotations_as_functor, encode_query_structure_as_functor}; +// use functor_encoding::{encode_fetch_annotations_as_functor, encode_query_annotations_as_functor, encode_query_structure_as_functor}; + +pub(crate) async fn run_analyze_query( + transaction: &Transaction, + query: impl AsRef, +) -> TypeDBResult { + transaction.analyze_query(query).await +} + +#[apply(generic_step)] +#[step(expr = r"get answers of typeql analyze query")] +pub async fn get_answers_of_typeql_analyze_query(context: &mut Context, step: &Step) { + context.cleanup_answers().await; + context.set_analyzed(run_analyze_query(context.transaction(), step.docstring().unwrap()).await).unwrap(); +} + +#[apply(generic_step)] +#[step(expr = r"typeql analyze query{may_error}")] +async fn typeql_analyze_query_may_error(context: &mut Context, may_error: params::MayError, step: &Step) { + context.cleanup_answers().await; + let result = run_analyze_query(context.transaction(), step.docstring().unwrap()).await; + may_error.check(result); +} + +#[apply(generic_step)] +#[step(expr = r"analyzed query pipeline structure is:")] +pub async fn analyzed_query_pipeline_structure_is(context: &mut Context, step: &Step) { + let expected_functor = step.docstring().unwrap(); + let analyzed = context.get_analyzed().unwrap(); + let (actual_functor, _preamble) = encode_query_structure_as_functor(&analyzed); + assert_eq!(normalize_functor_for_compare(&actual_functor), normalize_functor_for_compare(expected_functor)); +} + +#[apply(generic_step)] +#[step(expr = r"analyzed query preamble contains:")] +async fn analyzed_query_preamble_contains(context: &mut Context, step: &Step) { + let expected_functor = step.docstring().unwrap(); + let analyzed = context.get_analyzed().unwrap(); + let (_pipeline, preamble_functors) = encode_query_structure_as_functor(&analyzed); + + assert!( + preamble_functors.iter().any(|actual_functor| { + normalize_functor_for_compare(actual_functor) == normalize_functor_for_compare(expected_functor) + }), + "Looking for\n\t{}\nin any of:\n\t{}", + normalize_functor_for_compare(expected_functor), + preamble_functors.iter().map(|s| normalize_functor_for_compare(s)).join("\n\t") + ); +} + +#[apply(generic_step)] +#[step(expr = r"analyzed query pipeline annotations are:")] +async fn analyzed_query_annotations_is(context: &mut Context, step: &Step) { + let expected_functor = step.docstring().unwrap(); + let analyzed = context.get_analyzed().unwrap(); + let (actual_functor, _preamble) = encode_query_annotations_as_functor(&analyzed); + assert_eq!(normalize_functor_for_compare(&actual_functor), normalize_functor_for_compare(expected_functor)); +} + +#[apply(generic_step)] +#[step(expr = r"analyzed preamble annotations contains:")] +async fn analyzed_preamble_annotations_contains(context: &mut Context, step: &Step) { + let expected_functor = step.docstring().unwrap(); + let analyzed = context.get_analyzed().unwrap(); + let (_pipeline, preamble_functors) = encode_query_annotations_as_functor(&analyzed); + + assert!( + preamble_functors.iter().any(|actual_functor| { + normalize_functor_for_compare(actual_functor) == normalize_functor_for_compare(expected_functor) + }), + "Looking for\n\t{}\nin any of:\n\t{}", + normalize_functor_for_compare(expected_functor), + preamble_functors.iter().map(|s| normalize_functor_for_compare(s)).join("\n\t") + ); +} + +#[apply(generic_step)] +#[step(expr = r"analyzed fetch annotations are:")] +async fn analyzed_fetch_annotations_are(context: &mut Context, step: &Step) { + let expected_functor = step.docstring().unwrap(); + let analyzed = context.get_analyzed().unwrap(); + let actual_functor = encode_fetch_annotations_as_functor(&analyzed); + + assert_eq!( + normalize_functor_for_compare(&actual_functor), + normalize_functor_for_compare(expected_functor) + ); +} + +fn normalize_functor_for_compare(functor: &String) -> String { + let mut normalized = functor.to_lowercase(); + normalized.retain(|c| !c.is_whitespace()); + normalized +} + + + +#[cfg(debug_assertions)] +pub mod functor_encoding { + use std::collections::HashMap; + use itertools::Itertools; + + struct FunctorContext<'a> { + structure: &'a PipelineStructure, + annotations: &'a PipelineAnnotations, + } + + pub trait FunctorEncoded { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String; + } + + pub mod functor_macros { + macro_rules! encode_args { + ($context:ident, { $( $arg:ident, )* } ) => { + { + let arr: Vec<&dyn FunctorEncoded> = vec![ $($arg,)* ]; + arr.into_iter().map(|s| s.encode_as_functor($context)).join(", ") + } + }; + ($context:ident, ( $( $arg:ident, )* ) ) => { + functor_macros::encode_args!($context, { $( $arg, )* } ) + }; + } + macro_rules! encode_functor_impl { + ($context:ident, $func:ident $args:tt) => { + std::format!("{}({})", std::stringify!($func), functor_macros::encode_args!($context, $args)) + }; + } + + macro_rules! add_ignored_fields { + ($qualified:path : { $( $arg:ident, )* }) => { $qualified { $( $arg, )* .. } }; + ($qualified:path : ($( $arg:ident, )*)) => { $qualified ( $( $arg, )* .. ) }; + } + + macro_rules! encode_functor { + ($context:ident, $what:ident as struct $struct_name:ident $fields:tt) => { + functor_macros::encode_functor!($context, $what => [ $struct_name => $struct_name $fields, ]) + }; + ($context:ident, $what:ident as struct $struct_name:ident $fields:tt named $renamed:ident ) => { + functor_macros::encode_functor!($context, $what => [ $struct_name => $renamed $fields, ]) + }; + ($context:ident, $what:ident as enum $enum_name:ident [ $($variant:ident $fields:tt |)* ]) => { + functor_macros::encode_functor!($context, $what => [ $( $enum_name::$variant => $variant $fields ,)* ]) + }; + ($context:ident, $what:ident => [ $($qualified:path => $func:ident $fields:tt, )* ]) => { + match $what { + $( functor_macros::add_ignored_fields!($qualified : $fields) => { + functor_macros::encode_functor_impl!($context, $func $fields) + })* + } + }; + } + + macro_rules! impl_functor_for_impl { + ($which:ident => |$self:ident, $context:ident| $block:block) => { + impl FunctorEncoded for $which { + fn encode_as_functor<'a>($self: &Self, $context: &FunctorContext<'a>) -> String { + $block + } + } + }; + } + + macro_rules! impl_functor_for { + (struct $struct_name:ident $fields:tt) => { + functor_macros::impl_functor_for!(struct $struct_name $fields named $struct_name); + }; + (struct $struct_name:ident $fields:tt named $renamed:ident) => { + functor_macros::impl_functor_for_impl!($struct_name => |self, context| { + functor_macros::encode_functor!(context, self as struct $struct_name $fields named $renamed) + }); + }; + (enum $enum_name:ident [ $($func:ident $fields:tt |)* ]) => { + functor_macros::impl_functor_for_impl!($enum_name => |self, context| { + functor_macros::encode_functor!(context, self as enum $enum_name [ $($func $fields |)* ]) + }); + }; + (primitive $primitive:ident) => { + functor_macros::impl_functor_for_impl!($primitive => |self, _context| { self.to_string() }); + }; + } + pub(crate) use add_ignored_fields; + pub(crate) use encode_args; + pub(crate) use encode_functor; + pub(crate) use encode_functor_impl; + pub(crate) use impl_functor_for; + pub(crate) use impl_functor_for_impl; + } + + impl_functor_for!(primitive String); + impl_functor_for!(primitive u64); + + impl FunctorEncoded for HashMap { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { + std::format!("{{ {} }}", self.iter().map(|(k, v)| { + std::format!("{}: {}", k.encode_as_functor(context), v.encode_as_functor(context)) + }).sorted_by(|a,b| a.cmp(b)).join(", ")) + } + } + + impl FunctorEncoded for Vec { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { + std::format!("[{}]", self.iter().map(|v| v.encode_as_functor(context)).join(", ")) + } + } + + impl FunctorEncoded for Option { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { + self.as_ref().map(|inner| inner.encode_as_functor(context)).unwrap_or("".to_owned()) + } + } + + use typedb_driver::analyze::{AnalyzedQuery, conjunction::{Constraint, Conjunction, ConjunctionID, ConstraintVertex, Reducer, Variable}, FunctionStructure, pipeline::{PipelineStructure, PipelineStage, SortVariable, SortOrder, ReduceAssign}, ReturnOperation}; + use typedb_driver::analyze::annotations::{FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, PipelineAnnotations, VariableAnnotations}; + use typedb_driver::analyze::conjunction::{Comparator, ConstraintExactness, NamedRole}; + use typedb_driver::concept::type_::Type; + use typedb_driver::concept::{Value, ValueType}; + use functor_macros::encode_functor_impl; + use crate::analyze::functor_encoding::functor_macros::{impl_functor_for, impl_functor_for_impl}; + + impl_functor_for!(struct ReduceAssign { assigned, reducer, } named ReduceAssign); + impl_functor_for!(struct Reducer { reducer, arguments, } named Reducer); + impl_functor_for!(enum PipelineStage [ + Match { block, } | + Insert { block, } | + Delete { deleted_variables, block, } | + Put { block, } | + Update { block, } | + Select { variables, } | + Sort { variables, } | + Offset { offset, } | + Limit { limit, } | + Require { variables, } | + Distinct { } | + Reduce { reducers, groupby, } | // TODO + ]); + + macro_rules! encode_functor_impl_exactness { + ($context:ident, $exactness:ident, $variant:ident $exactVariant:ident $fields:tt ) => { + match $exactness { + ConstraintExactness::Exact => encode_functor_impl!($context, $exactVariant $fields), + ConstraintExactness::Subtypes => encode_functor_impl!($context, $variant $fields), + } + }; + } + impl FunctorEncoded for Constraint { + fn encode_as_functor<'a>(self: &Self, context: &FunctorContext<'a>) -> String { + match self { + Self::Isa { instance, r#type, exactness } => { + encode_functor_impl_exactness!(context, exactness, Isa IsaExact { instance, r#type, }) + } + Self::Has { owner, attribute, exactness } => { + encode_functor_impl_exactness!(context, exactness, Has HasExact { owner, attribute, }) + } + Self::Links { relation, player, role, exactness } => { + encode_functor_impl_exactness!(context, exactness, Links LinksExact { relation, player, role, } ) + } + Self::Sub { subtype, supertype, exactness } => { + encode_functor_impl_exactness!(context, exactness, Sub SubExact { subtype, supertype, } ) + } + Self::Owns { owner, attribute, exactness } => { + encode_functor_impl_exactness!(context, exactness, Owns OwnsExact { owner, attribute, } ) + } + Self::Relates { relation, role, exactness } => { + encode_functor_impl_exactness!(context, exactness, Relates RelatesExact { relation, role, } ) + } + Self::Plays { player, role, exactness } => { + encode_functor_impl_exactness!(context, exactness, Plays PlaysExact { player, role, } ) + } + Self::FunctionCall { name, assigned, arguments, } => { + encode_functor_impl!(context, FunctionCall { name, assigned, arguments, }) + } + Self::Expression { text, assigned, arguments, } => { + encode_functor_impl!(context, Expression { text, assigned, arguments, }) + } + Self::Is { lhs, rhs, } => { + encode_functor_impl!(context, Is { lhs, rhs, }) + } + Self::Iid { concept, iid, } => { + let iid_str = format!("0x{}", iid.iter().map(|x| format!("{:02X}", x)).join("")); + let iid_ref = &iid_str; + encode_functor_impl!(context, Iid { concept, iid_ref, }) + } + Self::Comparison { lhs, rhs, comparator, } => { + encode_functor_impl!(context, Comparison { lhs, rhs, comparator, }) + } + Self::Kind { kind, r#type, } => { + let kind_str = kind.name().to_owned(); + let kind_ref = &kind_str; + encode_functor_impl!(context, Kind { kind_ref, r#type, }) + } + Self::Label { r#type, label, } => { + encode_functor_impl!(context, Label { r#type, label, }) + } + Self::Value { attribute_type, value_type, } => { + let value_type_sr = value_type.name().to_owned(); + let value_type_ref = &value_type_sr; + encode_functor_impl!(context, Value { attribute_type, value_type_ref, }) + } + Self::Or { branches, } => { + encode_functor_impl!(context, Or { branches, }) + } + Self::Not { conjunction, } => { + encode_functor_impl!(context, Not { conjunction, }) + } + Self::Try { conjunction, } => { + encode_functor_impl!(context, Try { conjunction, }) + } + } + } + } + + impl_functor_for_impl!(ConstraintVertex => |self, context| { + match self { + ConstraintVertex::Variable(id) => { id.encode_as_functor(context) } + ConstraintVertex::Label(type_) => { type_.encode_as_functor(context) } + ConstraintVertex::Unresolved(label) => { label.encode_as_functor(context) } + ConstraintVertex::NamedRole(NamedRole { name,.. }) => { name.encode_as_functor(context) } + ConstraintVertex::Value(v) => { + match v { + Value::String(s) => std::format!("\"{}\"", s.to_string()), + other => other.to_string(), + } + } + } + }); + // + macro_rules! impl_functor_for_multi { + (|$self:ident, $context:ident| [ $( $type_name:ident => $block:block )* ]) => { + $ (impl_functor_for_impl!($type_name => |$self, $context| $block); )* + }; + } + impl_functor_for_multi!(|self, context| [ + Variable => { format!("${}", context.structure.variable_names.get(self).as_ref().map(|v| v.as_str()).unwrap_or("_")) } + Type => { self.label().to_owned().encode_as_functor(context) } + Comparator => { format!("{}", self.symbol()) } + ConjunctionID => { context.structure.conjunctions[self.0].encode_as_functor(context) } + Conjunction => { let Conjunction { constraints } = self; constraints.encode_as_functor(context) } + PipelineStructure => { let pipeline = &self.stages; encode_functor_impl!(context, Pipeline { pipeline, }) } + FunctionStructure => { + let FunctionStructure { arguments, returns, body } = self; + encode_functor_impl!(context, Function { arguments, returns, body, }) + } + ValueType => { + match self { + ValueType::Struct(name) => encode_functor_impl!(context, Struct { name, }), + other => other.name().to_owned().encode_as_functor(context), + } + } + SortVariable => { + let Self { order, variable } = self; + match order { + SortOrder::Ascending => encode_functor_impl!(context, Asc { variable, }), + SortOrder::Descending => encode_functor_impl!(context, Desc { variable, }), + } + } + ]); + // + impl_functor_for!(enum ReturnOperation [ + Stream { variables, } | + Single { selector, variables, } | + Check { } | + Reduce {} | + ]); + + pub fn encode_query_structure_as_functor(analyzed: &AnalyzedQuery) -> (String, Vec) { + let context = FunctorContext { structure: &analyzed.structure.query, annotations: &analyzed.annotations.query }; + let query = analyzed.structure.query.encode_as_functor(&context); + let preamble = analyzed.structure.preamble.iter().zip(analyzed.annotations.preamble.iter()).map(|(func, anno)| { + let context = FunctorContext { structure: &func.body, annotations: &anno.body }; + func.encode_as_functor(&context) + }).collect(); + (query, preamble) + } + + // annotations + + pub fn encode_query_annotations_as_functor(analyzed: &AnalyzedQuery) -> (String, Vec) { + let context = FunctorContext { structure: &analyzed.structure.query, annotations: &analyzed.annotations.query }; + let query = analyzed.annotations.query.encode_as_functor(&context); + let preamble = analyzed.annotations.preamble.iter().zip(analyzed.structure.preamble.iter()) + .map(|(annotations, structure)| { + let context = FunctorContext { structure: &structure.body, annotations: &annotations.body }; + annotations.encode_as_functor(&context) + }).collect(); + (query, preamble) + } + + impl FunctorEncoded for PipelineAnnotations { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { + let encoded_stages = context.structure.stages.iter().map(|stage| { + match stage { + PipelineStage::Match { block } => { + let block = &BlockAnnotationToEncode(block.0); + encode_functor_impl!(context, Match { block, }) + }, + PipelineStage::Insert { block } => { + let block = &BlockAnnotationToEncode(block.0); + encode_functor_impl!(context, Insert { block, }) + } + PipelineStage::Delete { block, .. } => { + let block = &BlockAnnotationToEncode(block.0); + encode_functor_impl!(context, Delete { block, }) + } + PipelineStage::Put { block } => { + let block = &BlockAnnotationToEncode(block.0); + encode_functor_impl!(context, Put { block, }) + }, + PipelineStage::Update { block } => { + let block = &BlockAnnotationToEncode(block.0); + encode_functor_impl!(context, Update { block, }) + } + PipelineStage::Select { .. } => encode_functor_impl!(context, Select { }), + PipelineStage::Sort { .. } => encode_functor_impl!(context, Sort { }), + PipelineStage::Offset { .. } => encode_functor_impl!(context, Offset { }), + PipelineStage::Limit { .. } => encode_functor_impl!(context, Limit { }), + PipelineStage::Require { .. } => encode_functor_impl!(context, Require { }), + PipelineStage::Distinct => encode_functor_impl!(context, Select { }), + PipelineStage::Reduce { .. } => encode_functor_impl!(context, Reduce { }), + } + }).collect::>(); + let encoded_stages_ref = &encoded_stages; + encode_functor_impl!(context, Pipeline { encoded_stages_ref, })// Not ideal to encode the elements again + } + } + + impl_functor_for!(struct FunctionAnnotations { arguments, returns, body, } named Function); + impl_functor_for!(enum FunctionReturnAnnotations [ Single(annotations,) | Stream(annotations,) | ]); + + #[derive(Debug, Clone, Copy)] + struct TrunkAnnotationToEncode(usize); + + #[derive(Debug, Clone, Copy)] + struct BlockAnnotationToEncode(usize); + impl From for BlockAnnotationToEncode { + fn from(value: ConjunctionID) -> Self { + Self(value.0) + } + } + + enum SubBlockAnnotation { + Trunk { conjunction: TrunkAnnotationToEncode }, + Or { branches: Vec }, + Not { conjunction: BlockAnnotationToEncode }, + Try { conjunction: BlockAnnotationToEncode }, + } + + impl FunctorEncoded for BlockAnnotationToEncode { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { + let mut elements = vec![SubBlockAnnotation::Trunk { conjunction: TrunkAnnotationToEncode(self.0) }]; + elements.extend(context.structure.conjunctions[self.0].constraints.iter() + .filter_map(|c| match c { + Constraint::Or { branches } => { + let branches = branches.iter().copied().map_into().collect(); + Some(SubBlockAnnotation::Or { branches }) + }, + Constraint::Not { conjunction } => { + Some(SubBlockAnnotation::Not { conjunction: (*conjunction).into() }) + }, + Constraint::Try { conjunction } => { + Some(SubBlockAnnotation::Try { conjunction: (*conjunction).into() }) + }, + _ => None, + })); + elements.encode_as_functor(context) + } + } + + impl_functor_for!(enum SubBlockAnnotation [ Trunk { conjunction, } | Or { branches, } | Not { conjunction, } | Try { conjunction, } | ]); + impl_functor_for!(enum VariableAnnotations [ Thing (annotations,) | Type (annotations,) | Value (value_types,) | ]); + impl_functor_for_multi!(|self, context| [ + TrunkAnnotationToEncode => { + context.annotations.conjunction_annotations[self.0].variable_annotations.encode_as_functor(context) + } + ]); + + // Fetch + pub fn encode_fetch_annotations_as_functor(analyzed: &AnalyzedQuery) -> String { + let context = FunctorContext { + structure: &analyzed.structure.query, + annotations: &analyzed.annotations.query + }; + analyzed.annotations.fetch.encode_as_functor(&context) + } + + impl FunctorEncoded for FetchAnnotations { + fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { + match self { + FetchAnnotations::Leaf(value_types) => { + value_types.encode_as_functor(context) + } + FetchAnnotations::Object(possible_fields) => { + possible_fields.encode_as_functor(context) + } + FetchAnnotations::List(elements) => { + let elements_as_ref = elements.as_ref(); + encode_functor_impl!(context, List { elements_as_ref, }) + } + } + } + } +} + diff --git a/rust/tests/behaviour/steps/lib.rs b/rust/tests/behaviour/steps/lib.rs index 55998e29a..e06357659 100644 --- a/rust/tests/behaviour/steps/lib.rs +++ b/rust/tests/behaviour/steps/lib.rs @@ -37,6 +37,7 @@ use futures::{ use itertools::Itertools; use tokio::time::{sleep, Duration}; use typedb_driver::{ + analyze::AnalyzedQuery, answer::{ConceptDocument, ConceptRow, QueryAnswer, QueryType}, BoxStream, Credentials, DriverOptions, QueryOptions, Result as TypeDBResult, Transaction, TransactionOptions, TypeDBDriver, @@ -47,6 +48,7 @@ use crate::{ util::{create_temp_dir, TempDir}, }; +mod analyze; mod connection; mod params; mod query; @@ -530,7 +532,6 @@ macro_rules! in_background { }; } pub(crate) use in_background; -use typedb_driver::analyze::AnalyzedQuery; // Most of the drivers are error-driven, while the Rust driver returns Option::None in many cases instead. // These "fake" errors allow us to emulate error messages for generalised driver BDDs, diff --git a/rust/tests/behaviour/steps/query.rs b/rust/tests/behaviour/steps/query.rs index 56f060cf6..0de69f83c 100644 --- a/rust/tests/behaviour/steps/query.rs +++ b/rust/tests/behaviour/steps/query.rs @@ -35,10 +35,9 @@ use crate::{ assert_err, generic_step, params, params::check_boolean, util, - util::{functor_encoding::encode_query_structure_as_functor, iter_table, list_contains_json, parse_json}, + util::{iter_table, list_contains_json, parse_json}, BehaviourTestOptionalError, Context, }; -use crate::util::functor_encoding::{encode_fetch_annotations_as_functor, encode_query_annotations_as_functor}; pub(crate) async fn run_query( transaction: &Transaction, @@ -51,13 +50,6 @@ pub(crate) async fn run_query( } } -pub(crate) async fn run_analyze_query( - transaction: &Transaction, - query: impl AsRef, -) -> TypeDBResult { - transaction.analyze_query(query).await -} - fn get_collected_column_names(concept_row: &ConceptRow) -> Vec { concept_row.get_column_names().into_iter().cloned().collect() } @@ -990,90 +982,3 @@ pub async fn answer_contains_document( &format!("Concept documents: {:?}", concept_documents), ); } - -#[apply(generic_step)] -#[step(expr = r"get answers of typeql analyze query")] -pub async fn get_answers_of_typeql_analyze_query(context: &mut Context, step: &Step) { - context.cleanup_answers().await; - context.set_analyzed(run_analyze_query(context.transaction(), step.docstring().unwrap()).await).unwrap(); -} - -#[apply(generic_step)] -#[step(expr = r"typeql analyze query{may_error}")] -async fn typeql_analyze_query_may_error(context: &mut Context, may_error: params::MayError, step: &Step) { - context.cleanup_answers().await; - let result = run_analyze_query(context.transaction(), step.docstring().unwrap()).await; - may_error.check(result); -} - -#[apply(generic_step)] -#[step(expr = r"analyzed query pipeline structure is:")] -pub async fn analyzed_query_pipeline_structure_is(context: &mut Context, step: &Step) { - let expected_functor = step.docstring().unwrap(); - let analyzed = context.get_analyzed().unwrap(); - let (actual_functor, _preamble) = encode_query_structure_as_functor(&analyzed); - assert_eq!(normalize_functor_for_compare(&actual_functor), normalize_functor_for_compare(expected_functor)); -} - -#[apply(generic_step)] -#[step(expr = r"analyzed query preamble contains:")] -async fn analyzed_query_preamble_contains(context: &mut Context, step: &Step) { - let expected_functor = step.docstring().unwrap(); - let analyzed = context.get_analyzed().unwrap(); - let (_pipeline, preamble_functors) = encode_query_structure_as_functor(&analyzed); - - assert!( - preamble_functors.iter().any(|actual_functor| { - normalize_functor_for_compare(actual_functor) == normalize_functor_for_compare(expected_functor) - }), - "Looking for\n\t{}\nin any of:\n\t{}", - normalize_functor_for_compare(expected_functor), - preamble_functors.iter().map(|s| normalize_functor_for_compare(s)).join("\n\t") - ); -} - -#[apply(generic_step)] -#[step(expr = r"analyzed query pipeline annotations are:")] -async fn analyzed_query_annotations_is(context: &mut Context, step: &Step) { - let expected_functor = step.docstring().unwrap(); - let analyzed = context.get_analyzed().unwrap(); - let (actual_functor, _preamble) = encode_query_annotations_as_functor(&analyzed); - assert_eq!(normalize_functor_for_compare(&actual_functor), normalize_functor_for_compare(expected_functor)); -} - -#[apply(generic_step)] -#[step(expr = r"analyzed preamble annotations contains:")] -async fn analyzed_preamble_annotations_contains(context: &mut Context, step: &Step) { - let expected_functor = step.docstring().unwrap(); - let analyzed = context.get_analyzed().unwrap(); - let (_pipeline, preamble_functors) = encode_query_annotations_as_functor(&analyzed); - - assert!( - preamble_functors.iter().any(|actual_functor| { - normalize_functor_for_compare(actual_functor) == normalize_functor_for_compare(expected_functor) - }), - "Looking for\n\t{}\nin any of:\n\t{}", - normalize_functor_for_compare(expected_functor), - preamble_functors.iter().map(|s| normalize_functor_for_compare(s)).join("\n\t") - ); -} - -#[apply(generic_step)] -#[step(expr = r"analyzed fetch annotations are:")] -async fn analyzed_fetch_annotations_are(context: &mut Context, step: &Step) { - let expected_functor = step.docstring().unwrap(); - let analyzed = context.get_analyzed().unwrap(); - let actual_functor = encode_fetch_annotations_as_functor(&analyzed); - - assert_eq!( - normalize_functor_for_compare(&actual_functor), - normalize_functor_for_compare(expected_functor) - ); -} - - -fn normalize_functor_for_compare(functor: &String) -> String { - let mut normalized = functor.to_lowercase(); - normalized.retain(|c| !c.is_whitespace()); - normalized -} diff --git a/rust/tests/behaviour/steps/util.rs b/rust/tests/behaviour/steps/util.rs index 661d0b7cc..84ae730ae 100644 --- a/rust/tests/behaviour/steps/util.rs +++ b/rust/tests/behaviour/steps/util.rs @@ -223,409 +223,3 @@ async fn file_write(context: &mut Context, file_name: String, step: &Step) { let path = context.get_full_file_path(&file_name); write_file(path, data.as_bytes()); } - - -#[cfg(debug_assertions)] -pub mod functor_encoding { - use std::collections::HashMap; - use itertools::Itertools; - - struct FunctorContext<'a> { - structure: &'a PipelineStructure, - annotations: &'a PipelineAnnotations, - } - - pub trait FunctorEncoded { - fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String; - } - - pub mod functor_macros { - macro_rules! encode_args { - ($context:ident, { $( $arg:ident, )* } ) => { - { - let arr: Vec<&dyn FunctorEncoded> = vec![ $($arg,)* ]; - arr.into_iter().map(|s| s.encode_as_functor($context)).join(", ") - } - }; - ($context:ident, ( $( $arg:ident, )* ) ) => { - functor_macros::encode_args!($context, { $( $arg, )* } ) - }; - } - macro_rules! encode_functor_impl { - ($context:ident, $func:ident $args:tt) => { - std::format!("{}({})", std::stringify!($func), functor_macros::encode_args!($context, $args)) - }; - } - - macro_rules! add_ignored_fields { - ($qualified:path : { $( $arg:ident, )* }) => { $qualified { $( $arg, )* .. } }; - ($qualified:path : ($( $arg:ident, )*)) => { $qualified ( $( $arg, )* .. ) }; - } - - macro_rules! encode_functor { - ($context:ident, $what:ident as struct $struct_name:ident $fields:tt) => { - functor_macros::encode_functor!($context, $what => [ $struct_name => $struct_name $fields, ]) - }; - ($context:ident, $what:ident as struct $struct_name:ident $fields:tt named $renamed:ident ) => { - functor_macros::encode_functor!($context, $what => [ $struct_name => $renamed $fields, ]) - }; - ($context:ident, $what:ident as enum $enum_name:ident [ $($variant:ident $fields:tt |)* ]) => { - functor_macros::encode_functor!($context, $what => [ $( $enum_name::$variant => $variant $fields ,)* ]) - }; - ($context:ident, $what:ident => [ $($qualified:path => $func:ident $fields:tt, )* ]) => { - match $what { - $( functor_macros::add_ignored_fields!($qualified : $fields) => { - functor_macros::encode_functor_impl!($context, $func $fields) - })* - } - }; - } - - macro_rules! impl_functor_for_impl { - ($which:ident => |$self:ident, $context:ident| $block:block) => { - impl FunctorEncoded for $which { - fn encode_as_functor<'a>($self: &Self, $context: &FunctorContext<'a>) -> String { - $block - } - } - }; - } - - macro_rules! impl_functor_for { - (struct $struct_name:ident $fields:tt) => { - functor_macros::impl_functor_for!(struct $struct_name $fields named $struct_name); - }; - (struct $struct_name:ident $fields:tt named $renamed:ident) => { - functor_macros::impl_functor_for_impl!($struct_name => |self, context| { - functor_macros::encode_functor!(context, self as struct $struct_name $fields named $renamed) - }); - }; - (enum $enum_name:ident [ $($func:ident $fields:tt |)* ]) => { - functor_macros::impl_functor_for_impl!($enum_name => |self, context| { - functor_macros::encode_functor!(context, self as enum $enum_name [ $($func $fields |)* ]) - }); - }; - (primitive $primitive:ident) => { - functor_macros::impl_functor_for_impl!($primitive => |self, _context| { self.to_string() }); - }; - } - pub(crate) use add_ignored_fields; - pub(crate) use encode_args; - pub(crate) use encode_functor; - pub(crate) use encode_functor_impl; - pub(crate) use impl_functor_for; - pub(crate) use impl_functor_for_impl; - } - - functor_macros::impl_functor_for!(primitive String); - functor_macros::impl_functor_for!(primitive u64); - - impl FunctorEncoded for HashMap { - fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { - std::format!("{{ {} }}", self.iter().map(|(k, v)| { - std::format!("{}: {}", k.encode_as_functor(context), v.encode_as_functor(context)) - }).sorted_by(|a,b| a.cmp(b)).join(", ")) - } - } - - impl FunctorEncoded for Vec { - fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { - std::format!("[{}]", self.iter().map(|v| v.encode_as_functor(context)).join(", ")) - } - } - - impl FunctorEncoded for Option { - fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { - self.as_ref().map(|inner| inner.encode_as_functor(context)).unwrap_or("".to_owned()) - } - } - - use typedb_driver::analyze::{AnalyzedQuery, conjunction::{Constraint, Conjunction, ConjunctionID, ConstraintVertex, Reducer, Variable}, FunctionStructure, pipeline::{PipelineStructure, PipelineStage, SortVariable, SortOrder, ReduceAssign}, QueryStructure, ReturnOperation}; - use typedb_driver::analyze::annotations::{FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, PipelineAnnotations, VariableAnnotations}; - use typedb_driver::analyze::conjunction::{Comparator, ConstraintExactness, NamedRole}; - use typedb_driver::concept::type_::Type; - use typedb_driver::concept::{Value, ValueType}; - use crate::util::functor_encoding::functor_macros::{encode_functor, encode_functor_impl}; - - functor_macros::impl_functor_for!(struct ReduceAssign { assigned, reducer, } named ReduceAssign); - functor_macros::impl_functor_for!(struct Reducer { reducer, arguments, } named Reducer); - functor_macros::impl_functor_for!(enum PipelineStage [ - Match { block, } | - Insert { block, } | - Delete { deleted_variables, block, } | - Put { block, } | - Update { block, } | - Select { variables, } | - Sort { variables, } | - Offset { offset, } | - Limit { limit, } | - Require { variables, } | - Distinct { } | - Reduce { reducers, groupby, } | // TODO - ]); - - macro_rules! encode_functor_impl_exactness { - ($context:ident, $exactness:ident, $variant:ident $exactVariant:ident $fields:tt ) => { - match $exactness { - ConstraintExactness::Exact => encode_functor_impl!($context, $exactVariant $fields), - ConstraintExactness::Subtypes => encode_functor_impl!($context, $variant $fields), - } - }; - } - impl FunctorEncoded for Constraint { - fn encode_as_functor<'a>(self: &Self, context: &FunctorContext<'a>) -> String { - match self { - Self::Isa { instance, r#type, exactness } => { - encode_functor_impl_exactness!(context, exactness, Isa IsaExact { instance, r#type, }) - } - Self::Has { owner, attribute, exactness } => { - encode_functor_impl_exactness!(context, exactness, Has HasExact { owner, attribute, }) - } - Self::Links { relation, player, role, exactness } => { - encode_functor_impl_exactness!(context, exactness, Links LinksExact { relation, player, role, } ) - } - Self::Sub { subtype, supertype, exactness } => { - encode_functor_impl_exactness!(context, exactness, Sub SubExact { subtype, supertype, } ) - } - Self::Owns { owner, attribute, exactness } => { - encode_functor_impl_exactness!(context, exactness, Owns OwnsExact { owner, attribute, } ) - } - Self::Relates { relation, role, exactness } => { - encode_functor_impl_exactness!(context, exactness, Relates RelatesExact { relation, role, } ) - } - Self::Plays { player, role, exactness } => { - encode_functor_impl_exactness!(context, exactness, Plays PlaysExact { player, role, } ) - } - Self::FunctionCall { name, assigned, arguments, } => { - encode_functor_impl!(context, FunctionCall { name, assigned, arguments, }) - } - Self::Expression { text, assigned, arguments, } => { - encode_functor_impl!(context, Expression { text, assigned, arguments, }) - } - Self::Is { lhs, rhs, } => { - encode_functor_impl!(context, Is { lhs, rhs, }) - } - Self::Iid { concept, iid, } => { - let iid_str = format!("0x{}", iid.iter().map(|x| format!("{:02X}", x)).join("")); - let iid_ref = &iid_str; - encode_functor_impl!(context, Iid { concept, iid_ref, }) - } - Self::Comparison { lhs, rhs, comparator, } => { - encode_functor_impl!(context, Comparison { lhs, rhs, comparator, }) - } - Self::Kind { kind, r#type, } => { - let kind_str = kind.name().to_owned(); - let kind_ref = &kind_str; - encode_functor_impl!(context, Kind { kind_ref, r#type, }) - } - Self::Label { r#type, label, } => { - encode_functor_impl!(context, Label { r#type, label, }) - } - Self::Value { attribute_type, value_type, } => { - let value_type_sr = value_type.name().to_owned(); - let value_type_ref = &value_type_sr; - encode_functor_impl!(context, Value { attribute_type, value_type_ref, }) - } - Self::Or { branches, } => { - encode_functor_impl!(context, Or { branches, }) - } - Self::Not { conjunction, } => { - encode_functor_impl!(context, Not { conjunction, }) - } - Self::Try { conjunction, } => { - encode_functor_impl!(context, Try { conjunction, }) - } - } - } - } - - functor_macros::impl_functor_for_impl!(ConstraintVertex => |self, context| { - match self { - ConstraintVertex::Variable(id) => { id.encode_as_functor(context) } - ConstraintVertex::Label(type_) => { type_.encode_as_functor(context) } - ConstraintVertex::Unresolved(label) => { label.encode_as_functor(context) } - ConstraintVertex::NamedRole(NamedRole { name,.. }) => { name.encode_as_functor(context) } - ConstraintVertex::Value(v) => { - match v { - Value::String(s) => std::format!("\"{}\"", s.to_string()), - other => other.to_string(), - } - } - } - }); - // - macro_rules! impl_functor_for_multi { - (|$self:ident, $context:ident| [ $( $type_name:ident => $block:block )* ]) => { - $ (functor_macros::impl_functor_for_impl!($type_name => |$self, $context| $block); )* - }; - } - impl_functor_for_multi!(|self, context| [ - Variable => { format!("${}", context.structure.variable_names.get(self).as_ref().map(|v| v.as_str()).unwrap_or("_")) } - Type => { self.label().to_owned().encode_as_functor(context) } - Comparator => { format!("{}", self.symbol()) } - ConjunctionID => { context.structure.conjunctions[self.0 as usize].encode_as_functor(context) } - Conjunction => { let Conjunction { constraints } = self; constraints.encode_as_functor(context) } - PipelineStructure => { let pipeline = &self.stages; functor_macros::encode_functor_impl!(context, Pipeline { pipeline, }) } - FunctionStructure => { - let FunctionStructure { arguments, returns, body } = self; - functor_macros::encode_functor_impl!(context, Function { arguments, returns, body, }) - } - ValueType => { - match self { - ValueType::Struct(name) => functor_macros::encode_functor_impl!(context, Struct { name, }), - other => other.name().to_owned().encode_as_functor(context), - } - } - SortVariable => { - let Self { order, variable } = self; - match order { - SortOrder::Ascending => functor_macros::encode_functor_impl!(context, Asc { variable, }), - SortOrder::Descending => functor_macros::encode_functor_impl!(context, Desc { variable, }), - } - } - ]); - // - functor_macros::impl_functor_for!(enum ReturnOperation [ - Stream { variables, } | - Single { selector, variables, } | - Check { } | - Reduce {} | - ]); - - pub fn encode_query_structure_as_functor(analyzed: &AnalyzedQuery) -> (String, Vec) { - let context = FunctorContext { structure: &analyzed.structure.query, annotations: &analyzed.annotations.query }; - let query = analyzed.structure.query.encode_as_functor(&context); - let preamble = analyzed.structure.preamble.iter().zip(analyzed.annotations.preamble.iter()).map(|(func, anno)| { - let context = FunctorContext { structure: &func.body, annotations: &anno.body }; - func.encode_as_functor(&context) - }).collect(); - (query, preamble) - } - - // annotations - - pub fn encode_query_annotations_as_functor(analyzed: &AnalyzedQuery) -> (String, Vec) { - let context = FunctorContext { structure: &analyzed.structure.query, annotations: &analyzed.annotations.query }; - let query = analyzed.annotations.query.encode_as_functor(&context); - let preamble = analyzed.annotations.preamble.iter().zip(analyzed.structure.preamble.iter()) - .map(|(annotations, structure)| { - let context = FunctorContext { structure: &structure.body, annotations: &annotations.body }; - annotations.encode_as_functor(&context) - }).collect(); - (query, preamble) - } - - impl FunctorEncoded for PipelineAnnotations { - fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { - let encoded_stages = context.structure.stages.iter().map(|stage| { - match stage { - PipelineStage::Match { block } => { - let block = &BlockAnnotationToEncode(block.0); - functor_macros::encode_functor_impl!(context, Match { block, }) - }, - PipelineStage::Insert { block } => { - let block = &BlockAnnotationToEncode(block.0); - functor_macros::encode_functor_impl!(context, Insert { block, }) - } - PipelineStage::Delete { block, .. } => { - let block = &BlockAnnotationToEncode(block.0); - functor_macros::encode_functor_impl!(context, Delete { block, }) - } - PipelineStage::Put { block } => { - let block = &BlockAnnotationToEncode(block.0); - functor_macros::encode_functor_impl!(context, Put { block, }) - }, - PipelineStage::Update { block } => { - let block = &BlockAnnotationToEncode(block.0); - functor_macros::encode_functor_impl!(context, Update { block, }) - } - PipelineStage::Select { .. } => functor_macros::encode_functor_impl!(context, Select { }), - PipelineStage::Sort { .. } => functor_macros::encode_functor_impl!(context, Sort { }), - PipelineStage::Offset { .. } => functor_macros::encode_functor_impl!(context, Offset { }), - PipelineStage::Limit { .. } => functor_macros::encode_functor_impl!(context, Limit { }), - PipelineStage::Require { .. } => functor_macros::encode_functor_impl!(context, Require { }), - PipelineStage::Distinct => functor_macros::encode_functor_impl!(context, Select { }), - PipelineStage::Reduce { .. } => functor_macros::encode_functor_impl!(context, Reduce { }), - } - }).collect::>(); - let encoded_stages_ref = &encoded_stages; - encode_functor_impl!(context, Pipeline { encoded_stages_ref, })// Not ideal to encode the elements again - } - } - - functor_macros::impl_functor_for!(struct FunctionAnnotations { arguments, returns, body, } named Function); - functor_macros::impl_functor_for!(enum FunctionReturnAnnotations [ Single(annotations,) | Stream(annotations,) | ]); - - #[derive(Debug, Clone, Copy)] - struct TrunkAnnotationToEncode(usize); - - #[derive(Debug, Clone, Copy)] - struct BlockAnnotationToEncode(usize); - impl From for BlockAnnotationToEncode { - fn from(value: ConjunctionID) -> Self { - Self(value.0) - } - } - - enum SubBlockAnnotation { - Trunk { conjunction: TrunkAnnotationToEncode }, - Or { branches: Vec }, - Not { conjunction: BlockAnnotationToEncode }, - Try { conjunction: BlockAnnotationToEncode }, - } - - impl FunctorEncoded for BlockAnnotationToEncode { - fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { - let mut elements = vec![SubBlockAnnotation::Trunk { conjunction: TrunkAnnotationToEncode(self.0) }]; - elements.extend(context.structure.conjunctions[self.0].constraints.iter() - .filter_map(|c| match c { - Constraint::Or { branches } => { - let branches = branches.iter().copied().map_into().collect(); - Some(SubBlockAnnotation::Or { branches }) - }, - Constraint::Not { conjunction } => { - Some(SubBlockAnnotation::Not { conjunction: (*conjunction).into() }) - }, - Constraint::Try { conjunction } => { - Some(SubBlockAnnotation::Try { conjunction: (*conjunction).into() }) - }, - _ => None, - })); - elements.encode_as_functor(context) - } - } - - functor_macros::impl_functor_for!(enum SubBlockAnnotation [ Trunk { conjunction, } | Or { branches, } | Not { conjunction, } | Try { conjunction, } | ]); - functor_macros::impl_functor_for!(enum VariableAnnotations [ Thing (annotations,) | Type (annotations,) | Value (value_types,) | ]); - impl_functor_for_multi!(|self, context| [ - TrunkAnnotationToEncode => { - context.annotations.conjunction_annotations[self.0].variable_annotations.encode_as_functor(context) - } - ]); - - // Fetch - pub fn encode_fetch_annotations_as_functor(analyzed: &AnalyzedQuery) -> String { - let context = FunctorContext { - structure: &analyzed.structure.query, - annotations: &analyzed.annotations.query - }; - analyzed.annotations.fetch.encode_as_functor(&context) - } - - impl FunctorEncoded for FetchAnnotations { - fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { - match self { - FetchAnnotations::Leaf(value_types) => { - value_types.encode_as_functor(context) - } - FetchAnnotations::Object(possible_fields) => { - possible_fields.encode_as_functor(context) - } - FetchAnnotations::List(elements) => { - let elements_as_ref = elements.as_ref(); - encode_functor_impl!(context, List { elements_as_ref, }) - } - } - } - } -} From 2f005664ac92e72dc69934a36968c0bd61062745 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Mon, 6 Oct 2025 17:52:10 +0200 Subject: [PATCH 17/22] Small cleanup --- rust/src/transaction.rs | 3 +-- rust/tests/behaviour/steps/query.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust/src/transaction.rs b/rust/src/transaction.rs index 277a4d117..4443aaee1 100644 --- a/rust/src/transaction.rs +++ b/rust/src/transaction.rs @@ -93,8 +93,7 @@ impl Transaction { /// transaction.analyze_query(query) /// ``` pub fn analyze_query(&self, query: impl AsRef) -> impl Promise<'static, Result> { - let query = query.as_ref(); - self.transaction_stream.analyze(query) + self.transaction_stream.analyze(query.as_ref()) } /// Retrieves the transaction’s type (READ or WRITE). diff --git a/rust/tests/behaviour/steps/query.rs b/rust/tests/behaviour/steps/query.rs index 0de69f83c..5258cfd3b 100644 --- a/rust/tests/behaviour/steps/query.rs +++ b/rust/tests/behaviour/steps/query.rs @@ -24,7 +24,6 @@ use futures::{future::join_all, StreamExt, TryStreamExt}; use itertools::Itertools; use macro_rules_attribute::apply; use typedb_driver::{ - analyze::AnalyzedQuery, answer::{ConceptRow, QueryAnswer, JSON}, concept::{AttributeType, Concept, ConceptCategory, EntityType, RelationType, Value, ValueType}, error::ConceptError, From 66754fc4bf8410195ef2408f20e1788e1f8bfccd Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Mon, 6 Oct 2025 19:49:34 +0200 Subject: [PATCH 18/22] Small rearrangements --- rust/src/analyze/annotations.rs | 16 +- rust/src/analyze/mod.rs | 9 +- rust/src/connection/network/proto/analyze.rs | 4 +- rust/tests/behaviour/steps/analyze.rs | 186 ++++++++++--------- 4 files changed, 115 insertions(+), 100 deletions(-) diff --git a/rust/src/analyze/annotations.rs b/rust/src/analyze/annotations.rs index a065fafa7..6b0f49fc4 100644 --- a/rust/src/analyze/annotations.rs +++ b/rust/src/analyze/annotations.rs @@ -17,10 +17,7 @@ * under the License. */ -use std::{ - collections::{BTreeMap, HashMap}, - vec::Vec, -}; +use std::{collections::HashMap, vec::Vec}; use crate::{ analyze::conjunction::Variable, @@ -28,8 +25,10 @@ use crate::{ }; #[derive(Debug)] -pub struct PipelineAnnotations { - pub conjunction_annotations: Vec, +pub struct QueryAnnotations { + pub query: PipelineAnnotations, + pub preamble: Vec, + pub fetch: Option, } #[derive(Debug)] @@ -52,6 +51,11 @@ pub enum FetchAnnotations { Object(HashMap), } +#[derive(Debug)] +pub struct PipelineAnnotations { + pub conjunction_annotations: Vec, +} + #[derive(Debug)] pub struct ConjunctionAnnotations { pub variable_annotations: HashMap, diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs index 782043235..c36a4aed2 100644 --- a/rust/src/analyze/mod.rs +++ b/rust/src/analyze/mod.rs @@ -18,7 +18,7 @@ */ use crate::analyze::{ - annotations::{FetchAnnotations, FunctionAnnotations, PipelineAnnotations}, + annotations::QueryAnnotations, conjunction::{Reducer, Variable}, pipeline::PipelineStructure, }; @@ -55,10 +55,3 @@ pub enum ReturnOperation { Check {}, Reduce { reducers: Vec }, } - -#[derive(Debug)] -pub struct QueryAnnotations { - pub query: PipelineAnnotations, - pub preamble: Vec, - pub fetch: Option, -} diff --git a/rust/src/connection/network/proto/analyze.rs b/rust/src/connection/network/proto/analyze.rs index a868f667c..7e360583a 100644 --- a/rust/src/connection/network/proto/analyze.rs +++ b/rust/src/connection/network/proto/analyze.rs @@ -37,14 +37,14 @@ use crate::{ analyze::{ annotations::{ ConjunctionAnnotations, FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, - PipelineAnnotations, VariableAnnotations, + PipelineAnnotations, QueryAnnotations, VariableAnnotations, }, conjunction::{ Comparator, Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, NamedRole, Reducer, Variable, }, pipeline::{PipelineStage, PipelineStructure, ReduceAssign, SortOrder, SortVariable}, - AnalyzedQuery, FunctionStructure, QueryAnnotations, QueryStructure, ReturnOperation, + AnalyzedQuery, FunctionStructure, QueryStructure, ReturnOperation, }, common::Result, concept::{type_, Kind, Value, ValueType}, diff --git a/rust/tests/behaviour/steps/analyze.rs b/rust/tests/behaviour/steps/analyze.rs index 366451aac..dd583a7c3 100644 --- a/rust/tests/behaviour/steps/analyze.rs +++ b/rust/tests/behaviour/steps/analyze.rs @@ -20,10 +20,14 @@ use cucumber::gherkin::Step; use itertools::Itertools; use macro_rules_attribute::apply; -use typedb_driver::{analyze::AnalyzedQuery, Transaction, Result as TypeDBResult}; -use crate::{Context, params, generic_step}; -use crate::analyze::functor_encoding::{encode_fetch_annotations_as_functor, encode_query_annotations_as_functor, encode_query_structure_as_functor}; -// use functor_encoding::{encode_fetch_annotations_as_functor, encode_query_annotations_as_functor, encode_query_structure_as_functor}; +use typedb_driver::{analyze::AnalyzedQuery, Result as TypeDBResult, Transaction}; + +use crate::{ + analyze::functor_encoding::{ + encode_fetch_annotations_as_functor, encode_query_annotations_as_functor, encode_query_structure_as_functor, + }, + generic_step, params, Context, +}; pub(crate) async fn run_analyze_query( transaction: &Transaction, @@ -106,10 +110,7 @@ async fn analyzed_fetch_annotations_are(context: &mut Context, step: &Step) { let analyzed = context.get_analyzed().unwrap(); let actual_functor = encode_fetch_annotations_as_functor(&analyzed); - assert_eq!( - normalize_functor_for_compare(&actual_functor), - normalize_functor_for_compare(expected_functor) - ); + assert_eq!(normalize_functor_for_compare(&actual_functor), normalize_functor_for_compare(expected_functor)); } fn normalize_functor_for_compare(functor: &String) -> String { @@ -118,11 +119,10 @@ fn normalize_functor_for_compare(functor: &String) -> String { normalized } - - #[cfg(debug_assertions)] pub mod functor_encoding { use std::collections::HashMap; + use itertools::Itertools; struct FunctorContext<'a> { @@ -217,9 +217,15 @@ pub mod functor_encoding { impl FunctorEncoded for HashMap { fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { - std::format!("{{ {} }}", self.iter().map(|(k, v)| { - std::format!("{}: {}", k.encode_as_functor(context), v.encode_as_functor(context)) - }).sorted_by(|a,b| a.cmp(b)).join(", ")) + std::format!( + "{{ {} }}", + self.iter() + .map(|(k, v)| { + std::format!("{}: {}", k.encode_as_functor(context), v.encode_as_functor(context)) + }) + .sorted_by(|a, b| a.cmp(b)) + .join(", ") + ) } } @@ -235,12 +241,23 @@ pub mod functor_encoding { } } - use typedb_driver::analyze::{AnalyzedQuery, conjunction::{Constraint, Conjunction, ConjunctionID, ConstraintVertex, Reducer, Variable}, FunctionStructure, pipeline::{PipelineStructure, PipelineStage, SortVariable, SortOrder, ReduceAssign}, ReturnOperation}; - use typedb_driver::analyze::annotations::{FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, PipelineAnnotations, VariableAnnotations}; - use typedb_driver::analyze::conjunction::{Comparator, ConstraintExactness, NamedRole}; - use typedb_driver::concept::type_::Type; - use typedb_driver::concept::{Value, ValueType}; use functor_macros::encode_functor_impl; + use typedb_driver::{ + analyze::{ + annotations::{ + FetchAnnotations, FunctionAnnotations, FunctionReturnAnnotations, PipelineAnnotations, + VariableAnnotations, + }, + conjunction::{ + Comparator, Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, NamedRole, + Reducer, Variable, + }, + pipeline::{PipelineStage, PipelineStructure, ReduceAssign, SortOrder, SortVariable}, + AnalyzedQuery, FunctionStructure, ReturnOperation, + }, + concept::{type_::Type, Value, ValueType}, + }; + use crate::analyze::functor_encoding::functor_macros::{impl_functor_for, impl_functor_for_impl}; impl_functor_for!(struct ReduceAssign { assigned, reducer, } named ReduceAssign); @@ -257,7 +274,7 @@ pub mod functor_encoding { Limit { limit, } | Require { variables, } | Distinct { } | - Reduce { reducers, groupby, } | // TODO + Reduce { reducers, groupby, } | ]); macro_rules! encode_functor_impl_exactness { @@ -271,64 +288,64 @@ pub mod functor_encoding { impl FunctorEncoded for Constraint { fn encode_as_functor<'a>(self: &Self, context: &FunctorContext<'a>) -> String { match self { - Self::Isa { instance, r#type, exactness } => { + Self::Isa { instance, r#type, exactness } => { encode_functor_impl_exactness!(context, exactness, Isa IsaExact { instance, r#type, }) } - Self::Has { owner, attribute, exactness } => { + Self::Has { owner, attribute, exactness } => { encode_functor_impl_exactness!(context, exactness, Has HasExact { owner, attribute, }) } - Self::Links { relation, player, role, exactness } => { + Self::Links { relation, player, role, exactness } => { encode_functor_impl_exactness!(context, exactness, Links LinksExact { relation, player, role, } ) } - Self::Sub { subtype, supertype, exactness } => { + Self::Sub { subtype, supertype, exactness } => { encode_functor_impl_exactness!(context, exactness, Sub SubExact { subtype, supertype, } ) } - Self::Owns { owner, attribute, exactness } => { + Self::Owns { owner, attribute, exactness } => { encode_functor_impl_exactness!(context, exactness, Owns OwnsExact { owner, attribute, } ) } - Self::Relates { relation, role, exactness } => { + Self::Relates { relation, role, exactness } => { encode_functor_impl_exactness!(context, exactness, Relates RelatesExact { relation, role, } ) } - Self::Plays { player, role, exactness } => { + Self::Plays { player, role, exactness } => { encode_functor_impl_exactness!(context, exactness, Plays PlaysExact { player, role, } ) } - Self::FunctionCall { name, assigned, arguments, } => { + Self::FunctionCall { name, assigned, arguments } => { encode_functor_impl!(context, FunctionCall { name, assigned, arguments, }) } - Self::Expression { text, assigned, arguments, } => { + Self::Expression { text, assigned, arguments } => { encode_functor_impl!(context, Expression { text, assigned, arguments, }) } - Self::Is { lhs, rhs, } => { + Self::Is { lhs, rhs } => { encode_functor_impl!(context, Is { lhs, rhs, }) } - Self::Iid { concept, iid, } => { + Self::Iid { concept, iid } => { let iid_str = format!("0x{}", iid.iter().map(|x| format!("{:02X}", x)).join("")); let iid_ref = &iid_str; encode_functor_impl!(context, Iid { concept, iid_ref, }) } - Self::Comparison { lhs, rhs, comparator, } => { + Self::Comparison { lhs, rhs, comparator } => { encode_functor_impl!(context, Comparison { lhs, rhs, comparator, }) } - Self::Kind { kind, r#type, } => { + Self::Kind { kind, r#type } => { let kind_str = kind.name().to_owned(); let kind_ref = &kind_str; encode_functor_impl!(context, Kind { kind_ref, r#type, }) } - Self::Label { r#type, label, } => { + Self::Label { r#type, label } => { encode_functor_impl!(context, Label { r#type, label, }) } - Self::Value { attribute_type, value_type, } => { + Self::Value { attribute_type, value_type } => { let value_type_sr = value_type.name().to_owned(); let value_type_ref = &value_type_sr; encode_functor_impl!(context, Value { attribute_type, value_type_ref, }) } - Self::Or { branches, } => { + Self::Or { branches } => { encode_functor_impl!(context, Or { branches, }) } - Self::Not { conjunction, } => { + Self::Not { conjunction } => { encode_functor_impl!(context, Not { conjunction, }) } - Self::Try { conjunction, } => { + Self::Try { conjunction } => { encode_functor_impl!(context, Try { conjunction, }) } } @@ -391,10 +408,16 @@ pub mod functor_encoding { pub fn encode_query_structure_as_functor(analyzed: &AnalyzedQuery) -> (String, Vec) { let context = FunctorContext { structure: &analyzed.structure.query, annotations: &analyzed.annotations.query }; let query = analyzed.structure.query.encode_as_functor(&context); - let preamble = analyzed.structure.preamble.iter().zip(analyzed.annotations.preamble.iter()).map(|(func, anno)| { - let context = FunctorContext { structure: &func.body, annotations: &anno.body }; - func.encode_as_functor(&context) - }).collect(); + let preamble = analyzed + .structure + .preamble + .iter() + .zip(analyzed.annotations.preamble.iter()) + .map(|(func, anno)| { + let context = FunctorContext { structure: &func.body, annotations: &anno.body }; + func.encode_as_functor(&context) + }) + .collect(); (query, preamble) } @@ -403,22 +426,30 @@ pub mod functor_encoding { pub fn encode_query_annotations_as_functor(analyzed: &AnalyzedQuery) -> (String, Vec) { let context = FunctorContext { structure: &analyzed.structure.query, annotations: &analyzed.annotations.query }; let query = analyzed.annotations.query.encode_as_functor(&context); - let preamble = analyzed.annotations.preamble.iter().zip(analyzed.structure.preamble.iter()) + let preamble = analyzed + .annotations + .preamble + .iter() + .zip(analyzed.structure.preamble.iter()) .map(|(annotations, structure)| { let context = FunctorContext { structure: &structure.body, annotations: &annotations.body }; annotations.encode_as_functor(&context) - }).collect(); + }) + .collect(); (query, preamble) } impl FunctorEncoded for PipelineAnnotations { fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { - let encoded_stages = context.structure.stages.iter().map(|stage| { - match stage { + let encoded_stages = context + .structure + .stages + .iter() + .map(|stage| match stage { PipelineStage::Match { block } => { let block = &BlockAnnotationToEncode(block.0); encode_functor_impl!(context, Match { block, }) - }, + } PipelineStage::Insert { block } => { let block = &BlockAnnotationToEncode(block.0); encode_functor_impl!(context, Insert { block, }) @@ -427,25 +458,25 @@ pub mod functor_encoding { let block = &BlockAnnotationToEncode(block.0); encode_functor_impl!(context, Delete { block, }) } - PipelineStage::Put { block } => { + PipelineStage::Put { block } => { let block = &BlockAnnotationToEncode(block.0); encode_functor_impl!(context, Put { block, }) - }, - PipelineStage::Update { block } => { + } + PipelineStage::Update { block } => { let block = &BlockAnnotationToEncode(block.0); encode_functor_impl!(context, Update { block, }) } - PipelineStage::Select { .. } => encode_functor_impl!(context, Select { }), - PipelineStage::Sort { .. } => encode_functor_impl!(context, Sort { }), - PipelineStage::Offset { .. } => encode_functor_impl!(context, Offset { }), - PipelineStage::Limit { .. } => encode_functor_impl!(context, Limit { }), - PipelineStage::Require { .. } => encode_functor_impl!(context, Require { }), - PipelineStage::Distinct => encode_functor_impl!(context, Select { }), - PipelineStage::Reduce { .. } => encode_functor_impl!(context, Reduce { }), - } - }).collect::>(); + PipelineStage::Select { .. } => encode_functor_impl!(context, Select {}), + PipelineStage::Sort { .. } => encode_functor_impl!(context, Sort {}), + PipelineStage::Offset { .. } => encode_functor_impl!(context, Offset {}), + PipelineStage::Limit { .. } => encode_functor_impl!(context, Limit {}), + PipelineStage::Require { .. } => encode_functor_impl!(context, Require {}), + PipelineStage::Distinct => encode_functor_impl!(context, Select {}), + PipelineStage::Reduce { .. } => encode_functor_impl!(context, Reduce {}), + }) + .collect::>(); let encoded_stages_ref = &encoded_stages; - encode_functor_impl!(context, Pipeline { encoded_stages_ref, })// Not ideal to encode the elements again + encode_functor_impl!(context, Pipeline { encoded_stages_ref, }) // Not ideal to encode the elements again } } @@ -473,20 +504,15 @@ pub mod functor_encoding { impl FunctorEncoded for BlockAnnotationToEncode { fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { let mut elements = vec![SubBlockAnnotation::Trunk { conjunction: TrunkAnnotationToEncode(self.0) }]; - elements.extend(context.structure.conjunctions[self.0].constraints.iter() - .filter_map(|c| match c { - Constraint::Or { branches } => { - let branches = branches.iter().copied().map_into().collect(); - Some(SubBlockAnnotation::Or { branches }) - }, - Constraint::Not { conjunction } => { - Some(SubBlockAnnotation::Not { conjunction: (*conjunction).into() }) - }, - Constraint::Try { conjunction } => { - Some(SubBlockAnnotation::Try { conjunction: (*conjunction).into() }) - }, - _ => None, - })); + elements.extend(context.structure.conjunctions[self.0].constraints.iter().filter_map(|c| match c { + Constraint::Or { branches } => { + let branches = branches.iter().copied().map_into().collect(); + Some(SubBlockAnnotation::Or { branches }) + } + Constraint::Not { conjunction } => Some(SubBlockAnnotation::Not { conjunction: (*conjunction).into() }), + Constraint::Try { conjunction } => Some(SubBlockAnnotation::Try { conjunction: (*conjunction).into() }), + _ => None, + })); elements.encode_as_functor(context) } } @@ -501,22 +527,15 @@ pub mod functor_encoding { // Fetch pub fn encode_fetch_annotations_as_functor(analyzed: &AnalyzedQuery) -> String { - let context = FunctorContext { - structure: &analyzed.structure.query, - annotations: &analyzed.annotations.query - }; + let context = FunctorContext { structure: &analyzed.structure.query, annotations: &analyzed.annotations.query }; analyzed.annotations.fetch.encode_as_functor(&context) } impl FunctorEncoded for FetchAnnotations { fn encode_as_functor<'a>(&self, context: &FunctorContext<'a>) -> String { match self { - FetchAnnotations::Leaf(value_types) => { - value_types.encode_as_functor(context) - } - FetchAnnotations::Object(possible_fields) => { - possible_fields.encode_as_functor(context) - } + FetchAnnotations::Leaf(value_types) => value_types.encode_as_functor(context), + FetchAnnotations::Object(possible_fields) => possible_fields.encode_as_functor(context), FetchAnnotations::List(elements) => { let elements_as_ref = elements.as_ref(); encode_functor_impl!(context, List { elements_as_ref, }) @@ -525,4 +544,3 @@ pub mod functor_encoding { } } } - From 931b2d299f1fcede16949e2ec6ab98a47d1215ab Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Mon, 6 Oct 2025 19:57:00 +0200 Subject: [PATCH 19/22] One more --- rust/src/analyze/conjunction.rs | 6 ------ rust/src/analyze/mod.rs | 4 ++-- rust/src/analyze/pipeline.rs | 8 +++++++- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rust/src/analyze/conjunction.rs b/rust/src/analyze/conjunction.rs index 492b3d818..d6735e24b 100644 --- a/rust/src/analyze/conjunction.rs +++ b/rust/src/analyze/conjunction.rs @@ -142,12 +142,6 @@ pub struct NamedRole { pub name: String, } -#[derive(Debug)] -pub struct Reducer { - pub arguments: Vec, - pub reducer: String, -} - #[derive(Debug)] pub enum Comparator { Equal, diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs index c36a4aed2..be32b5c5d 100644 --- a/rust/src/analyze/mod.rs +++ b/rust/src/analyze/mod.rs @@ -19,8 +19,8 @@ use crate::analyze::{ annotations::QueryAnnotations, - conjunction::{Reducer, Variable}, - pipeline::PipelineStructure, + conjunction::Variable, + pipeline::{PipelineStructure, Reducer}, }; pub mod annotations; diff --git a/rust/src/analyze/pipeline.rs b/rust/src/analyze/pipeline.rs index 0a989ec33..3fa417b5e 100644 --- a/rust/src/analyze/pipeline.rs +++ b/rust/src/analyze/pipeline.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; -use crate::analyze::conjunction::{Conjunction, ConjunctionID, Reducer, Variable}; +use crate::analyze::conjunction::{Conjunction, ConjunctionID, Variable}; #[derive(Debug)] pub struct PipelineStructure { @@ -51,6 +51,12 @@ pub struct ReduceAssign { pub reducer: Reducer, } +#[derive(Debug)] +pub struct Reducer { + pub arguments: Vec, + pub reducer: String, +} + #[derive(Debug)] pub struct SortVariable { pub variable: Variable, From 1328d5623d58a9d0f5e57d5470cbaeacfc891f80 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Mon, 6 Oct 2025 20:00:28 +0200 Subject: [PATCH 20/22] Fix build --- rust/src/analyze/mod.rs | 2 -- rust/src/connection/network/proto/analyze.rs | 4 ++-- rust/tests/behaviour/steps/analyze.rs | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/rust/src/analyze/mod.rs b/rust/src/analyze/mod.rs index be32b5c5d..9dae0b937 100644 --- a/rust/src/analyze/mod.rs +++ b/rust/src/analyze/mod.rs @@ -27,8 +27,6 @@ pub mod annotations; pub mod conjunction; pub mod pipeline; -pub type TryFromError = &'static str; - #[derive(Debug)] pub struct AnalyzedQuery { pub structure: QueryStructure, diff --git a/rust/src/connection/network/proto/analyze.rs b/rust/src/connection/network/proto/analyze.rs index 7e360583a..f0c6e1e61 100644 --- a/rust/src/connection/network/proto/analyze.rs +++ b/rust/src/connection/network/proto/analyze.rs @@ -41,9 +41,9 @@ use crate::{ }, conjunction::{ Comparator, Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, NamedRole, - Reducer, Variable, + Variable, }, - pipeline::{PipelineStage, PipelineStructure, ReduceAssign, SortOrder, SortVariable}, + pipeline::{PipelineStage, PipelineStructure, ReduceAssign, Reducer, SortOrder, SortVariable}, AnalyzedQuery, FunctionStructure, QueryStructure, ReturnOperation, }, common::Result, diff --git a/rust/tests/behaviour/steps/analyze.rs b/rust/tests/behaviour/steps/analyze.rs index dd583a7c3..6f80e1b10 100644 --- a/rust/tests/behaviour/steps/analyze.rs +++ b/rust/tests/behaviour/steps/analyze.rs @@ -250,9 +250,9 @@ pub mod functor_encoding { }, conjunction::{ Comparator, Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, NamedRole, - Reducer, Variable, + Variable, }, - pipeline::{PipelineStage, PipelineStructure, ReduceAssign, SortOrder, SortVariable}, + pipeline::{PipelineStage, PipelineStructure, Reducer, ReduceAssign, SortOrder, SortVariable}, AnalyzedQuery, FunctionStructure, ReturnOperation, }, concept::{type_::Type, Value, ValueType}, From fc9c98ce175458bf32c1c3c962f00ed50392e091 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Mon, 6 Oct 2025 20:04:30 +0200 Subject: [PATCH 21/22] Remove misplaced cleanup_answers in analyze steps --- rust/tests/behaviour/steps/analyze.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rust/tests/behaviour/steps/analyze.rs b/rust/tests/behaviour/steps/analyze.rs index 6f80e1b10..6d9940d73 100644 --- a/rust/tests/behaviour/steps/analyze.rs +++ b/rust/tests/behaviour/steps/analyze.rs @@ -39,14 +39,12 @@ pub(crate) async fn run_analyze_query( #[apply(generic_step)] #[step(expr = r"get answers of typeql analyze query")] pub async fn get_answers_of_typeql_analyze_query(context: &mut Context, step: &Step) { - context.cleanup_answers().await; context.set_analyzed(run_analyze_query(context.transaction(), step.docstring().unwrap()).await).unwrap(); } #[apply(generic_step)] #[step(expr = r"typeql analyze query{may_error}")] async fn typeql_analyze_query_may_error(context: &mut Context, may_error: params::MayError, step: &Step) { - context.cleanup_answers().await; let result = run_analyze_query(context.transaction(), step.docstring().unwrap()).await; may_error.check(result); } From 3705f447f8fea13bad9ca13bfa54b316e33ed402 Mon Sep 17 00:00:00 2001 From: Krishnan Govindraj Date: Mon, 6 Oct 2025 20:08:20 +0200 Subject: [PATCH 22/22] update url to myfork in typedb_protocol dependency --- dependencies/typedb/repositories.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index bf8d3e64e..2b332da70 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -27,7 +27,7 @@ def typedb_dependencies(): def typedb_protocol(): git_repository( name = "typedb_protocol", - remote = "https://github.com/typedb/typedb-protocol", + remote = "https://github.com/krishnangovindraj/typedb-protocol", commit = "bf987393f6eb1462846d6c62bf2ffe7ae4b6e90d", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol )