From 11c3a8de942a5586b7187c85a6c39271bbbb3e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Sun, 9 Feb 2025 19:14:54 +0100 Subject: [PATCH] Adapt to new trustfall model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- Cargo.lock | 941 +++++++++++++++++++++- crates/plaixt/Cargo.toml | 1 + crates/plaixt/src/adapter/adapter_impl.rs | 185 +++++ crates/plaixt/src/adapter/edges.rs | 85 ++ crates/plaixt/src/adapter/entrypoints.rs | 16 + crates/plaixt/src/adapter/mod.rs | 55 ++ crates/plaixt/src/adapter/properties.rs | 159 ++++ crates/plaixt/src/adapter/schema.graphql | 88 ++ crates/plaixt/src/adapter/tests.rs | 16 + crates/plaixt/src/adapter/vertex.rs | 15 + crates/plaixt/src/main.rs | 24 +- crates/plaixt/src/parsing.rs | 34 +- crates/plaixt/src/trustfall_plaixt.rs | 639 --------------- flake.nix | 59 +- 14 files changed, 1632 insertions(+), 685 deletions(-) create mode 100644 crates/plaixt/src/adapter/adapter_impl.rs create mode 100644 crates/plaixt/src/adapter/edges.rs create mode 100644 crates/plaixt/src/adapter/entrypoints.rs create mode 100644 crates/plaixt/src/adapter/mod.rs create mode 100644 crates/plaixt/src/adapter/properties.rs create mode 100644 crates/plaixt/src/adapter/schema.graphql create mode 100644 crates/plaixt/src/adapter/tests.rs create mode 100644 crates/plaixt/src/adapter/vertex.rs delete mode 100644 crates/plaixt/src/trustfall_plaixt.rs diff --git a/Cargo.lock b/Cargo.lock index c1ac24f..23b0445 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,7 +135,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -147,6 +147,12 @@ dependencies = [ "backtrace", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -183,6 +189,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + [[package]] name = "bytes" version = "1.10.0" @@ -262,6 +274,28 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -299,6 +333,19 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_more" +version = "0.99.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + [[package]] name = "digest" version = "0.10.7" @@ -309,12 +356,32 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -331,6 +398,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "filesystem-trustfall-adapter" version = "0.1.1" @@ -357,6 +430,30 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures" version = "0.3.31" @@ -465,7 +562,7 @@ dependencies = [ "cfg-if", "libc", "wasi 0.13.3+wasi-0.2.2", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -474,6 +571,25 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.15.2" @@ -492,6 +608,40 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "human-panic" version = "2.0.2" @@ -508,6 +658,182 @@ dependencies = [ "uuid", ] +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.7.1" @@ -519,6 +845,12 @@ dependencies = [ "serde", ] +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + [[package]] name = "is_ci" version = "1.2.0" @@ -575,6 +907,16 @@ dependencies = [ "jiff-tzdb", ] +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "kdl" version = "6.3.3" @@ -611,6 +953,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "lock_api" version = "0.4.12" @@ -680,6 +1028,12 @@ dependencies = [ "syn", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "miniz_oxide" version = "0.8.3" @@ -700,6 +1054,23 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "native-tls" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -826,6 +1197,50 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "openssl" +version = "0.10.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" +dependencies = [ + "bitflags 2.8.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_info" version = "3.9.2" @@ -849,6 +1264,21 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56" +[[package]] +name = "paperless-rs" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e929358cf0d9963f0ee77487fc1b45d4bbc20542e79b072bec05b4bd66e085f4" +dependencies = [ + "async-trait", + "base64 0.21.7", + "bytes", + "derive_more", + "reqwest", + "serde", + "tokio", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -869,9 +1299,15 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "pest" version = "2.7.15" @@ -914,6 +1350,7 @@ dependencies = [ "kdl", "miette", "owo-colors", + "paperless-rs", "tokio", "tokio-stream", "tracing", @@ -927,7 +1364,7 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ - "base64", + "base64 0.22.1", "indexmap", "quick-xml", "serde", @@ -1035,12 +1472,61 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -1054,6 +1540,21 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + [[package]] name = "ryu" version = "1.0.19" @@ -1069,12 +1570,50 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.8.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" + [[package]] name = "serde" version = "1.0.217" @@ -1116,6 +1655,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.10.8" @@ -1192,6 +1743,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.1" @@ -1230,6 +1787,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syntect" version = "5.2.0" @@ -1252,6 +1826,41 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +dependencies = [ + "cfg-if", + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "terminal_size" version = "0.4.1" @@ -1353,6 +1962,16 @@ dependencies = [ "time-core", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tokio" version = "1.43.0" @@ -1382,6 +2001,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.17" @@ -1440,6 +2069,12 @@ dependencies = [ "toml_datetime", ] +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.41" @@ -1540,6 +2175,12 @@ dependencies = [ "syn", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typenum" version = "1.17.0" @@ -1570,6 +2211,29 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -1591,6 +2255,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -1607,6 +2277,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1622,6 +2301,87 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1653,13 +2413,22 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1668,7 +2437,22 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1677,28 +2461,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "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_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1711,24 +2513,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -1744,6 +2570,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wit-bindgen-rt" version = "0.33.0" @@ -1753,6 +2589,18 @@ dependencies = [ "bitflags 2.8.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "yaml-rust" version = "0.4.5" @@ -1761,3 +2609,70 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/crates/plaixt/Cargo.toml b/crates/plaixt/Cargo.toml index 610df66..9dce34e 100644 --- a/crates/plaixt/Cargo.toml +++ b/crates/plaixt/Cargo.toml @@ -15,6 +15,7 @@ jiff = "0.1.28" kdl.workspace = true miette = { version = "7.4.0", features = ["fancy", "syntect-highlighter"] } owo-colors = "4.1.0" +paperless-rs = "0.1.5" tokio = { version = "1.43.0", features = ["full"] } tokio-stream = { version = "0.1.17", features = ["full"] } tracing = "0.1.41" diff --git a/crates/plaixt/src/adapter/adapter_impl.rs b/crates/plaixt/src/adapter/adapter_impl.rs new file mode 100644 index 0000000..dbfa146 --- /dev/null +++ b/crates/plaixt/src/adapter/adapter_impl.rs @@ -0,0 +1,185 @@ +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::sync::Arc; +use std::sync::OnceLock; + +use paperless_rs::PaperlessClient; +use trustfall::provider::resolve_coercion_using_schema; +use trustfall::provider::resolve_property_with; +use trustfall::provider::AsVertex; +use trustfall::provider::ContextIterator; +use trustfall::provider::ContextOutcomeIterator; +use trustfall::provider::EdgeParameters; +use trustfall::provider::ResolveEdgeInfo; +use trustfall::provider::ResolveInfo; +use trustfall::provider::Typename; +use trustfall::provider::VertexIterator; +use trustfall::FieldValue; +use trustfall::Schema; + +use super::vertex::Vertex; +use crate::parsing::DefinitionKind; +use crate::parsing::Record; + +static SCHEMA: OnceLock = OnceLock::new(); + +#[non_exhaustive] +pub struct Adapter { + schema: Arc, + records: Vec, + definitions: Arc>>, + paperless_client: Option, + runtime_handle: tokio::runtime::Handle, +} + +impl std::fmt::Debug for Adapter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Adapter").finish_non_exhaustive() + } +} + +impl Adapter { + pub fn new( + schema: Schema, + records: Vec, + definitions: BTreeMap>, + paperless_client: Option, + runtime: tokio::runtime::Handle, + ) -> Self { + Self { + schema: Arc::new(schema), + records, + definitions: Arc::new(definitions), + paperless_client, + runtime_handle: runtime, + } + } + + pub const SCHEMA_TEXT: &'static str = include_str!("./schema.graphql"); + + pub fn schema() -> &'static Schema { + SCHEMA.get_or_init(|| Schema::parse(Self::SCHEMA_TEXT).expect("not a valid schema")) + } +} + +impl<'a> trustfall::provider::Adapter<'a> for Adapter { + type Vertex = Vertex; + + fn resolve_starting_vertices( + &self, + edge_name: &Arc, + _parameters: &EdgeParameters, + resolve_info: &ResolveInfo, + ) -> VertexIterator<'a, Self::Vertex> { + match edge_name.as_ref() { + "Records" => super::entrypoints::records(resolve_info, &self.records), + _ => { + unreachable!( + "attempted to resolve starting vertices for unexpected edge name: {edge_name}" + ) + } + } + } + + fn resolve_property + 'a>( + &self, + contexts: ContextIterator<'a, V>, + type_name: &Arc, + property_name: &Arc, + resolve_info: &ResolveInfo, + ) -> ContextOutcomeIterator<'a, V, FieldValue> { + if property_name.as_ref() == "__typename" { + return resolve_property_with(contexts, |vertex| vertex.typename().into()); + } + match type_name.as_ref() { + "PaperlessDocument" => super::properties::resolve_paperless_document_property( + contexts, + property_name.as_ref(), + resolve_info, + ), + "Path" => super::properties::resolve_path_property( + contexts, + property_name.as_ref(), + resolve_info, + ), + "File" => super::properties::resolve_file_property( + contexts, + property_name.as_ref(), + resolve_info, + ), + "Directory" => super::properties::resolve_directory_property( + contexts, + property_name.as_ref(), + resolve_info, + ), + "Record" => { + super::properties::resolve_record_property(contexts, property_name, resolve_info) + } + kind if kind.starts_with("p_") => { + super::properties::resolve_record_property(contexts, property_name, resolve_info) + } + _ => { + unreachable!( + "attempted to read property '{property_name}' on unexpected type: {type_name}" + ) + } + } + } + + fn resolve_neighbors + 'a>( + &self, + contexts: ContextIterator<'a, V>, + type_name: &Arc, + edge_name: &Arc, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, V, VertexIterator<'a, Self::Vertex>> { + match type_name.as_ref() { + "Directory" => super::edges::resolve_directory_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ), + kind if kind.starts_with("p_") => super::edges::resolve_record_edge( + contexts, + edge_name, + parameters, + resolve_info, + &self.definitions, + ), + _ => { + unreachable!( + "attempted to resolve edge '{edge_name}' on unexpected type: {type_name}" + ) + } + } + } + + fn resolve_coercion + 'a>( + &self, + contexts: ContextIterator<'a, V>, + _type_name: &Arc, + coerce_to_type: &Arc, + _resolve_info: &ResolveInfo, + ) -> ContextOutcomeIterator<'a, V, bool> { + let schema = self.schema.clone(); + let coerce_to_type = coerce_to_type.clone(); + + Box::new(contexts.map(move |ctx| { + let subtypes: BTreeSet<_> = schema + .subtypes(coerce_to_type.as_ref()) + .unwrap_or_else(|| panic!("type {coerce_to_type} is not part of this schema")) + .collect(); + + match ctx.active_vertex::() { + None => (ctx, false), + Some(vertex) => { + let typename = vertex.typename(); + let can_coerce = subtypes.contains(typename); + (ctx, can_coerce) + } + } + })) + } +} diff --git a/crates/plaixt/src/adapter/edges.rs b/crates/plaixt/src/adapter/edges.rs new file mode 100644 index 0000000..54b841b --- /dev/null +++ b/crates/plaixt/src/adapter/edges.rs @@ -0,0 +1,85 @@ +use std::collections::BTreeMap; +use std::sync::Arc; + +use trustfall::provider::resolve_neighbors_with; +use trustfall::provider::AsVertex; +use trustfall::provider::ContextIterator; +use trustfall::provider::ContextOutcomeIterator; +use trustfall::provider::EdgeParameters; +use trustfall::provider::ResolveEdgeInfo; +use trustfall::provider::VertexIterator; + +use super::Vertex; +use crate::parsing::DefinitionKind; + +pub(super) fn resolve_directory_edge<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + edge_name: &str, + _parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, V, VertexIterator<'a, Vertex>> { + match edge_name { + "Children" => directory::children(contexts, resolve_info), + _ => unreachable!("attempted to resolve unexpected edge '{edge_name}' on type 'Directory'"), + } +} + +mod directory { + use camino::Utf8Path; + use trustfall::provider::resolve_neighbors_with; + use trustfall::provider::AsVertex; + use trustfall::provider::ContextIterator; + use trustfall::provider::ContextOutcomeIterator; + use trustfall::provider::ResolveEdgeInfo; + use trustfall::provider::VertexIterator; + + use crate::adapter::Vertex; + + pub(super) fn children<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, V, VertexIterator<'a, Vertex>> { + resolve_neighbors_with(contexts, move |vertex| { + let vertex = vertex + .as_directory() + .expect("conversion failed, vertex was not a Directory"); + + fn read_children(path: &Utf8Path) -> Option> { + Some( + path.read_dir_utf8() + .ok()? + .flat_map(|item| Some(Vertex::Path(item.ok()?.path().to_path_buf()))), + ) + } + + read_children(vertex) + .map(|i| { + let it: Box> = Box::new(i); + it + }) + .unwrap_or_else(|| Box::new(std::iter::empty())) + }) + } +} + +pub(super) fn resolve_record_edge<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + edge_name: &Arc, + _parameters: &EdgeParameters, + _resolve_info: &ResolveEdgeInfo, + definitions: &Arc>>, +) -> ContextOutcomeIterator<'a, V, VertexIterator<'a, Vertex>> { + let edge_name = edge_name.clone(); + let definitions = definitions.clone(); + resolve_neighbors_with(contexts, move |v| { + let rec = v.as_record().expect("Expected a record"); + let def = &definitions[&rec.kind][edge_name.as_ref()]; + + match def { + DefinitionKind::Path => Box::new(std::iter::once(Vertex::Path( + rec.fields[edge_name.as_ref()].as_string().unwrap().into(), + ))), + _ => unreachable!("Only `Path` can appear as edge for now"), + } + }) +} diff --git a/crates/plaixt/src/adapter/entrypoints.rs b/crates/plaixt/src/adapter/entrypoints.rs new file mode 100644 index 0000000..5ee05a5 --- /dev/null +++ b/crates/plaixt/src/adapter/entrypoints.rs @@ -0,0 +1,16 @@ +use trustfall::provider::ResolveInfo; +use trustfall::provider::VertexIterator; + +use super::vertex::Vertex; +use crate::parsing::Record; + +pub(super) fn records<'a>( + _resolve_info: &ResolveInfo, + records: &'_ [Record], +) -> VertexIterator<'a, Vertex> { + #[expect( + clippy::unnecessary_to_owned, + reason = "We have to go through a vec to satisfy the lifetimes" + )] + Box::new(records.to_vec().into_iter().map(Vertex::Record)) +} diff --git a/crates/plaixt/src/adapter/mod.rs b/crates/plaixt/src/adapter/mod.rs new file mode 100644 index 0000000..c2219c0 --- /dev/null +++ b/crates/plaixt/src/adapter/mod.rs @@ -0,0 +1,55 @@ +mod adapter_impl; +mod edges; +mod entrypoints; +mod properties; +mod vertex; + +#[cfg(test)] +mod tests; + +pub use adapter_impl::Adapter; +use tracing::trace; +use trustfall::Schema; +pub use vertex::Vertex; + +pub struct CustomVertex { + pub name: String, + pub definition: String, +} + +impl crate::parsing::Definition { + fn to_custom_vertices(&self) -> Vec { + let name = format!("p_{}", self.name); + + let fields = self + .fields + .iter() + .map(|(fname, ftype)| { + let kind = ftype.trustfall_kind(&format!("{name}{fname}")); + format!("{fname}: {kind}") + }) + .chain([String::from("_at: String!"), String::from("_kind: String!")]) + .collect::>(); + + let definition = format!("type {name} implements Record {{ {} }}", fields.join(",")); + + [CustomVertex { name, definition }].into_iter().collect() + } +} + +pub(crate) fn to_schema( + definitions: &std::collections::BTreeMap>, +) -> trustfall::Schema { + let base_text = Adapter::SCHEMA_TEXT; + + let generated = definitions + .values() + .flat_map(|defs| defs.last().unwrap().to_custom_vertices()) + .map(|v| v.definition) + .collect::>() + .join("\n"); + + let input = format!("{base_text}{generated}"); + trace!(%input, "Using schema"); + Schema::parse(input).unwrap() +} diff --git a/crates/plaixt/src/adapter/properties.rs b/crates/plaixt/src/adapter/properties.rs new file mode 100644 index 0000000..4f8d955 --- /dev/null +++ b/crates/plaixt/src/adapter/properties.rs @@ -0,0 +1,159 @@ +use std::collections::BTreeMap; +use std::sync::Arc; + +use kdl::KdlValue; +use paperless_rs::PaperlessClient; +use trustfall::provider::field_property; +use trustfall::provider::resolve_property_with; +use trustfall::provider::AsVertex; +use trustfall::provider::ContextIterator; +use trustfall::provider::ContextOutcomeIterator; +use trustfall::provider::ResolveInfo; +use trustfall::FieldValue; + +use super::vertex::Vertex; + +pub(super) fn resolve_path_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + match property_name { + "exists" => resolve_property_with(contexts, move |v: &Vertex| { + let path = v.as_path().expect("vertex was not a Path"); + + path.exists().into() + }), + "basename" => resolve_property_with(contexts, move |v: &Vertex| { + let path = v.as_path().expect("vertex was not a Path"); + + path.file_name().into() + }), + "path" => resolve_property_with(contexts, move |v: &Vertex| { + let path = v.as_path().expect("vertex was not a Path"); + + path.to_string().into() + }), + _ => { + unreachable!("attempted to read unexpected property '{property_name}' on type 'Path'") + } + } +} + +pub(super) fn resolve_directory_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + match property_name { + "exists" => resolve_property_with(contexts, move |v: &Vertex| { + let directory = v.as_directory().expect("vertex was not a Directory"); + + directory.exists().into() + }), + "basename" => resolve_property_with(contexts, move |v: &Vertex| { + let directory = v.as_directory().expect("vertex was not a Directory"); + + directory.file_name().into() + }), + "path" => resolve_property_with(contexts, move |v: &Vertex| { + let directory = v.as_directory().expect("vertex was not a Directory"); + + directory.to_string().into() + }), + _ => { + unreachable!("attempted to read unexpected property '{property_name}' on type 'File'") + } + } +} + +pub(super) fn resolve_file_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + match property_name { + "exists" => resolve_property_with(contexts, move |v: &Vertex| { + let file = v.as_file().expect("vertex was not a File"); + + file.exists().into() + }), + "basename" => resolve_property_with(contexts, move |v: &Vertex| { + let file = v.as_file().expect("vertex was not a File"); + + file.file_name().into() + }), + "path" => resolve_property_with(contexts, move |v: &Vertex| { + let file = v.as_file().expect("vertex was not a File"); + + file.to_string().into() + }), + "extension" => resolve_property_with(contexts, move |v: &Vertex| { + let file = v.as_file().expect("vertex was not a File"); + + file.extension().into() + }), + _ => { + unreachable!("attempted to read unexpected property '{property_name}' on type 'File'") + } + } +} + +pub(super) fn resolve_paperless_document_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + match property_name { + "added" => resolve_property_with(contexts, field_property!(as_paperless_document, added)), + "archive_serial_number" => resolve_property_with( + contexts, + field_property!(as_paperless_document, archive_serial_number), + ), + "content" => { + resolve_property_with(contexts, field_property!(as_paperless_document, content)) + } + "created" => { + resolve_property_with(contexts, field_property!(as_paperless_document, created)) + } + "id" => resolve_property_with(contexts, field_property!(as_paperless_document, id)), + "title" => resolve_property_with(contexts, field_property!(as_paperless_document, title)), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'PaperlessDocument'" + ) + } + } +} + +pub(super) fn resolve_record_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &Arc, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + let property_name = property_name.clone(); + match property_name.as_ref() { + "_at" => resolve_property_with( + contexts, + field_property!(as_record, at, { at.to_string().into() }), + ), + "_kind" => resolve_property_with(contexts, field_property!(as_record, kind)), + _ => resolve_property_with(contexts, move |v: &Vertex| { + let rec = v + .as_record() + .expect("Called record property without it being a record"); + + kdl_to_trustfall_value(rec.fields[property_name.as_ref()].clone()) + }), + } +} + +fn kdl_to_trustfall_value(val: KdlValue) -> FieldValue { + match val { + KdlValue::Bool(b) => FieldValue::Boolean(b), + KdlValue::Float(f) => FieldValue::Float64(f), + KdlValue::Null => FieldValue::Null, + KdlValue::Integer(i) => FieldValue::Int64(i.try_into().unwrap()), + KdlValue::String(s) => FieldValue::String(s.into()), + } +} diff --git a/crates/plaixt/src/adapter/schema.graphql b/crates/plaixt/src/adapter/schema.graphql new file mode 100644 index 0000000..b56faad --- /dev/null +++ b/crates/plaixt/src/adapter/schema.graphql @@ -0,0 +1,88 @@ +schema { + query: RootSchemaQuery +} + +directive @filter( + """ + Name of the filter operation to perform. + """ + op: String! + """ + List of string operands for the operator. + """ + value: [String!] +) repeatable on FIELD | INLINE_FRAGMENT +directive @tag( + """ + Name to apply to the given property field. + """ + name: String +) on FIELD +directive @output( + """ + What to designate the output field generated from this property field. + """ + name: String +) on FIELD +directive @optional on FIELD +directive @recurse( + """ + Recurse up to this many times on this edge. A depth of 1 produces the current + vertex and its immediate neighbors along the given edge. + """ + depth: Int! +) on FIELD +directive @fold on FIELD +directive @transform( + """ + Name of the transformation operation to perform. + """ + op: String! +) on FIELD + + +""" +All the possible data types to begin querying +""" +type RootSchemaQuery { + """ + All records in your plaixt instance + """ + Records: [Record!]! +} + +interface Record { + _kind: String! + _at: String! +} + +interface Path { + path: String! + exists: Boolean! + basename: String! +} + +interface File implements Path { + path: String! + exists: Boolean! + basename: String! + + extension: String! +} + +type Directory implements Path { + path: String! + exists: Boolean! + basename: String! + + Children: [Path!]! +} + +type PaperlessDocument { + id: Int! + title: String! + content: String! + archive_serial_number: Int + created: String! + added: String! +} diff --git a/crates/plaixt/src/adapter/tests.rs b/crates/plaixt/src/adapter/tests.rs new file mode 100644 index 0000000..8acec27 --- /dev/null +++ b/crates/plaixt/src/adapter/tests.rs @@ -0,0 +1,16 @@ +use trustfall::provider::check_adapter_invariants; + +use super::Adapter; + +#[tokio::test] +async fn adapter_satisfies_trustfall_invariants() { + let schema = Adapter::schema(); + let adapter = Adapter::new( + schema.clone(), + vec![], + [].into(), + None, + tokio::runtime::Handle::current(), + ); + check_adapter_invariants(schema, adapter); +} diff --git a/crates/plaixt/src/adapter/vertex.rs b/crates/plaixt/src/adapter/vertex.rs new file mode 100644 index 0000000..3829e2e --- /dev/null +++ b/crates/plaixt/src/adapter/vertex.rs @@ -0,0 +1,15 @@ +use camino::Utf8PathBuf; +use paperless_rs::endpoint::documents::Document as PaperlessDocument; + +use crate::parsing::Record; + +#[non_exhaustive] +#[derive(Debug, Clone, trustfall::provider::TrustfallEnumVertex)] +pub enum Vertex { + Path(Utf8PathBuf), + File(Utf8PathBuf), + Directory(Utf8PathBuf), + + PaperlessDocument(PaperlessDocument), + Record(Record), +} diff --git a/crates/plaixt/src/main.rs b/crates/plaixt/src/main.rs index c64aa27..4361ea5 100644 --- a/crates/plaixt/src/main.rs +++ b/crates/plaixt/src/main.rs @@ -8,7 +8,6 @@ use camino::Utf8PathBuf; use clap::Parser; use clap::Subcommand; use clap::ValueHint; -use filesystem_trustfall_adapter::FileSystemAdapter; use human_panic::Metadata; use miette::IntoDiagnostic; use parsing::Definition; @@ -18,9 +17,9 @@ use tracing_subscriber::EnvFilter; use trustfall::execute_query; use trustfall::FieldValue; +mod adapter; mod config; mod parsing; -mod trustfall_plaixt; #[derive(Debug, Parser)] struct Args { @@ -97,14 +96,19 @@ async fn main() -> miette::Result<()> { fn get_schema_and_adapter( definitions: &BTreeMap>, records: Vec, -) -> (trustfall::Schema, trustfall_plaixt::TrustfallMultiAdapter) { - let schema = trustfall_plaixt::to_schema(definitions); - let adapter = trustfall_plaixt::TrustfallMultiAdapter { - plaixt: trustfall_plaixt::PlaixtAdapter { - records: records.clone(), - }, - filesystem: FileSystemAdapter::new(), - }; +) -> (trustfall::Schema, adapter::Adapter) { + let schema = adapter::to_schema(definitions); + let definitions = definitions + .iter() + .map(|(name, def)| (name.clone(), def.last().cloned().unwrap().fields)) + .collect(); + let adapter = adapter::Adapter::new( + schema.clone(), + records, + definitions, + None, + tokio::runtime::Handle::current(), + ); (schema, adapter) } diff --git a/crates/plaixt/src/parsing.rs b/crates/plaixt/src/parsing.rs index 243dd61..f3ca840 100644 --- a/crates/plaixt/src/parsing.rs +++ b/crates/plaixt/src/parsing.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; -use std::collections::HashMap; use camino::Utf8Path; use camino::Utf8PathBuf; @@ -15,8 +14,6 @@ use miette::NamedSource; use owo_colors::OwoColorize; use tokio_stream::wrappers::ReadDirStream; -use crate::trustfall_plaixt::ADAPTER_SEP; - #[derive(Debug, Clone)] pub struct Record { pub(crate) kind: String, @@ -155,7 +152,7 @@ pub(crate) async fn load_records( Ok(defs) } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum DefinitionKind { String, Path, @@ -163,11 +160,11 @@ pub enum DefinitionKind { } impl DefinitionKind { - pub(crate) fn trustfall_kind(&self) -> String { + pub(crate) fn trustfall_kind(&self, _namespace: &str) -> String { match self { - DefinitionKind::String => String::from("String"), - DefinitionKind::Path => format!("fs{ADAPTER_SEP}Path"), - DefinitionKind::OneOf(_vecs) => String::from("String"), + DefinitionKind::String => String::from("String!"), + DefinitionKind::Path => String::from("Path!"), + DefinitionKind::OneOf(_vecs) => String::from("String!"), } } @@ -188,6 +185,23 @@ impl DefinitionKind { .ok_or_else(|| format!("Expected one of: {}", options.join(", "))), } } + + pub(crate) fn extra_trustfall_kinds( + &self, + namespace: &str, + ) -> Vec { + match self { + DefinitionKind::OneOf(defs) => { + let name = format!("{namespace}Def"); + let vec = vec![crate::adapter::CustomVertex { + definition: format!("enum {name} {{ {} }}", defs.join(",")), + name, + }]; + vec + } + _ => vec![], + } + } } impl TryFrom<&str> for DefinitionKind { @@ -201,11 +215,11 @@ impl TryFrom<&str> for DefinitionKind { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Definition { pub(crate) name: String, pub(crate) since: Timestamp, - pub(crate) fields: HashMap, + pub(crate) fields: BTreeMap, } pub(crate) fn parse_definition( diff --git a/crates/plaixt/src/trustfall_plaixt.rs b/crates/plaixt/src/trustfall_plaixt.rs deleted file mode 100644 index 7e95369..0000000 --- a/crates/plaixt/src/trustfall_plaixt.rs +++ /dev/null @@ -1,639 +0,0 @@ -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::fmt::Write; -use std::ops::Not; -use std::sync::Arc; - -use kdl::KdlValue; -use tracing::debug; -use tracing::trace; -use trustfall::provider::field_property; -use trustfall::provider::resolve_coercion_with; -use trustfall::provider::resolve_neighbors_with; -use trustfall::provider::resolve_property_with; -use trustfall::provider::Adapter; -use trustfall::provider::AsVertex; -use trustfall::FieldValue; -use trustfall::Schema; - -use crate::parsing::Definition; -use crate::parsing::Record; - -pub(crate) const ADAPTER_SEP: &str = "__"; - -#[derive(Debug, Default)] -pub struct StartingVertex { - adapter_name: String, - start_vertex_name: String, - vertex_type: String, -} - -impl StartingVertex { - pub fn new(adapter_name: String, start_vertex_name: String, start_vertex_type: String) -> Self { - Self { - adapter_name, - start_vertex_name, - vertex_type: start_vertex_type, - } - } - - pub fn schema_name(&self) -> String { - format!( - "{}{ADAPTER_SEP}{}", - self.adapter_name, self.start_vertex_name - ) - } - - pub fn vertex_type(&self) -> &str { - &self.vertex_type - } -} - -#[derive(Debug, Default)] -pub struct VertexType { - adapter_name: String, - vertex_name: String, - vertex_fields: HashMap, - implements: Vec, -} - -impl VertexType { - pub fn new( - adapter_name: String, - vertex_name: String, - vertex_fields: HashMap, - implements: Vec, - ) -> Self { - Self { - adapter_name, - vertex_name, - vertex_fields, - implements, - } - } - - pub fn schema_name(&self) -> String { - format!("{}{ADAPTER_SEP}{}", self.adapter_name, self.vertex_name) - } - - pub fn schema_type(&self) -> String { - format!( - r#"type {name} {impls} {{ {fields} }}"#, - name = self.schema_name(), - impls = self - .implements - .is_empty() - .not() - .then(|| format!("implements {}", self.implements.join(" & "))) - .unwrap_or_else(String::new), - fields = self.vertex_fields.iter().fold(String::new(), |mut out, f| { - write!(out, "{}: {}, ", f.0, f.1).unwrap(); - out - }), - ) - } -} - -#[derive(Debug, Default)] -pub struct DynamicSchema { - roots: Vec, - types: Vec, -} - -impl DynamicSchema { - pub fn new() -> Self { - Self::default() - } - - pub fn add_root(&mut self, root: StartingVertex) { - self.roots.push(root); - } - - pub fn add_type(&mut self, kind: VertexType) { - self.types.push(kind); - } -} - -pub(crate) fn to_schema(definitions: &BTreeMap>) -> Schema { - let mut schema = DynamicSchema::new(); - - schema.add_root(StartingVertex::new( - "Plaixt".to_string(), - "RecordsAll".to_string(), - "[Record!]!".to_string(), - )); - - for definition in definitions.values().flat_map(|d| d.first()) { - let fields = VertexType::new( - "Plaixt".to_string(), - format!("{}Fields", definition.name), - definition - .fields - .iter() - .map(|(name, val)| (name.clone(), format!("{}!", val.trustfall_kind()))) - .collect(), - vec![], - ); - schema.add_type(VertexType::new( - "Plaixt".to_string(), - definition.name.clone(), - [ - (String::from("at"), String::from("String!")), - (String::from("kind"), String::from("String!")), - (String::from("fields"), format!("{}!", fields.schema_name())), - ] - .into(), - vec![String::from("Record")], - )); - schema.add_type(fields); - } - - let schema = format!( - r#"schema {{ - query: RootSchemaQuery - }} - {} - type RootSchemaQuery {{ - {roots} - fs{ADAPTER_SEP}Path(path: String!): fs{ADAPTER_SEP}Path!, - }} - interface Record {{ - at: String!, - kind: String!, - }} - - interface fs{ADAPTER_SEP}Path {{ - path: String! - }} - - type fs{ADAPTER_SEP}Folder implements fs{ADAPTER_SEP}Path {{ - path: String! - children: [fs{ADAPTER_SEP}Path!] - }} - - type fs{ADAPTER_SEP}File implements fs{ADAPTER_SEP}Path {{ - path: String! - size: Int! - extension: String! - Hash: String! - }} - - {types} - "#, - Schema::ALL_DIRECTIVE_DEFINITIONS, - roots = schema.roots.iter().fold(String::new(), |mut out, r| { - write!(out, "{}: {}, ", r.schema_name(), r.vertex_type()).unwrap(); - out - }), - types = schema.types.iter().fold(String::new(), |mut out, t| { - writeln!(out, "{}", t.schema_type()).unwrap(); - out - }), - ); - trace!(%schema, "Using schema"); - Schema::parse(schema).unwrap() -} - -pub struct TrustfallMultiAdapter { - pub plaixt: PlaixtAdapter, - pub filesystem: filesystem_trustfall_adapter::FileSystemAdapter, -} - -#[derive(Debug, Clone)] -pub enum TrustfallMultiVertex { - Plaixt(PlaixtVertex), - Filesystem(filesystem_trustfall_adapter::vertex::Vertex), -} - -impl AsVertex for TrustfallMultiVertex { - fn as_vertex(&self) -> Option<&filesystem_trustfall_adapter::vertex::Vertex> { - self.as_filesystem() - } - - fn into_vertex(self) -> Option { - self.as_filesystem().cloned() - } -} - -impl AsVertex for TrustfallMultiVertex { - fn as_vertex(&self) -> Option<&PlaixtVertex> { - self.as_plaixt() - } - - fn into_vertex(self) -> Option { - self.as_plaixt().cloned() - } -} - -impl TrustfallMultiVertex { - pub fn as_plaixt(&self) -> Option<&PlaixtVertex> { - if let Self::Plaixt(v) = self { - Some(v) - } else { - None - } - } - - pub fn as_filesystem( - &self, - ) -> Option< - &>::Vertex, - > { - if let Self::Filesystem(v) = self { - Some(v) - } else { - None - } - } -} - -impl<'v> Adapter<'v> for TrustfallMultiAdapter { - type Vertex = TrustfallMultiVertex; - - fn resolve_starting_vertices( - &self, - edge_name: &Arc, - parameters: &trustfall::provider::EdgeParameters, - resolve_info: &trustfall::provider::ResolveInfo, - ) -> trustfall::provider::VertexIterator<'v, Self::Vertex> { - let (adapter_name, edge_name) = edge_name.split_once(ADAPTER_SEP).unwrap(); - - trace!( - ?adapter_name, - ?edge_name, - "resolving top-level starting vertex" - ); - - match adapter_name { - "Plaixt" => { - let iter = self.plaixt.resolve_starting_vertices( - &Arc::from(edge_name), - parameters, - resolve_info, - ); - - Box::new(iter.map(TrustfallMultiVertex::Plaixt)) - } - "fs" => { - let iter = self.filesystem.resolve_starting_vertices( - &Arc::from(edge_name), - parameters, - resolve_info, - ); - - Box::new( - iter.inspect(|v| trace!(?v, "Got vertex")) - .map(TrustfallMultiVertex::Filesystem), - ) - } - _ => unreachable!(), - } - } - - fn resolve_property( - &self, - contexts: trustfall::provider::ContextIterator<'v, V>, - type_name: &Arc, - property_name: &Arc, - resolve_info: &trustfall::provider::ResolveInfo, - ) -> trustfall::provider::ContextOutcomeIterator<'v, V, FieldValue> - where - V: trustfall::provider::AsVertex + 'v, - { - trace!(?type_name, ?property_name, "resolving top-level property"); - let (adapter_name, type_name) = type_name - .split_once(ADAPTER_SEP) - .unwrap_or(("Plaixt", type_name)); - - match adapter_name { - "Plaixt" => { - let contexts = contexts.collect::>(); - - let properties = self.plaixt.resolve_property( - Box::new( - contexts - .clone() - .into_iter() - .map(|v| v.flat_map(&mut |v: V| v.into_vertex())), - ), - &Arc::from(type_name), - property_name, - resolve_info, - ); - - Box::new( - properties - .into_iter() - .zip(contexts) - .map(|((_ctx, name), og_ctx)| (og_ctx, name)), - ) - } - "fs" => { - let contexts = contexts.collect::>(); - - let properties = self.filesystem.resolve_property( - Box::new( - contexts - .clone() - .into_iter() - .map(|v| v.flat_map(&mut |v: V| v.into_vertex())) - .inspect(|v| trace!(?v, "Got vertex")), - ), - &Arc::from(type_name), - property_name, - resolve_info, - ); - - Box::new( - properties - .into_iter() - .zip(contexts) - .map(|((_ctx, name), og_ctx)| (og_ctx, name)), - ) - } - _ => unreachable!(), - } - } - - fn resolve_neighbors + 'v>( - &self, - contexts: trustfall::provider::ContextIterator<'v, V>, - type_name: &Arc, - edge_name: &Arc, - parameters: &trustfall::provider::EdgeParameters, - resolve_info: &trustfall::provider::ResolveEdgeInfo, - ) -> trustfall::provider::ContextOutcomeIterator< - 'v, - V, - trustfall::provider::VertexIterator<'v, Self::Vertex>, - > { - trace!(?type_name, ?edge_name, "Resolving top-level neighbor"); - let (adapter_name, type_name) = type_name.split_once(ADAPTER_SEP).unwrap(); - - match adapter_name { - "Plaixt" => { - let contexts = contexts.collect::>(); - - let properties = self.plaixt.resolve_neighbors( - Box::new( - contexts - .clone() - .into_iter() - .map(|v| v.flat_map(&mut |v: V| v.into_vertex())), - ), - &Arc::from(type_name), - edge_name, - parameters, - resolve_info, - ); - - Box::new( - properties - .into_iter() - .zip(contexts) - .map(|((_ctx, vals), og_ctx)| { - ( - og_ctx, - Box::new(vals.map(TrustfallMultiVertex::Plaixt)) as Box<_>, - ) - }), - ) - } - "fs" => { - let contexts = contexts.collect::>(); - - let properties = self.filesystem.resolve_neighbors( - Box::new( - contexts - .clone() - .into_iter() - .map(|v| v.flat_map(&mut |v: V| v.into_vertex())), - ), - &Arc::from(type_name), - edge_name, - parameters, - resolve_info, - ); - - Box::new( - properties - .into_iter() - .zip(contexts) - .map(|((_ctx, vals), og_ctx)| { - ( - og_ctx, - Box::new( - vals.inspect(|v| trace!(?v, "Got vertex")) - .map(TrustfallMultiVertex::Filesystem), - ) as Box<_>, - ) - }), - ) - } - _ => unreachable!(), - } - } - - fn resolve_coercion + 'v>( - &self, - contexts: trustfall::provider::ContextIterator<'v, V>, - type_name: &Arc, - coerce_to_type: &Arc, - resolve_info: &trustfall::provider::ResolveInfo, - ) -> trustfall::provider::ContextOutcomeIterator<'v, V, bool> { - trace!(?type_name, ?coerce_to_type, "Top-level coerce"); - let (adapter_name, coerce_to_type) = coerce_to_type.split_once(ADAPTER_SEP).unwrap(); - - match adapter_name { - "Plaixt" => { - let contexts = contexts.collect::>(); - - let properties = self.plaixt.resolve_coercion( - Box::new( - contexts - .clone() - .into_iter() - .map(|v| v.flat_map(&mut |v: V| v.into_vertex())), - ), - type_name, - &Arc::from(coerce_to_type), - resolve_info, - ); - - Box::new( - properties - .into_iter() - .zip(contexts) - .map(|((_ctx, val), og_ctx)| (og_ctx, val)), - ) - } - "fs" => { - let contexts = contexts.collect::>(); - - let properties = self.filesystem.resolve_coercion( - Box::new( - contexts - .clone() - .into_iter() - .map(|v| v.flat_map(&mut |v: V| v.into_vertex())), - ), - type_name, - &Arc::from(coerce_to_type), - resolve_info, - ); - - let type_name = type_name.clone(); - let coerce_to_type = coerce_to_type.to_string(); - Box::new(properties.into_iter().zip(contexts).map( - move |((_ctx, allowed), og_ctx)| { - trace!(?allowed, ?type_name, ?coerce_to_type, "Allowed coercion?"); - (og_ctx, allowed) - }, - )) - } - _ => unreachable!(), - } - } -} - -pub(crate) struct PlaixtAdapter { - pub(crate) records: Vec, -} - -#[derive(Clone, Debug)] -pub(crate) enum PlaixtVertex { - Record(Record), - Fields { - name: String, - values: BTreeMap, - }, -} - -impl PlaixtVertex { - pub(crate) fn as_fields(&self) -> Option<&BTreeMap> { - if let Self::Fields { values, .. } = self { - Some(values) - } else { - None - } - } - - pub(crate) fn as_record(&self) -> Option<&Record> { - if let Self::Record(v) = self { - Some(v) - } else { - None - } - } - - pub(crate) fn typename(&self) -> String { - match self { - PlaixtVertex::Record { .. } => "Record".to_string(), - PlaixtVertex::Fields { name, .. } => name.clone(), - } - } -} - -impl<'a> Adapter<'a> for PlaixtAdapter { - type Vertex = PlaixtVertex; - - fn resolve_starting_vertices( - &self, - edge_name: &Arc, - _parameters: &trustfall::provider::EdgeParameters, - _resolve_info: &trustfall::provider::ResolveInfo, - ) -> trustfall::provider::VertexIterator<'a, Self::Vertex> { - trace!(?edge_name, "Resolving start vertex"); - match edge_name.as_ref() { - "RecordsAll" => Box::new(self.records.clone().into_iter().map(PlaixtVertex::Record)), - _ => unreachable!(), - } - } - - fn resolve_property + 'a>( - &self, - contexts: trustfall::provider::ContextIterator<'a, V>, - type_name: &Arc, - property_name: &Arc, - _resolve_info: &trustfall::provider::ResolveInfo, - ) -> trustfall::provider::ContextOutcomeIterator<'a, V, trustfall::FieldValue> { - match (type_name.as_ref(), property_name.as_ref()) { - (_, "__typename") => Box::new(contexts.map(|ctx| { - let value = match ctx.active_vertex() { - Some(_record) => _record.typename().into(), - None => FieldValue::Null, - }; - - (ctx, value) - })), - (_, "at") => resolve_property_with( - contexts, - field_property!(as_record, at, { at.to_string().into() }), - ), - (_, "kind") => resolve_property_with(contexts, field_property!(as_record, kind)), - (name, field) => { - debug!(?name, ?field, "Asking for properties"); - - let field = field.to_string(); - resolve_property_with(contexts, move |vertex| { - trace!(?vertex, ?field, "Getting property"); - let fields = vertex.as_fields().unwrap(); - match fields.get(&field).unwrap().clone() { - KdlValue::Bool(b) => FieldValue::Boolean(b), - KdlValue::Float(f) => FieldValue::Float64(f), - KdlValue::Null => FieldValue::Null, - KdlValue::Integer(i) => FieldValue::Int64(i.try_into().unwrap()), - KdlValue::String(s) => FieldValue::String(s.into()), - } - }) - } - } - } - - fn resolve_neighbors + 'a>( - &self, - contexts: trustfall::provider::ContextIterator<'a, V>, - type_name: &Arc, - edge_name: &Arc, - _parameters: &trustfall::provider::EdgeParameters, - _resolve_info: &trustfall::provider::ResolveEdgeInfo, - ) -> trustfall::provider::ContextOutcomeIterator< - 'a, - V, - trustfall::provider::VertexIterator<'a, Self::Vertex>, - > { - trace!(?type_name, ?edge_name, "Resolving neighbors"); - match edge_name.as_ref() { - "fields" => resolve_neighbors_with(contexts, |c| { - Box::new( - c.as_record() - .map(|r| PlaixtVertex::Fields { - name: format!("{}Fields", r.kind), - values: r.fields.clone(), - }) - .into_iter(), - ) - }), - _ => resolve_neighbors_with(contexts, |c| todo!()), - _ => unreachable!("Could not resolve {edge_name}"), - } - } - - fn resolve_coercion + 'a>( - &self, - contexts: trustfall::provider::ContextIterator<'a, V>, - type_name: &Arc, - coerce_to_type: &Arc, - _resolve_info: &trustfall::provider::ResolveInfo, - ) -> trustfall::provider::ContextOutcomeIterator<'a, V, bool> { - debug!("Asking to coerce {type_name} into {coerce_to_type}"); - let coerce_to_type = coerce_to_type.clone(); - resolve_coercion_with(contexts, move |node| { - node.as_record() - .map(|r| r.kind == *coerce_to_type) - .unwrap_or(false) - }) - } -} diff --git a/flake.nix b/flake.nix index e5c7893..2d2449a 100644 --- a/flake.nix +++ b/flake.nix @@ -16,8 +16,17 @@ }; }; - outputs = { self, nixpkgs, crane, flake-utils, rust-overlay, ... }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + nixpkgs, + crane, + flake-utils, + rust-overlay, + ... + }: + flake-utils.lib.eachDefaultSystem ( + system: let pkgs = import nixpkgs { inherit system; @@ -25,29 +34,51 @@ }; rustTarget = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; - unstableRustTarget = pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override { - extensions = [ "rust-src" "miri" "rustfmt" ]; - }); + unstableRustTarget = pkgs.rust-bin.selectLatestNightlyWith ( + toolchain: + toolchain.default.override { + extensions = [ + "rust-src" + "miri" + "rustfmt" + ]; + } + ); craneLib = (crane.mkLib pkgs).overrideToolchain rustTarget; unstableCraneLib = (crane.mkLib pkgs).overrideToolchain unstableRustTarget; tomlInfo = craneLib.crateNameFromCargoToml { cargoToml = ./Cargo.toml; }; - inherit (tomlInfo) pname version; + inherit (tomlInfo) version; + src = ./.; rustfmt' = pkgs.writeShellScriptBin "rustfmt" '' exec "${unstableRustTarget}/bin/rustfmt" "$@" ''; - cargoArtifacts = craneLib.buildDepsOnly { - inherit src; - cargoExtraArgs = "--all-features --all"; + common = { + src = ./.; + + buildInputs = [ + pkgs.openssl + pkgs.pkg-config + ]; }; - plaixt = craneLib.buildPackage { - inherit cargoArtifacts src version; - cargoExtraArgs = "--all-features --all"; - }; + cargoArtifacts = craneLib.buildDepsOnly ( + common + // { + cargoExtraArgs = "--all-features --all"; + } + ); + + plaixt = craneLib.buildPackage ( + common + // { + inherit cargoArtifacts version; + cargoExtraArgs = "--all-features --all"; + } + ); in rec { @@ -78,6 +109,8 @@ devShells.plaixt = pkgs.mkShell { buildInputs = [ ]; + inputsFrom = [ plaixt ]; + nativeBuildInputs = [ rustfmt' rustTarget