diff --git a/.gitignore b/.gitignore index d63f5c1..83b8213 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ /target .DS_Store -*.xcuserdatad \ No newline at end of file +*.xcuserdatad +.venv +*.csv +*.h +*.py +.idea \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 441e7ee..491fe0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,14 +14,38 @@ dependencies = [ ] [[package]] -name = "aho-corasick" -version = "0.7.20" +name = "ahash" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -46,6 +70,71 @@ dependencies = [ "num-traits", ] +[[package]] +name = "argminmax" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202108b46429b765ef483f8a24d5c46f48c14acfdacc086dd4ab6dddf6bcdbd2" +dependencies = [ + "num-traits", +] + +[[package]] +name = "array-init-cursor" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7d0a018de4f6aa429b9d33d69edf69072b1c5b1cb8d3e4a5f7ef898fc3eb76" + +[[package]] +name = "arrow-format" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07884ea216994cdc32a2d5f8274a8bee979cfe90274b83f86f440866ee3132c7" +dependencies = [ + "planus", + "serde", +] + +[[package]] +name = "arrow2" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c468daea140b747d781a1da9f7db5f0a8e6636d4af20cc539e43d05b0604fa" +dependencies = [ + "ahash 0.8.3", + "arrow-format", + "bytemuck", + "chrono", + "dyn-clone", + "either", + "ethnum", + "foreign_vec", + "futures", + "getrandom", + "hash_hasher", + "lexical-core", + "lz4", + "multiversion", + "num-traits", + "regex", + "regex-syntax 0.6.29", + "rustc_version", + "simdutf8", + "strength_reduce", + "zstd", +] + +[[package]] +name = "async-trait" +version = "0.1.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "atoi" version = "1.0.0" @@ -55,6 +144,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -73,6 +171,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "block-buffer" version = "0.10.4" @@ -90,7 +194,7 @@ checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", - "regex-automata", + "regex-automata 0.1.10", "serde", ] @@ -105,6 +209,20 @@ name = "bytemuck" version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] [[package]] name = "byteorder" @@ -123,6 +241,9 @@ name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -132,18 +253,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "serde", - "time", "wasm-bindgen", - "winapi", + "windows-targets 0.48.5", ] [[package]] @@ -152,7 +272,7 @@ version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex", "is-terminal", @@ -171,7 +291,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.95", ] [[package]] @@ -193,6 +313,18 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "comfy-table" +version = "7.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab77dbd8adecaf3f0db40581631b995f312a8a5ae3aa9993188bb8f23d83a5b" +dependencies = [ + "crossterm", + "strum", + "strum_macros 0.24.3", + "unicode-width", +] + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -209,10 +341,12 @@ dependencies = [ "csv", "itertools", "nalgebra", + "polars", "rayon", "rmp-serde", "serde", "sqlx", + "tempfile", "tokio", ] @@ -293,6 +427,31 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossterm" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" +dependencies = [ + "bitflags 1.3.2", + "crossterm_winapi", + "libc", + "mio", + "parking_lot 0.12.1", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -349,7 +508,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn", + "syn 1.0.95", ] [[package]] @@ -366,7 +525,7 @@ checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.95", ] [[package]] @@ -386,10 +545,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03d8c417d7a8cb362e0c37e5d815f5eb7c37f79ff93707329d5a194e42e54ca0" [[package]] -name = "either" -version = "1.6.1" +name = "dyn-clone" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "encoding_rs" @@ -400,6 +565,24 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum_dispatch" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.2.8" @@ -411,6 +594,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -421,12 +614,36 @@ dependencies = [ "libc", ] +[[package]] +name = "ethnum" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8ff382b2fa527fb7fb06eeebfc5bbb3f17e3cc6b9d70b006c41daa8824adac" + [[package]] name = "event-listener" version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "fast-float" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95765f67b4b18863968b4a1bd5bb576f732b29a4a28c7cd84c09fa3e2875f33c" + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "foreign_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1b05cbd864bcaecbd3455d6d967862d446e4ebfc3c2e5e5b9841e53cba6673" + [[package]] name = "form_urlencoded" version = "1.1.0" @@ -437,10 +654,25 @@ dependencies = [ ] [[package]] -name = "futures-channel" -version = "0.3.26" +name = "futures" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -448,9 +680,20 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] [[package]] name = "futures-intrusive" @@ -464,28 +707,50 @@ dependencies = [ ] [[package]] -name = "futures-sink" -version = "0.3.26" +name = "futures-io" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -505,17 +770,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", + "wasm-bindgen", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "hash_hasher" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74721d007512d0cb3338cd20f0654ac913920061a4c4d0d8708edb3f2a698c0c" + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +dependencies = [ + "ahash 0.8.3", + "allocator-api2", + "rayon", ] [[package]] @@ -524,14 +814,14 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" dependencies = [ - "hashbrown", + "hashbrown 0.12.3", ] [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" dependencies = [ "unicode-segmentation", ] @@ -557,6 +847,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "iana-time-zone" version = "0.1.53" @@ -598,7 +897,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +dependencies = [ + "equivalent", + "hashbrown 0.14.1", ] [[package]] @@ -617,7 +926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -628,8 +937,8 @@ checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix", - "windows-sys", + "rustix 0.36.8", + "windows-sys 0.45.0", ] [[package]] @@ -653,6 +962,15 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.61" @@ -669,10 +987,89 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -name = "libc" -version = "0.2.139" +name = "lexical" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "c7aefb36fd43fef7003334742cbf77b243fcd36418a1d1bdd480d613a67968f6" +dependencies = [ + "lexical-core", +] + +[[package]] +name = "lexical-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "link-cplusplus" @@ -689,6 +1086,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + [[package]] name = "lock_api" version = "0.4.9" @@ -708,6 +1111,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lz4" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +dependencies = [ + "libc", + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "matrixmultiply" version = "0.3.2" @@ -719,9 +1142,18 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memmap2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6" +dependencies = [ + "libc", +] [[package]] name = "memoffset" @@ -746,8 +1178,30 @@ checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "wasi", + "windows-sys 0.45.0", +] + +[[package]] +name = "multiversion" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2c7b9d7fe61760ce5ea19532ead98541f6b4c495d87247aff9826445cf6872a" +dependencies = [ + "multiversion-macros", + "target-features", +] + +[[package]] +name = "multiversion-macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26a83d8500ed06d68877e9de1dde76c1dbb83885dcdbda4ef44ccbc3fbda2ac8" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.95", + "target-features", ] [[package]] @@ -774,7 +1228,7 @@ checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.95", ] [[package]] @@ -787,6 +1241,24 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "now" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89e9874397a1f0a52fc1f197a8effd9735223cb2390e9dcc83ac6cd02923d0" +dependencies = [ + "chrono", +] + +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + [[package]] name = "num-complex" version = "0.4.1" @@ -824,6 +1296,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -838,9 +1311,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "os_str_bytes" @@ -878,7 +1351,7 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] @@ -891,9 +1364,9 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -920,6 +1393,278 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "planus" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1691dd09e82f428ce8d6310bd6d5da2557c82ff17694d2a32cad7242aea89f" +dependencies = [ + "array-init-cursor", +] + +[[package]] +name = "polars" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1362d4a136c0ebacb40d88a37ba361738b222fd8a2ee9340a3d8642f698c52b" +dependencies = [ + "getrandom", + "polars-core", + "polars-io", + "polars-lazy", + "polars-ops", + "polars-sql", + "polars-time", + "version_check", +] + +[[package]] +name = "polars-arrow" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f967c901fa5da4ca7f64e813d1268488ba97e9b3004cefc579ff851c197a1138" +dependencies = [ + "arrow2", + "hashbrown 0.14.1", + "multiversion", + "num-traits", + "polars-error", + "thiserror", + "version_check", +] + +[[package]] +name = "polars-core" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b24f92fc5b167f668ff85ab9607dfa72e2c09664cacef59297ee8601dee60126" +dependencies = [ + "ahash 0.8.3", + "arrow2", + "bitflags 2.4.0", + "chrono", + "comfy-table", + "either", + "hashbrown 0.14.1", + "indexmap 2.0.2", + "num-traits", + "once_cell", + "polars-arrow", + "polars-error", + "polars-row", + "polars-utils", + "rand", + "rand_distr", + "rayon", + "regex", + "smartstring", + "thiserror", + "version_check", + "xxhash-rust", +] + +[[package]] +name = "polars-error" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40d09c3a7337e53b38c37b57999038440fa39c6801b9ba48afaecd8e16f7ac0a" +dependencies = [ + "arrow2", + "regex", + "thiserror", +] + +[[package]] +name = "polars-io" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92cab0df9f2a35702fa5aec99edfaabf9ae8e9cdd0acf69e143ad2d132f34f9c" +dependencies = [ + "ahash 0.8.3", + "arrow2", + "async-trait", + "bytes", + "chrono", + "fast-float", + "futures", + "home", + "lexical", + "lexical-core", + "memchr", + "memmap2", + "num-traits", + "once_cell", + "polars-arrow", + "polars-core", + "polars-error", + "polars-time", + "polars-utils", + "rayon", + "regex", + "simdutf8", + "tokio", +] + +[[package]] +name = "polars-lazy" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c33762ec2a55e01c9f8776b34db86257c70a0a3b3929bd4eb91a52aacf61456" +dependencies = [ + "ahash 0.8.3", + "bitflags 2.4.0", + "glob", + "once_cell", + "polars-arrow", + "polars-core", + "polars-io", + "polars-ops", + "polars-pipe", + "polars-plan", + "polars-time", + "polars-utils", + "rayon", + "smartstring", + "version_check", +] + +[[package]] +name = "polars-ops" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825575c96302d2daedfc205a0062180033c92c55bcd6aafc4e109d4d8849ed0" +dependencies = [ + "argminmax", + "arrow2", + "either", + "indexmap 2.0.2", + "memchr", + "polars-arrow", + "polars-core", + "polars-utils", + "smartstring", + "version_check", +] + +[[package]] +name = "polars-pipe" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f2bc9a12da9ed043fb0cb51dbcb87b365e4845b7ab6399d7a81e838460c6974" +dependencies = [ + "crossbeam-channel", + "crossbeam-queue", + "enum_dispatch", + "hashbrown 0.14.1", + "num-traits", + "polars-arrow", + "polars-core", + "polars-io", + "polars-ops", + "polars-plan", + "polars-row", + "polars-utils", + "rayon", + "smartstring", + "version_check", +] + +[[package]] +name = "polars-plan" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb67b014f0295e8e9dbb84404a91d666d477b3bc248a2ed51bc442833b16da35" +dependencies = [ + "ahash 0.8.3", + "arrow2", + "once_cell", + "polars-arrow", + "polars-core", + "polars-io", + "polars-ops", + "polars-time", + "polars-utils", + "rayon", + "regex", + "smartstring", + "strum_macros 0.25.2", + "version_check", +] + +[[package]] +name = "polars-row" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f54c1956027bf6301948fb4f2837cf6d6b638d8dd1edf3aaeaa19906a986be" +dependencies = [ + "arrow2", + "polars-error", + "polars-utils", +] + +[[package]] +name = "polars-sql" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfcb15cf8eebd25ea1724109d0153817cd484c6326290585f0736b4e7fcf2f4" +dependencies = [ + "polars-arrow", + "polars-core", + "polars-lazy", + "polars-plan", + "serde", + "serde_json", + "sqlparser", +] + +[[package]] +name = "polars-time" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f42d2632f5971c9575041d33cbcfb1f996900c40bbf58bc6eb0a0c5efbecea" +dependencies = [ + "arrow2", + "atoi 2.0.0", + "chrono", + "now", + "once_cell", + "polars-arrow", + "polars-core", + "polars-ops", + "polars-utils", + "regex", + "smartstring", +] + +[[package]] +name = "polars-utils" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c326708a370d71dc6e11a8f4bbc10a8479e1c314dc048ba73543b815cd0bf339" +dependencies = [ + "ahash 0.8.3", + "hashbrown 0.14.1", + "num-traits", + "once_cell", + "polars-error", + "rayon", + "smartstring", + "sysinfo", + "version_check", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -929,7 +1674,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.95", "version_check", ] @@ -946,22 +1691,62 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + [[package]] name = "rawpointer" version = "0.2.1" @@ -996,18 +1781,28 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.7.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "d119d7c7ca818f8a53c300863d4f87566aac09943aef5b355bb83969dae75d87" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-automata 0.4.1", + "regex-syntax 0.8.1", ] [[package]] @@ -1017,10 +1812,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] -name = "regex-syntax" -version = "0.6.28" +name = "regex-automata" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.1", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d84fdd47036b038fc80dd333d10b6aab10d5d31f4a366e20014def75328d33" [[package]] name = "ring" @@ -1059,18 +1871,40 @@ dependencies = [ "serde", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.36.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ - "bitflags", - "errno", + "bitflags 1.3.2", + "errno 0.2.8", "io-lifetimes", "libc", - "linux-raw-sys", - "windows-sys", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.0", + "errno 0.3.8", + "libc", + "linux-raw-sys 0.4.12", + "windows-sys 0.52.0", ] [[package]] @@ -1094,6 +1928,12 @@ dependencies = [ "base64", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.10" @@ -1132,23 +1972,40 @@ dependencies = [ ] [[package]] -name = "serde" -version = "1.0.137" +name = "semver" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", +] + +[[package]] +name = "serde_json" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +dependencies = [ + "itoa 1.0.6", + "ryu", + "serde", ] [[package]] @@ -1162,6 +2019,27 @@ dependencies = [ "digest", ] +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -1184,12 +2062,38 @@ dependencies = [ "wide", ] +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "static_assertions", + "version_check", +] + [[package]] name = "socket2" version = "0.4.9" @@ -1217,6 +2121,15 @@ dependencies = [ "unicode_categories", ] +[[package]] +name = "sqlparser" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eaa1e88e78d2c2460d78b7dc3f0c08dbb606ab4222f9aff36f420d36e307d87" +dependencies = [ + "log", +] + [[package]] name = "sqlx" version = "0.6.2" @@ -1233,9 +2146,9 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbc16ddba161afc99e14d1713a453747a2b07fc097d2009f4c300ec99286105" dependencies = [ - "ahash", - "atoi", - "bitflags", + "ahash 0.7.6", + "atoi 1.0.0", + "bitflags 1.3.2", "byteorder", "bytes", "crc", @@ -1250,7 +2163,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap", + "indexmap 1.9.2", "itoa 1.0.6", "libc", "log", @@ -1288,7 +2201,7 @@ dependencies = [ "sha2", "sqlx-core", "sqlx-rt", - "syn", + "syn 1.0.95", "url", ] @@ -1303,6 +2216,18 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + [[package]] name = "stringprep" version = "0.1.2" @@ -1319,6 +2244,38 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.95", +] + +[[package]] +name = "strum_macros" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.38", +] + [[package]] name = "syn" version = "1.0.95" @@ -1330,6 +2287,50 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sysinfo" +version = "0.29.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a18d114d420ada3a891e6bc8e96a2023402203296a47cdd65083377dad18ba5" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "winapi", +] + +[[package]] +name = "target-features" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb5fa503293557c5158bd215fdc225695e567a77e453f5d4452a50a193969bd" + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.4.1", + "rustix 0.38.28", + "windows-sys 0.48.0", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -1356,18 +2357,7 @@ checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "syn 1.0.95", ] [[package]] @@ -1402,7 +2392,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1413,7 +2403,7 @@ checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.95", ] [[package]] @@ -1512,12 +2502,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1545,7 +2529,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.95", "wasm-bindgen-shared", ] @@ -1567,7 +2551,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.95", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1654,7 +2638,25 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.1", +] + +[[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 0.52.0", ] [[package]] @@ -1663,13 +2665,43 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_msvc 0.42.1", +] + +[[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]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -1678,38 +2710,157 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "xxhash-rust" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9828b178da53440fa9c766a3d2f73f7cf5d0ac1fe3980c1e5018d899fd19e07b" + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 04f9503..499dbdb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,12 +18,14 @@ clap = { version = "4.1.8", features = ["derive"] } anyhow = "1.0" itertools = "0.10.3" -chrono = {version = "0.4.23", features = ["default", "serde"]} +chrono = {version = "0.4.31", features = ["default", "serde"]} rayon = "1.6.0" tokio = { version = "1.26.0", features = ["full"] } -sqlx = { version = "0.6", features = [ "runtime-tokio-rustls", "mssql" ] } +sqlx = { version = "0.6", features = [ "runtime-tokio-rustls", "mssql", "any" ] } rmp-serde = "1.1.1" +tempfile = "3.7.0" +polars = {version = "0.32.1", features = ["lazy", "performant", "streaming", "cse", "dtype-datetime"]} # More info on targets: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target [lib] diff --git a/FastCoster/FastCoster.xcodeproj/project.pbxproj b/FastCoster/FastCoster.xcodeproj/project.pbxproj index d2840f2..7733f2e 100644 --- a/FastCoster/FastCoster.xcodeproj/project.pbxproj +++ b/FastCoster/FastCoster.xcodeproj/project.pbxproj @@ -12,6 +12,14 @@ 5A1986FB2996502C00FA0471 /* FileButtonSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A1986FA2996502C00FA0471 /* FileButtonSelector.swift */; }; 5A450751298CE6D500E3D402 /* CsvDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A450750298CE6D500E3D402 /* CsvDocument.swift */; }; 5A45075B298D01EF00E3D402 /* libcoster_rs.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A45075A298D01EF00E3D402 /* libcoster_rs.a */; }; + 5A53D5742BE4B4FB00563893 /* FileNodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A53D5732BE4B4FB00563893 /* FileNodeView.swift */; }; + 5A53D5772BE4B98300563893 /* SwiftCSV in Frameworks */ = {isa = PBXBuildFile; productRef = 5A53D5762BE4B98300563893 /* SwiftCSV */; }; + 5A53D5792BE4C0C300563893 /* CsvEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A53D5782BE4C0C300563893 /* CsvEditor.swift */; }; + 5A53D57B2BE4C1D400563893 /* OutputFilesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A53D57A2BE4C1D400563893 /* OutputFilesView.swift */; }; + 5A53D5822BE507AD00563893 /* ChartEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A53D5812BE507AD00563893 /* ChartEditor.swift */; }; + 5A53D5842BE507FF00563893 /* ChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A53D5832BE507FF00563893 /* ChartView.swift */; }; + 5A53D5892BE5182C00563893 /* Tasks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A53D5882BE5182C00563893 /* Tasks.swift */; }; + 5A53D58B2BE518CA00563893 /* Graph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A53D58A2BE518CA00563893 /* Graph.swift */; }; 5ADD9F2D298A713300F998F5 /* FastCosterApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADD9F2C298A713300F998F5 /* FastCosterApp.swift */; }; 5ADD9F2F298A713300F998F5 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADD9F2E298A713300F998F5 /* ContentView.swift */; }; 5ADD9F31298A713400F998F5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5ADD9F30298A713400F998F5 /* Assets.xcassets */; }; @@ -48,6 +56,13 @@ 5A450755298CFFE400E3D402 /* create-lib.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "create-lib.sh"; sourceTree = ""; }; 5A450756298D00AE00E3D402 /* remove-lib.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "remove-lib.sh"; sourceTree = ""; }; 5A45075A298D01EF00E3D402 /* libcoster_rs.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcoster_rs.a; path = "../costerrs/target/aarch64-apple-ios/release/libcoster_rs.a"; sourceTree = ""; }; + 5A53D5732BE4B4FB00563893 /* FileNodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileNodeView.swift; sourceTree = ""; }; + 5A53D5782BE4C0C300563893 /* CsvEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CsvEditor.swift; sourceTree = ""; }; + 5A53D57A2BE4C1D400563893 /* OutputFilesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputFilesView.swift; sourceTree = ""; }; + 5A53D5812BE507AD00563893 /* ChartEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartEditor.swift; sourceTree = ""; }; + 5A53D5832BE507FF00563893 /* ChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartView.swift; sourceTree = ""; }; + 5A53D5882BE5182C00563893 /* Tasks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tasks.swift; sourceTree = ""; }; + 5A53D58A2BE518CA00563893 /* Graph.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Graph.swift; sourceTree = ""; }; 5ADD9F29298A713300F998F5 /* FastCoster.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FastCoster.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5ADD9F2C298A713300F998F5 /* FastCosterApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FastCosterApp.swift; sourceTree = ""; }; 5ADD9F2E298A713300F998F5 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -67,6 +82,7 @@ buildActionMask = 2147483647; files = ( 5A45075B298D01EF00E3D402 /* libcoster_rs.a in Frameworks */, + 5A53D5772BE4B98300563893 /* SwiftCSV in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -106,6 +122,24 @@ name = Frameworks; sourceTree = ""; }; + 5A53D5802BE4C26A00563893 /* Charts */ = { + isa = PBXGroup; + children = ( + 5A53D5812BE507AD00563893 /* ChartEditor.swift */, + 5A53D5832BE507FF00563893 /* ChartView.swift */, + ); + path = Charts; + sourceTree = ""; + }; + 5A53D5852BE50C7B00563893 /* Model */ = { + isa = PBXGroup; + children = ( + 5A53D5882BE5182C00563893 /* Tasks.swift */, + 5A53D58A2BE518CA00563893 /* Graph.swift */, + ); + path = Model; + sourceTree = ""; + }; 5ADD9F20298A713300F998F5 = { isa = PBXGroup; children = ( @@ -131,6 +165,8 @@ 5ADD9F2B298A713300F998F5 /* FastCoster */ = { isa = PBXGroup; children = ( + 5A53D5852BE50C7B00563893 /* Model */, + 5A53D5802BE4C26A00563893 /* Charts */, 5ADD9F2C298A713300F998F5 /* FastCosterApp.swift */, 5ADD9F2E298A713300F998F5 /* ContentView.swift */, 5ADD9F30298A713400F998F5 /* Assets.xcassets */, @@ -140,6 +176,9 @@ 5A1986F62996436500FA0471 /* OverheadAllocation.swift */, 5A1986F82996436D00FA0471 /* MoveMoney.swift */, 5A1986FA2996502C00FA0471 /* FileButtonSelector.swift */, + 5A53D5732BE4B4FB00563893 /* FileNodeView.swift */, + 5A53D5782BE4C0C300563893 /* CsvEditor.swift */, + 5A53D57A2BE4C1D400563893 /* OutputFilesView.swift */, ); path = FastCoster; sourceTree = ""; @@ -187,6 +226,9 @@ dependencies = ( ); name = FastCoster; + packageProductDependencies = ( + 5A53D5762BE4B98300563893 /* SwiftCSV */, + ); productName = FastCoster; productReference = 5ADD9F29298A713300F998F5 /* FastCoster.app */; productType = "com.apple.product-type.application"; @@ -259,6 +301,9 @@ Base, ); mainGroup = 5ADD9F20298A713300F998F5; + packageReferences = ( + 5A53D5752BE4B98300563893 /* XCRemoteSwiftPackageReference "SwiftCSV" */, + ); productRefGroup = 5ADD9F2A298A713300F998F5 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -344,11 +389,18 @@ buildActionMask = 2147483647; files = ( 5A1986FB2996502C00FA0471 /* FileButtonSelector.swift in Sources */, + 5A53D58B2BE518CA00563893 /* Graph.swift in Sources */, 5ADD9F2F298A713300F998F5 /* ContentView.swift in Sources */, 5A1986F92996436D00FA0471 /* MoveMoney.swift in Sources */, + 5A53D57B2BE4C1D400563893 /* OutputFilesView.swift in Sources */, 5ADD9F2D298A713300F998F5 /* FastCosterApp.swift in Sources */, 5A450751298CE6D500E3D402 /* CsvDocument.swift in Sources */, + 5A53D5822BE507AD00563893 /* ChartEditor.swift in Sources */, + 5A53D5842BE507FF00563893 /* ChartView.swift in Sources */, + 5A53D5792BE4C0C300563893 /* CsvEditor.swift in Sources */, + 5A53D5892BE5182C00563893 /* Tasks.swift in Sources */, 5A1986F72996436500FA0471 /* OverheadAllocation.swift in Sources */, + 5A53D5742BE4B4FB00563893 /* FileNodeView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -524,7 +576,7 @@ "LIBRARY_SEARCH_PATHS[arch=*]" = "${DERIVED_FILES_DIR}"; MACOSX_DEPLOYMENT_TARGET = 13.1; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.Vato.FastCoster; + PRODUCT_BUNDLE_IDENTIFIER = dev.michaelpivato.FastCoster; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; @@ -564,7 +616,7 @@ "LIBRARY_SEARCH_PATHS[arch=*]" = "${DERIVED_FILES_DIR}"; MACOSX_DEPLOYMENT_TARGET = 13.1; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.Vato.FastCoster; + PRODUCT_BUNDLE_IDENTIFIER = dev.michaelpivato.FastCoster; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; @@ -705,6 +757,25 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 5A53D5752BE4B98300563893 /* XCRemoteSwiftPackageReference "SwiftCSV" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/swiftcsv/SwiftCSV.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.9.1; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 5A53D5762BE4B98300563893 /* SwiftCSV */ = { + isa = XCSwiftPackageProductDependency; + package = 5A53D5752BE4B98300563893 /* XCRemoteSwiftPackageReference "SwiftCSV" */; + productName = SwiftCSV; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 5ADD9F21298A713300F998F5 /* Project object */; } diff --git a/FastCoster/FastCoster/Charts/ChartEditor.swift b/FastCoster/FastCoster/Charts/ChartEditor.swift new file mode 100644 index 0000000..a041b75 --- /dev/null +++ b/FastCoster/FastCoster/Charts/ChartEditor.swift @@ -0,0 +1,18 @@ +// +// ChartEditor.swift +// FastCoster +// +// Created by Michael Pivato on 3/5/2024. +// + +import SwiftUI + +struct ChartEditor: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +#Preview { + ChartEditor() +} diff --git a/FastCoster/FastCoster/Charts/ChartView.swift b/FastCoster/FastCoster/Charts/ChartView.swift new file mode 100644 index 0000000..97b4723 --- /dev/null +++ b/FastCoster/FastCoster/Charts/ChartView.swift @@ -0,0 +1,19 @@ +// +// ChartView.swift +// FastCoster +// +// Created by Michael Pivato on 3/5/2024. +// + +import SwiftUI + +struct ChartView: View { + // View the chart for the given file and configuration: https://developer.apple.com/documentation/Charts + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +#Preview { + ChartView() +} diff --git a/FastCoster/FastCoster/ContentView.swift b/FastCoster/FastCoster/ContentView.swift index 4028371..f180d5e 100644 --- a/FastCoster/FastCoster/ContentView.swift +++ b/FastCoster/FastCoster/ContentView.swift @@ -11,6 +11,7 @@ enum ProcessType: String, Hashable { case MoveMoney = "Move Money" case OverheadAllocation = "Overhead Allocation" + // TODO: This needs to be the list of graphs static let values = [MoveMoney, OverheadAllocation] } @@ -37,6 +38,7 @@ struct ContentView: View { } } } + // TODO: Button to add a new graph } diff --git a/FastCoster/FastCoster/CsvEditor.swift b/FastCoster/FastCoster/CsvEditor.swift new file mode 100644 index 0000000..78a95b3 --- /dev/null +++ b/FastCoster/FastCoster/CsvEditor.swift @@ -0,0 +1,20 @@ +// +// CsvEditor.swift +// FastCoster +// +// Created by Michael Pivato on 3/5/2024. +// + +import SwiftUI + +struct CsvEditor: View { + // A table to view data in a file: https://developer.apple.com/documentation/SwiftUI/Table + // It's fine to load it all into memory to begin with, we'll probably want to change that later though. + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +#Preview { + CsvEditor() +} diff --git a/FastCoster/FastCoster/FileNodeView.swift b/FastCoster/FastCoster/FileNodeView.swift new file mode 100644 index 0000000..64a8dcb --- /dev/null +++ b/FastCoster/FastCoster/FileNodeView.swift @@ -0,0 +1,33 @@ +// +// FileNode.swift +// FastCoster +// +// Created by Michael Pivato on 3/5/2024. +// + +import SwiftUI + +struct FileNodeView: View { + @State private var showPicker = false + @State private var selectedFileUrl: URL? + var body: some View { + // Should basically show a file selector. + Button { + showPicker.toggle() + } label: { + Text("Select File") + }.fileImporter(isPresented: $showPicker, allowedContentTypes: [.commaSeparatedText]) { result in + + switch result { + case .success(let fileUrl): + selectedFileUrl = fileUrl + case .failure(let error): + print(error) + } + }.padding() + } +} + +#Preview { + FileNodeView() +} diff --git a/FastCoster/FastCoster/Model/Graph.swift b/FastCoster/FastCoster/Model/Graph.swift new file mode 100644 index 0000000..94a19dd --- /dev/null +++ b/FastCoster/FastCoster/Model/Graph.swift @@ -0,0 +1,23 @@ +// +// Graph.swift +// FastCoster +// +// Created by Michael Pivato on 3/5/2024. +// + +import Foundation +// JSON for saving/loading configuration: https://www.avanderlee.com/swift/json-parsing-decoding/ +struct Node: Codable { + var id: Int + var info: NodeInfo + var dependentNodeIds: [Int] + + func hasDependentNodes() -> Bool { + return !dependentNodeIds.isEmpty + } +} + +struct Graph: Codable { + var name: String + var nodes: [Node] +} diff --git a/FastCoster/FastCoster/Model/Tasks.swift b/FastCoster/FastCoster/Model/Tasks.swift new file mode 100644 index 0000000..8d1091c --- /dev/null +++ b/FastCoster/FastCoster/Model/Tasks.swift @@ -0,0 +1,118 @@ +// +// InputFile.swift +// FastCoster +// +// Created by Michael Pivato on 3/5/2024. +// + +import Foundation + +struct NodeInfo: Codable { + var name: String; + var outputFiles: [String] + var configuration: NodeConfiguration +} + +// Need to check if enums with data actually works with json serialisation/deserialisation, otherwise +// can look into binary serialisation/deserialisation instead +enum NodeConfiguration: Codable { + case FileNode + case MoveMoneyNode(MoveMoneyNode) + case MergeNode(MergeNode) + case DeriveNode(DeriveNode) +} + +enum MoveMoneyAmoutType: String, Codable { + case Percent, Amount +} + +struct MoveMoneyRule: Codable { + let fromAccout: String + let fromCC: String + let toAccount: String + let toCC: String + let value: Double + let type: MoveMoneyAmoutType +} + +struct MoveMoneyNode: Codable { + var departmentsPath: String + var accountsPath: String + var glPath: String + var rules: [MoveMoneyRule] +} + +enum JoinType: Codable { + case Left, Inner, Right +} + +struct MergeJoin: Codable { + var type: JoinType + var leftColumnName: String + var rightColumnName: String +} + +struct MergeNode: Codable { + var inputFiles: [String] + var joins: [MergeJoin] +} + +enum DeriveColumnType: Codable { + case Column(String) + case Constant(String) +} + +struct MapOperation: Codable { + var mappedValue: String +} + +enum DatePart: Codable { + case Year, Month, Week, Day, Hour, Minute, Secod +} + +enum SplitType: Codable { + case DateTime(String, DatePart) + case Numeric(String, Int) +} + +enum MatchComparisonType: Codable { + case Equal, GreaterThan, LessThan +} + +enum DeriveOperation: Codable { + case Concat([DeriveColumnType]) + case Add([DeriveColumnType]) + case Multiply([DeriveColumnType]) + case Subtract(DeriveColumnType, DeriveColumnType) + case Divide(DeriveColumnType, DeriveColumnType) + case Map(String, [MapOperation]) + case Split(String, SplitType) +} + +struct DeriveFilter: Codable { + var columnName: String + var comparator: MatchComparisonType + var matchValue: String +} + +struct DeriveRule: Codable { + // Should this actually be an array though? It think it's fine? + var operations: [DeriveOperation] + // Filter to only specific values if required, if empty every value is considered a match + var filters: [DeriveFilter] +} + +struct DeriveNode: Codable { + var rules: [DeriveRule] +} + + +// Example json serialisation +func tryJson() { + do { + let json = try JSONEncoder().encode(NodeInfo(name: "", outputFiles: [], configuration: NodeConfiguration.FileNode)) + let decoded = try JSONDecoder().decode(NodeInfo.self, from: json) + }catch { + + } +} diff --git a/FastCoster/FastCoster/OutputFilesView.swift b/FastCoster/FastCoster/OutputFilesView.swift new file mode 100644 index 0000000..11a281c --- /dev/null +++ b/FastCoster/FastCoster/OutputFilesView.swift @@ -0,0 +1,19 @@ +// +// OutputFilesView.swift +// FastCoster +// +// Created by Michael Pivato on 3/5/2024. +// + +import SwiftUI + +struct OutputFilesView: View { + // List of files, with links to open a file editor to edit the linked files + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +#Preview { + OutputFilesView() +} diff --git a/FastCoster/FastCoster/OverheadAllocation.swift b/FastCoster/FastCoster/OverheadAllocation.swift index 532575f..7fb3e19 100644 --- a/FastCoster/FastCoster/OverheadAllocation.swift +++ b/FastCoster/FastCoster/OverheadAllocation.swift @@ -8,6 +8,7 @@ import SwiftUI struct OverheadAllocation: View { + // TODO: Refactor to take inputs from another task instead @State private var lines: String? @State private var accounts: String? @State private var areas: String? diff --git a/src/bin/agent2/main.rs b/src/bin/agent2/main.rs index dd515ae..7fba9bb 100644 --- a/src/bin/agent2/main.rs +++ b/src/bin/agent2/main.rs @@ -1,4 +1,5 @@ -use sqlx::mssql::MssqlPoolOptions; +use coster_rs::upload_to_db; +use sqlx::{any::AnyPoolOptions, mssql::MssqlPoolOptions}; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -8,11 +9,11 @@ async fn main() -> anyhow::Result<()> { let database = ""; // USing sqlx: https://github.com/launchbadge/sqlx let connection_string = format!("mssq://{}:{}@{}/{}", user, password, host, database); - let pool = MssqlPoolOptions::new() + let pool = AnyPoolOptions::new() .max_connections(20) .connect(&connection_string) .await?; - // sqlx::query_as("") - // connection. + + // upload_to_db::upload_file_bulk(&pool, &"".to_owned(), &"".to_owned(), None, "".to_owned()).await?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 4695db3..dc94163 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +// TODO: Module api can probably use a cleanup mod move_money; pub use self::move_money::*; use std::ffi::c_char; @@ -9,7 +10,7 @@ pub use self::overhead_allocation::*; mod products; pub use self::products::create_products; -pub use self::products::CreateProductInputs; +pub use self::products::csv::SourceType; mod shared_models; pub use self::shared_models::*; @@ -18,6 +19,8 @@ pub mod link; pub mod filter; +pub mod upload_to_db; + mod io; #[no_mangle] @@ -56,6 +59,33 @@ pub extern "C" fn move_money_from_text( // This looks like exactly what I'm doing too: https://mozilla.github.io/firefox-browser-architecture/experiments/2017-09-06-rust-on-ios.htmlcar } +#[no_mangle] +pub extern "C" fn move_money_from_file( + rules_file: *const c_char, + lines: *const c_char, + accounts: *const c_char, + cost_centres: *const c_char, + output_path: *const c_char, + use_numeric_accounts: bool, +) { + let mut output_writer = csv::Writer::from_writer(vec![]); + let safe_rules = unwrap_c_char(rules_file); + let safe_lines = unwrap_c_char(lines); + let safe_accounts = unwrap_c_char(accounts); + let safe_cost_centres = unwrap_c_char(cost_centres); + move_money_2() + // move_money( + // , + // &mut csv::Reader::from_reader(safe_lines.to_str().unwrap()), + // &mut csv::Reader::from_reader(safe_accounts.to_bytes()), + // &mut csv::Reader::from_reader(safe_cost_centres.to_bytes()), + // &mut output_writer, + // use_numeric_accounts, + // false, + // ) + // .expect("Failed to move money"); +} + #[no_mangle] pub unsafe extern "C" fn move_money_from_text_free(s: *mut c_char) { unsafe { diff --git a/src/main.rs b/src/main.rs index cd1664e..57c8848 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ -use std::{fs::File, io::BufWriter, path::PathBuf}; +use std::{collections::HashMap, fs::File, io::BufWriter, path::PathBuf}; use clap::{Parser, Subcommand}; -use coster_rs::CreateProductInputs; +use coster_rs::{create_products::InputFile, SourceType}; #[derive(Parser)] #[command(name = "coster-rs")] @@ -95,6 +95,12 @@ enum Commands { #[arg(short, long, value_name = "FILE")] diagnoses: PathBuf, + #[arg(short, long, value_name = "FILE")] + patients: PathBuf, + + #[arg(short, long, value_name = "FILE")] + revenues: PathBuf, + #[arg(short, long, value_name = "FILE")] output: PathBuf, }, @@ -175,18 +181,68 @@ fn main() -> anyhow::Result<()> { transfers, procedures, diagnoses, + patients, + revenues, output, - } => coster_rs::create_products( - &mut csv::Reader::from_path(definitions)?, - CreateProductInputs { - encounters: csv::Reader::from_path(encounters)?, - services: csv::Reader::from_path(services)?, - transfers: csv::Reader::from_path(transfers)?, - procedures: csv::Reader::from_path(procedures)?, - diagnoses: csv::Reader::from_path(diagnoses)?, - }, - &mut csv::Writer::from_path(output)?, - 1000000, - ), + } => { + let mut inputs = HashMap::new(); + inputs.insert( + SourceType::Encounter, + InputFile { + file_path: encounters, + joins: HashMap::new(), + date_order_column: Some("StartDateTime".to_owned()), + }, + ); + inputs.insert( + SourceType::Service, + InputFile { + file_path: services, + joins: HashMap::new(), + date_order_column: Some("StartDateTime".to_owned()), + }, + ); + inputs.insert( + SourceType::Transfer, + InputFile { + file_path: transfers, + joins: HashMap::new(), + date_order_column: Some("StartDateTime".to_owned()), + }, + ); + inputs.insert( + SourceType::CodingProcedure, + InputFile { + file_path: procedures, + joins: HashMap::new(), + date_order_column: Some("ProcedureDateTime".to_owned()), + }, + ); + inputs.insert( + SourceType::CodingDiagnosis, + InputFile { + file_path: diagnoses, + joins: HashMap::new(), + date_order_column: None, + }, + ); + inputs.insert( + SourceType::Patient, + InputFile { + file_path: patients, + joins: HashMap::new(), + date_order_column: None, + }, + ); + inputs.insert( + SourceType::Revenue, + InputFile { + file_path: revenues, + joins: HashMap::new(), + date_order_column: None, + }, + ); + coster_rs::create_products::create_products_polars(definitions, vec![], output) + } } } diff --git a/src/overhead_allocation.rs b/src/overhead_allocation.rs index ac2e2f4..898a149 100644 --- a/src/overhead_allocation.rs +++ b/src/overhead_allocation.rs @@ -3,6 +3,7 @@ use std::{ io::Read, }; +use csv::Reader; use itertools::Itertools; use nalgebra::{DMatrix, Dynamic, LU}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; @@ -93,9 +94,6 @@ pub fn reciprocal_allocation, areas: &mut csv::Reader, cost_centres: &mut csv::Reader, - // TODO: Receiver method rather than this writer that can accept - // the raw float results, so we can write in an alternate format - // that more accurately represents the values on disk output: &mut impl RecordSerializer, use_numeric_accounts: bool, exclude_negative_allocation_statistics: bool, @@ -115,28 +113,8 @@ where .deserialize() .collect::, csv::Error>>()?; - let all_accounts_sorted: Vec = if use_numeric_accounts { - accounts - .deserialize::() - .filter(|account| { - account.is_ok() && account.as_ref().unwrap().account_type == account_type - }) - .map(|line| line.unwrap().code.clone().parse::().unwrap()) - .unique() - .sorted() - .map(|account| account.to_string()) - .collect() - } else { - accounts - .deserialize::() - .filter(|account| { - account.is_ok() && account.as_ref().unwrap().account_type == account_type - }) - .map(|line| line.unwrap().code.clone()) - .unique() - .sorted() - .collect() - }; + let all_accounts_sorted: Vec = + get_accounts_sorted(use_numeric_accounts, &account_type, accounts); let allocation_statistics = allocation_statistics .deserialize::() @@ -266,7 +244,8 @@ where let mut limited_ccs: Vec = Vec::new(); for limit_to in limit_tos.iter() { // TODO: It is technically possible to have more than one limit to (I think?) for a slot, so consider eventually splitting this and doing a foreach - let limit_value = area.get(&("LimitTo:".to_owned() + limit_to)).unwrap(); + // Also there's an exclude criteria that needs to be considered, which can exclude a rollup that would normally get included + let limit_value = area.get(&(format!("LimitTo:{}", limit_to))).unwrap(); if limit_value.is_empty() { continue; } @@ -274,7 +253,7 @@ where limited_ccs.push(limit_value.clone()); } else { let mut found_ccs = rollups - .get(&("RollupSlot:".to_owned() + limit_to)) + .get(&(format!("RollupSlot:{}", limit_to))) .map(|rollups| rollups.get(limit_value)) .flatten() .unwrap() @@ -293,35 +272,24 @@ where let mut totals: Vec<(String, String, f64)> = overhead_ccs .par_iter() .flat_map(|overhead_cc| { - let limited = limited_ccs + limited_ccs .iter() - .filter(|other_cc| { - totals.contains_key(&( - // TODO: This looks terrible - other_cc.clone().clone(), - allocation_statistic.clone(), - )) - }) - .map(|other_cc| { - ( - overhead_cc.clone(), - other_cc.clone(), - totals - .get(&(other_cc.clone(), allocation_statistic.clone())) - .map(|f| *f) - .unwrap(), - ) + .map(|other_cc| (other_cc.clone(), allocation_statistic.clone())) + .filter_map(|(other_cc, allocation_statistic)| { + let combined_stat = (other_cc, allocation_statistic); + if !totals.contains_key(&combined_stat) { + None + } else { + Some(( + overhead_cc.clone(), + combined_stat.0.clone(), + totals.get(&combined_stat).map(|f| *f).unwrap(), + )) + } }) .filter(|(_, _, value)| *value != 0.) .filter(|(from_cc, to_cc, _)| from_cc != to_cc) - .collect_vec(); - // TODO: Put me back if rayon proves problematic - // Insert is safe, since an overhead cc can only be a part of one area - // overhead_cc_totals.insert( - // overhead_cc.clone(), - // limited.iter().map(|(_, _, value)| value).sum(), - // ); - limited + .collect_vec() }) .collect(); overhead_other_total.append(&mut totals); @@ -355,24 +323,41 @@ where } // Export initial totals for operating departments - if show_from { - for line in lines.iter() { - if !overhead_ccs.contains(&line.department) { + for line in lines.iter() { + // TODO: Should we still output accounts that aren't in the accounts file anyway? + if all_accounts_sorted + .iter() + .find(|account| **account == line.account) + .is_some() + && !overhead_ccs.contains(&line.department) + && (show_from + // When we write out the final amounts rather than changes, + // ensure we still output departments that won't be receiving + // any costs. + || !overhead_other_total + .iter() + .any(|(_, to_department, _)| *to_department == line.department)) + { + if show_from { output.serialize(MovedAmount { account: line.account.clone(), cost_centre: line.department.clone(), value: line.value, from_cost_centre: line.department.clone(), })?; + } else { + output.serialize(CsvCost { + account: line.account.clone(), + department: line.department.clone(), + value: line.value, + })?; } } } // Finally, for each cc match total produced previously, sum the overhead cc where overhead cc appears in other cc, then // divide the other cc by this summed amount (thus getting the relative cost) - - // At this point we convert to our format that's actually used, need to somehow recover the to_cc_type... could build that out from the areas - + // At this point we convert to our format that's actually used in overhead allocation let allocation_rules: Vec = overhead_other_total .iter() .map( @@ -389,6 +374,8 @@ where ) .collect(); + // TODO: THIS CAN BE WRONG WHEN USING A FILE WITH ALL PASSES, for now ensure the input movement + // file only contains the final pass/outputs. let mut initial_account_costs: HashMap> = HashMap::new(); for line in lines { // Only include accounts we've already filtered on (i.e. by account type) @@ -430,7 +417,7 @@ where for cost in results { for department in cost.summed_department_costs { // Any consumers should assume missing cc/account value was 0 (we already ignore overhead, as they all 0 out) - if department.value > 0.00001 || department.value < -0.00001 { + if department.value != 0_f64 { output.serialize(CsvCost { account: cost.account.clone(), department: department.department, @@ -443,6 +430,35 @@ where Ok(()) } +fn get_accounts_sorted( + use_numeric_accounts: bool, + account_type: &String, + accounts: &mut Reader, +) -> Vec { + if use_numeric_accounts { + accounts + .deserialize::() + .filter(|account| { + account.is_ok() && account.as_ref().unwrap().account_type == *account_type + }) + .map(|line| line.unwrap().code.clone().parse::().unwrap()) + .unique() + .sorted() + .map(|account| account.to_string()) + .collect() + } else { + accounts + .deserialize::() + .filter(|account| { + account.is_ok() && account.as_ref().unwrap().account_type == *account_type + }) + .map(|line| line.unwrap().code.clone()) + .unique() + .sorted() + .collect() + } +} + fn split_allocation_statistic_range( allocation_statistic: &CsvAllocationStatistic, accounts_sorted: &Vec, @@ -661,7 +677,7 @@ fn solve_reciprocal_no_from( &operating_slice_costs, ); - // // Borrow so we don't move between loops + // Borrow so we don't move between loops let operating_overhead_mappings = &operating_overhead_mappings_mat; let calculated_overheads = &calculated_overheads; @@ -682,7 +698,6 @@ fn solve_reciprocal_no_from( // Redistribute floating point errors (only for ccs we actually allocated from/to) // Considered removing this since redistribution should be done in cost driver calculations, however since that usually // does nothing, we may as well keep this just in case. - // TODO: Not sure we actually need this, would probably be better to have a better storage format than // csv/string conversions // let initial_cost: f64 = total_costs @@ -696,7 +711,6 @@ fn solve_reciprocal_no_from( // .sum(); // let new_cost: f64 = converted_result.iter().map(|cost| cost.value).sum(); // let diff = initial_cost - new_cost; - AccountCost { account: total_costs.account.clone(), summed_department_costs: converted_result @@ -753,7 +767,7 @@ fn solve_reciprocal_with_from( account: total_costs.account.clone(), cost_centre: department.clone(), value, - from_cost_centre: department.clone(), + from_cost_centre: overhead_department_cost.department.clone(), }) .filter(|cost| cost.value != 0_f64) .collect::>() diff --git a/src/products/create_products.rs b/src/products/create_products.rs index f868aa8..93bb0b8 100644 --- a/src/products/create_products.rs +++ b/src/products/create_products.rs @@ -1,13 +1,22 @@ use std::{ - collections::HashMap, - io::{Read, Write}, + collections::{HashMap, HashSet}, + path::PathBuf, }; +use anyhow::anyhow; use chrono::NaiveDateTime; -use csv::Position; +use itertools::Itertools; +// inluding dsl works better for completion with rust analyzer +use polars::lazy::dsl::*; +use polars::prelude::*; use serde::Serialize; -use super::csv::{read_definitions, BuildFrom, ConstraintType, Definition}; +use super::csv::{read_definitions, Component, Definition, FileJoin, SourceType}; + +// TODO: Polars suggests this, but docs suggest it doesn't have very good platform support +//use jemallocator::Jemalloc; +// #[global_allocator] +// static GLOBAL: Jemalloc = Jemalloc; #[derive(Debug, Serialize, Default)] struct Product { @@ -28,120 +37,120 @@ struct Product { source_allocated_amount: Option, } -pub struct CreateProductInputs -where - E: Read, - S: Read, - T: Read, - P: Read, - Di: Read, -{ - pub encounters: csv::Reader, - pub services: csv::Reader, - pub transfers: csv::Reader, - pub procedures: csv::Reader

, - pub diagnoses: csv::Reader, +pub struct InputFile { + pub file_path: PathBuf, + pub joins: HashMap, + // if not specified, then don't allow change in type builds, as there's no way to detect changes over time + pub date_order_column: Option, } -// TODO: Build from linked dataset is pretty hard, it potentially requires knowing everything abuot the previous year's -// cosing run (BSCO, Dataset_Encounter_Cache, etc). -pub fn create_products( - definitions: &mut csv::Reader, - product_inputs: CreateProductInputs, - // TODO: Looks kind of bad, any other way around it? I'd rather not have to depend on crossbeam as well - output: &mut csv::Writer, - // TODO: Default to 10 million or something sane - batch_size: usize, -) -> anyhow::Result<()> -where - D: Read, - E: Read, - S: Read, - T: Read, - P: Read, - Di: Read, - // TODO: Looks kind of bad, any other way around it? I'd rather not have to depend on crossbeam as well - O: Write + Send + 'static, -{ - let mut all_definitions: HashMap = read_definitions(definitions)?; - // Partition the rules by the build from type, so that we'll run all the rules at once for a particular file, which should be much faster - // then opening files and scanning one at a time. Could also do batches in files - - let mut mapped_definitions: HashMap> = HashMap::new(); - for (_, definition) in all_definitions { - mapped_definitions - .entry(definition.build_from) - .or_insert(vec![]) - .push(definition); +pub fn create_products_polars( + definitions_path: PathBuf, + inputs: Vec, + output_path: PathBuf, +) -> anyhow::Result<()> { + let definitions = read_definitions(&mut csv::Reader::from_path(definitions_path)?)?; + let definitions = definitions.values().collect_vec(); + for definition in definitions { + build_polars(definition, &inputs, &output_path)?; } - - // Now whenever we want to produce a built service, just write it to tx. - - // Note that rust csv can seek to a certain position, so we can read in a batch from a reader, then - // seek to that position in the reader (or position 0) if we couldn't find a particular record. - // Alternatively, we could store an index of all records (e.g. encounter numbers) that map to their position in the reader, - // so we can quickly seek to the appropriate index and read the record. - // https://docs.rs/csv/latest/csv/struct.Reader.html#method.seek - // Store encounter positions in file, so that later when we read through transfers/whatever we can easily - // seak to the correct position quickly in case we have a cache miss - let mut encounter_positions: HashMap = HashMap::new(); - - // TODO: Alternative to storing encounter positions would be to sort portions of the file bits at a time (I think it's called a merge sort?). - - // TODO: Try with and without rayon, should be able to help I think as we're going through so much data sequentially, - // although we're still likely to be bottlenecked by just write-speed - let mut encounters = product_inputs.encounters; - let headers = encounters.headers()?.clone(); - - for encounter in encounters.records() { - let encounter = encounter?; - let position = encounter.position().unwrap(); - let encounter: HashMap = encounter.deserialize(Some(&headers))?; - encounter_positions.insert( - encounter.get("EncounterNumber").unwrap().to_string(), - position.clone(), - ); - // TODO: For each encounter definition, check this fits the filter criteria/constraints, - // and - let definitions = mapped_definitions.get(&BuildFrom::Encounter).unwrap(); - for definition in definitions { - let matching_filter = (definition.filters.is_empty() - || definition.filters.iter().any(|filter| { - let field = encounter.get(filter.field.as_str()); - if field.is_none() { - return false; - } - let field = field.unwrap(); - if filter.equal { - filter.value == *field - } else { - filter.value != *field - } - })) - && (definition.constraints.is_empty() - || definition.constraints.iter().any(|constraint| { - let field = encounter.get(constraint.field.as_str()); - if field.is_none() { - return false; - } - let field = field.unwrap(); - // TODO: Is this just number/datetime? Should probably be an enum? It's not, seems to be E in the test data - let field_type = &constraint.source_type; - match constraint.constraint_type { - ConstraintType::Equal => *field == constraint.value, - _ => false, - } - })); - if matching_filter { - // Generate the service code - } - } - - // TODO: Generate the built service - output.serialize(Product::default())?; - } - - // Now do the same with transfers, services, etc, referencing the encounter reader by using the - // indexes in encounter_positions + Ok(()) +} + +pub fn build_polars( + definition: &Definition, + inputs: &Vec, + output_path: &PathBuf, +) -> anyhow::Result<()> { + // 1. Apply filters to limit encounters + let filter = definition + .filters + .iter() + .map(|filter| { + let col = col(&filter.field); + match filter.filter_type { + super::csv::FilterType::Equal => col.eq(lit(filter.value.clone())), + super::csv::FilterType::GreaterThan => col.gt(lit(filter.value.clone())), + super::csv::FilterType::GreaterThanOrEqualTo => { + col.gt_eq(lit(filter.value.clone())) + } + super::csv::FilterType::LessThan => col.lt(lit(filter.value.clone())), + super::csv::FilterType::LessThanOrEqualTo => col.lt_eq(lit(filter.value.clone())), + super::csv::FilterType::NotEqualTo => col.neq(lit(filter.value.clone())), + } + }) + .reduce(|prev, next| prev.and(next)); + + let input_file = inputs.iter().find(|input| input.file_path == definition.source) + .ok_or(anyhow!("Failed to find valid file"))?; + let mut reader = LazyCsvReader::new(&input_file.file_path) + .has_header(true) + .finish()?; + let mut required_files = HashSet::new(); + for component in &definition.components { + if let Component::Field(file, field) = component { + required_files.insert(file); + } + } + for filter in &definition.filters { + required_files.insert(&filter.file); + } + for source_type in required_files { + // TODO: Better error messages + if source_type != &definition.source { + let source_file = inputs.iter() + .find(|input| input.file_path == definition.source) + .ok_or(anyhow!("Input file was not specified for source type"))?; + // TODO: Alias the joined columns so they don't potentially clash with the current column + let join_reader = LazyCsvReader::new(source_file.file_path.clone()).finish()?; + let left_column = input_file + .joins + .get(source_type) + .ok_or(anyhow!("Failed to get left join column"))?; + let right_column = source_file + .joins + .get(&definition.source) + .ok_or(anyhow!("Failed to get right join column"))?; + reader = reader.inner_join(join_reader, col(&left_column), col(&right_column)); + } + } + // TODO: Also work out how to expand rows, so that transfers can have stuff like daily or change in x expanded into multiple rows + // Since it's related to time it is probably related to this: https://docs.pola.rs/user-guide/transformations/time-series/parsing/ + // I'm guessing upsampling is what I'm looking for: https://docs.pola.rs/user-guide/transformations/time-series/resampling/#upsampling-to-a-higher-frequency + // Can use different strategies to break the time period down, range can be calculated by using start/end datetime + // Wonder if this can be done more generally (e.g. splitting up based on a number?) + // Note: This must occur before creating the components, since we'll need to create one for every upsampled row + let mut built_expression = lit(""); + // Create component columns + for component in &definition.components { + match component { + Component::Constant(constant) => { + built_expression = built_expression + lit(constant.clone()) + + } + // TODO: Do we need to worry about the source type? Might be clashing column names we need to think about earlier then address here? + // TODO: What I really want to do is not use source type, instead I want to be referring to a file, which we translate from the sourcetype + // to an actual filename. I don't want to be limited by a concept of 'sourcetype' at all, instead the definition should treat everything + // the same, and just translate the imported csv format to the necessary files and columns in files that are expected to be input. + Component::Field(source_type, column) => { + built_expression = built_expression + col(&column) + } + } + } + + // TODO: Build out the rest of the product definition, depending on the input definition + let select_columns = [built_expression]; + + // Filter and select the required data in one step, so optimiser can speed things up if necessary + let mut filtered = match filter { + Some(filter) => reader.filter(filter), + None => reader, + } + .select(select_columns) + .with_streaming(true) + .collect()?; + + let mut file = std::fs::File::create(output_path).unwrap(); + CsvWriter::new(&mut file).finish(&mut filtered)?; Ok(()) } diff --git a/src/products/csv.rs b/src/products/csv.rs index 07c92a4..d7d2886 100644 --- a/src/products/csv.rs +++ b/src/products/csv.rs @@ -1,17 +1,83 @@ -use std::{collections::HashMap, io::Read}; +use std::{collections::HashMap, io::Read, path::PathBuf}; -#[derive(Hash, PartialEq, PartialOrd, Ord, Eq)] +use anyhow::bail; +use chrono::NaiveDateTime; + +#[derive(Hash, PartialEq, PartialOrd)] pub struct Filter { - // Equal/not equal - pub equal: bool, + pub filter_type: FilterType, + pub file: PathBuf, pub field: String, pub value: String, - // TODO: Probably want to enum this. Source type determines things like filtering - // on encounter/patient fields when using something like a transfer - pub source_type: String, } -pub enum ConstraintType { +#[derive(Hash, PartialEq, PartialOrd, Eq, Ord, Clone)] +pub enum SourceType { + CodingDiagnosis, + CodingProcedure, + Encounter, + // TODO: Incident isn't used right now + // Incident, + Patient, + Revenue, + Service, + Transfer, +} + +impl TryFrom<&String> for SourceType { + type Error = anyhow::Error; + + fn try_from(value: &String) -> Result { + match value.as_str() { + "CD" => Ok(SourceType::CodingDiagnosis), + "CP" => Ok(SourceType::CodingProcedure), + "E" => Ok(SourceType::Encounter), + "P" => Ok(SourceType::Patient), + "R" => Ok(SourceType::Revenue), + "S" => Ok(SourceType::Service), + "T" => Ok(SourceType::Transfer), + _ => bail!("Source Type is not valid"), + } + } +} + +impl SourceType { + fn from_component_source_type(value: &str) -> anyhow::Result { + match value { + "CD" => Ok(SourceType::CodingDiagnosis), + "CP" => Ok(SourceType::CodingProcedure), + "E" => Ok(SourceType::Encounter), + "P" => Ok(SourceType::Patient), + "R" => Ok(SourceType::Revenue), + "S" => Ok(SourceType::Service), + "T" => Ok(SourceType::Transfer), + "EC" => Ok(SourceType::Encounter), + "CDX" => Ok(SourceType::CodingDiagnosis), + "CPX" => Ok(SourceType::CodingProcedure), + "EX" => Ok(SourceType::Encounter), + "PX" => Ok(SourceType::Patient), + "RX" => Ok(SourceType::Revenue), + "SX" => Ok(SourceType::Service), + "TX" => Ok(SourceType::Transfer), + _ => bail!("Invalid ComponentSourceType found: {}", value), + } + } + + fn to_file_path(&self) -> String { + match self { + SourceType::CodingDiagnosis => "coding_diagnoses.csv".to_owned(), + SourceType::CodingProcedure => "coding_procedures.csv".to_owned(), + SourceType::Encounter => "encounters.csv".to_owned(), + SourceType::Patient => "patients.csv".to_owned(), + SourceType::Revenue => "revenues.csv".to_owned(), + SourceType::Service => "services.csv".to_owned(), + SourceType::Transfer => "transfers.csv".to_owned(), + } + } +} + +#[derive(Hash, PartialEq, PartialOrd)] +pub enum FilterType { Equal, GreaterThan, GreaterThanOrEqualTo, @@ -20,59 +86,37 @@ pub enum ConstraintType { NotEqualTo, } -impl From<&String> for ConstraintType { - fn from(string: &String) -> Self { - match string.as_str() { - "=" => ConstraintType::Equal, - ">" => ConstraintType::GreaterThan, - ">=" => ConstraintType::GreaterThanOrEqualTo, - "<" => ConstraintType::LessThan, - "<=" => ConstraintType::LessThanOrEqualTo, - "!=" => ConstraintType::NotEqualTo, - _ => panic!(), +impl TryFrom<&String> for FilterType { + type Error = anyhow::Error; + + fn try_from(value: &String) -> Result { + match value.as_str() { + "=" => Ok(FilterType::Equal), + ">" => Ok(FilterType::GreaterThan), + ">=" => Ok(FilterType::GreaterThanOrEqualTo), + "<" => Ok(FilterType::LessThan), + "<=" => Ok(FilterType::LessThanOrEqualTo), + "!=" => Ok(FilterType::NotEqualTo), + _ => bail!("Invalid FilterType found: {}", value), } } } -pub struct Constraint { - pub source_type: String, - pub field: String, - pub constraint_type: ConstraintType, - pub value: String, +#[derive(PartialEq)] +pub enum ExtraType { + CodingDiagnosis, + CodingProcedure, + Encounter, + Patient, + Revenue, + Service, + Transfer, } pub enum Component { Constant(String), - // Even extras are allowed here, just specify the field type (encounter, service, etc) and the field name (incl Extra: or Classification: as appropriate) - // TODO: This first string should also be some kind of source type enum, probably shared with source types on filter/constraint - Field(String, String), -} - -#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)] -pub enum BuildFrom { - Service, - Transfer, - Encounter, - CodingProcedure, - CodingDiagnosis, - // TODO: This is hard/expensive, ignore for now as we don't have test data - LinkedDataset, - Revenue, -} - -impl From<&String> for BuildFrom { - fn from(string: &String) -> Self { - match string.as_str() { - "S" => BuildFrom::Service, - "E" => BuildFrom::Encounter, - "CP" => BuildFrom::CodingProcedure, - "CD" => BuildFrom::CodingDiagnosis, - "T" => BuildFrom::Transfer, - "BS" => BuildFrom::LinkedDataset, - "R" => BuildFrom::Revenue, - _ => panic!(), - } - } + // File, column_name + Field(PathBuf, String), } // Frequency per type: @@ -104,17 +148,20 @@ pub enum Frequency { OnePerSource, } -impl From<&String> for Frequency { - fn from(frequency: &String) -> Self { +impl TryFrom<&String> for Frequency { + type Error = anyhow::Error; + + fn try_from(frequency: &String) -> Result { match frequency.as_str() { - "O" => Frequency::OnePerSource, - "DOCW" => Frequency::DailyOrChangeInWard, - "D" => Frequency::Daily, - "DOCC" => Frequency::DailyOrChangeInClinic, - "DEAD" => Frequency::DailyExceptOnAdmissionDay, - "OAL" => Frequency::OnlyAdmissionLocation, - "CIW" => Frequency::ChangeInWard, - _ => panic!(), + "O" => Ok(Frequency::OnePerSource), + "DOCW" => Ok(Frequency::DailyOrChangeInWard), + "D" => Ok(Frequency::Daily), + "DOCC" => Ok(Frequency::DailyOrChangeInClinic), + "DEAD" => Ok(Frequency::DailyExceptOnAdmissionDay), + "OAL" => Ok(Frequency::OnlyAdmissionLocation), + "CIW" => Ok(Frequency::ChangeInWard), + "DDSD" => Ok(Frequency::DailyExceptOnDischargeDay), + _ => bail!("Invalid Frequency found: {}", frequency), } } } @@ -126,29 +173,30 @@ pub enum RoundingMode { None, } -impl From<&String> for RoundingMode { - fn from(rounding: &String) -> Self { +impl TryFrom<&String> for RoundingMode { + type Error = anyhow::Error; + + fn try_from(rounding: &String) -> Result { match rounding.as_str() { - "U" => RoundingMode::UpToClosestWhole, - "N" => RoundingMode::None, - "D" => RoundingMode::DownToClosestWhole, - "T" => RoundingMode::ToClosestWhole, - // TODO: Just use none when unknown? - _ => panic!(), + "U" => Ok(RoundingMode::UpToClosestWhole), + "N" => Ok(RoundingMode::None), + "D" => Ok(RoundingMode::DownToClosestWhole), + "T" => Ok(RoundingMode::ToClosestWhole), + _ => bail!("Invalid rounding mode found: {}", rounding), } } } -// enum ExtraValue { -// string(String), -// numeric(f64), -// datetime(NaiveDateTime), -// } +enum ExtraValue { + String(String), + Sumeric(f64), + Datetime(NaiveDateTime), +} -// struct Extra { -// extraType: String, -// value: ExtraValue, -// } +struct Extra { + extra_type: String, + value: ExtraValue, +} // Quantities per type: // Built Service: Constant, SourceQuantity @@ -187,15 +235,22 @@ pub enum DurationFallback { Service, } +pub struct FileJoin { + join_column: String, + file: String, + file_join_column: String, +} + pub struct Definition { pub name: String, pub components: Vec, pub filters: Vec, - pub constraints: Vec, - pub build_from: BuildFrom, + pub source: PathBuf, pub frequency: Frequency, pub quantity: BuiltQuantity, pub duration_fallback: DurationFallback, + // TODO: Need a way to define joins between different files. Or put that at some higher level might be better + // At the very least we still need a source/file type, and there should be one file supplied for each type } pub fn read_definitions( @@ -213,33 +268,36 @@ where "Definition" => { let quantity_type = record.get("BuiltQuantity").unwrap(); let rounding_mode = - RoundingMode::from(record.get("BuiltQuantityRounding").unwrap()); - let quantity = match quantity_type.as_str() { - "S" => Quantity::SourceQuantity, - "C" => Quantity::Constant( - record - .get("BuiltQuantityConstant") - .unwrap() - .parse() - .unwrap(), - ), - "H" => Quantity::Hours, + RoundingMode::try_from(record.get("BuiltQuantityRounding").unwrap())?; + let quantity: anyhow::Result = match quantity_type.as_str() { + "S" => Ok(Quantity::SourceQuantity), + "C" => { + let constant_value = + record.get("BuiltQuantityConstant").unwrap().parse()?; + Ok(Quantity::Constant(constant_value)) + } + "H" => Ok(Quantity::Hours), + "D" => Ok(Quantity::Days), // Above 3 are all that's needed for now - _ => panic![], + invalid_quantity => { + anyhow::bail!("Invalid quantity found: {}", invalid_quantity) + } }; + let quantity = quantity?; let built_quantity = BuiltQuantity { quantity, rounding_mode, }; + let build_from = SourceType::try_from(record.get("BuildFrom").unwrap())?; + let frequency = Frequency::try_from(record.get("Frequency").unwrap())?; all_definitions.insert( record.get("Name").unwrap().to_owned(), Definition { name: record.get("Name").unwrap().to_owned(), components: vec![], filters: vec![], - constraints: vec![], - build_from: BuildFrom::from(record.get("BuildFrom").unwrap()), - frequency: Frequency::from(record.get("Frequency").unwrap()), + source: build_from.to_file_path().into(), + frequency, quantity: built_quantity, // TODO: Figure this out // Not even in use, can ignore, or will BuiltService always be the default? @@ -248,11 +306,21 @@ where ); } "Filter" => { - let new_filter = Filter { - equal: record.get("FilterNotIn").unwrap() != "", - field: record.get("FilterField").unwrap().clone(), - value: record.get("FilterValue").unwrap().clone(), - source_type: record.get("FilterSourceType").unwrap().clone(), + let new_filter = { + let source_type = + SourceType::try_from(record.get("FilterSourceType").unwrap())?; + Filter { + // TODO: This looks wrong + filter_type: if record.get("FilterNotIn").unwrap() != "" { + FilterType::Equal + } else { + FilterType::NotEqualTo + }, + // TODO: extra/classification types need to append Extra:/Classification: to the start of the field + field: record.get("FilterField").unwrap().clone(), + value: record.get("FilterValue").unwrap().clone(), + file: source_type.to_file_path().into(), + } }; let all_filters = &mut all_definitions .get_mut(record.get("Name").unwrap()) @@ -265,11 +333,16 @@ where "C" => { Component::Constant(record.get("ComponentValueOrField").unwrap().to_owned()) } - source => Component::Field( - // TODO: Parse into source type enum - source.to_owned(), - record.get("ComponentValueOrField").unwrap().to_owned(), - ), + "MC" => { + Component::Constant(record.get("ComponentValueOrField").unwrap().to_owned()) + } + source => { + let component_source_type = SourceType::from_component_source_type(source)?; + Component::Field( + component_source_type.to_file_path().into(), + record.get("ComponentValueOrField").unwrap().to_owned(), + ) + } }; let all_components = &mut all_definitions .get_mut(record.get("Name").unwrap()) @@ -278,20 +351,41 @@ where all_components.push(component); } "Constraint" => { - let constraint = Constraint { - source_type: record.get("ConstraintSourceType").unwrap().to_owned(), - field: record.get("ConstraintColumn").unwrap().to_owned(), - constraint_type: ConstraintType::from(record.get("ConstraintType").unwrap()), - value: record.get("ConstraintValue").unwrap().to_owned(), + let constraint = { + let filter_type = FilterType::try_from(record.get("FilterType").unwrap())?; + let source_type = + SourceType::try_from(record.get("ConstraintSourceType").unwrap())?; + Filter { + field: record.get("ConstraintColumn").unwrap().to_owned(), + filter_type, + value: record.get("ConstraintValue").unwrap().to_owned(), + file: source_type.to_file_path().into(), + } }; - let all_constraints = &mut all_definitions + let all_filters = &mut all_definitions .get_mut(record.get("Name").unwrap()) .unwrap() - .constraints; - all_constraints.push(constraint); + .filters; + all_filters.push(constraint); } unknown => println!("Invalid type found: {}", unknown), } } Ok(all_definitions) } + +#[cfg(test)] +mod tests { + use super::read_definitions; + + #[test] + fn test_read_definitions() { + let definitions = read_definitions( + &mut csv::Reader::from_path("service_builder_definitions.csv").unwrap(), + ); + if let Err(error) = &definitions { + println!("{}", error) + } + assert!(definitions.is_ok()) + } +} diff --git a/src/products/mod.rs b/src/products/mod.rs index 8d738ef..185d247 100644 --- a/src/products/mod.rs +++ b/src/products/mod.rs @@ -1,5 +1,4 @@ -mod create_products; -pub use create_products::*; +pub mod create_products; // Don't re-export anything in csv atm, it's only used for internal processing -mod csv; +pub mod csv; diff --git a/src/upload_to_db.rs b/src/upload_to_db.rs new file mode 100644 index 0000000..65324f8 --- /dev/null +++ b/src/upload_to_db.rs @@ -0,0 +1,71 @@ +use std::{collections::HashMap, io::Read}; + +use csv::Reader; +use sqlx::{query, query_builder, Any, Mssql, Pool, QueryBuilder}; + +// Note: right now this is set to mssql only, since sqlx 0.7 is requried to use the Any +// type for sqlx 0.6 and earlier due to a query_builder lifetime issue, +// however sqlx >=0.7 currently doesn't support mssql. + +// Upload data in a file to a db table, with an optional post-script to run, +// such as to move data from the upload table into other tables +// TODO: Add bulk insert options for non-mssql dbs +// TODO: Add fallback insert when bulk insert fails (e.g. due to +// permission errors) +pub async fn upload_file_bulk( + pool: &Pool, + file_name: &String, + table_name: &String, + // Mappings from column in file -> column in db + column_mappings: Option>, + post_script: Option, +) -> anyhow::Result { + // TODO: Test if the table already exists. If it doesn't, try creating the table + + // First try a bulk insert command + // let result = match pool.any_kind() { + // sqlx::any::AnyKind::Mssql => { + let result = sqlx::query(&format!("BULK INSERT {} FROM {}", table_name, file_name)) + .execute(pool) + .await?; + // } + // }; + + let mut rows_affected = result.rows_affected(); + + + // let mut rows_affected = match &result { + // Result::Ok(result) => result.rows_affected(), + // // TODO: Log error + // Err(error) => 0_u64, + // }; + + // TODO: Adjust for various dbmss + if rows_affected == 0 { + let rows: Vec> = vec![]; + + let BIND_LIMIT: usize = 65535; + // TODO: Use csv to read from file + + // TODO: When bulk insert fails, Fall back to sql batched insert + // TODO: Columns to insert... needs some kind of mapping from file column name <-> db column + let mut query_builder = QueryBuilder::new(format!("INSERT INTO {}({}) ", table_name, "")); + // TODO: Iterate over all values in file, not the limit + query_builder.push_values(&rows[0..BIND_LIMIT], |mut b, row| { + b.push_bind(row.get("s")); + }); + let mut query_builder = query_builder; + // TODO: Looks like this issue: https://github.com/launchbadge/sqlx/issues/1978 + // Turns out we need v0.7 for this to not bug out, however mssql is only supported in versions before v0.7, so right now can't use sqlx + // to use this, unless we explicity specified mssql only, not Any as the db type... + let query = query_builder.build(); + let result = query.execute(pool).await?; + rows_affected = result.rows_affected(); + } + + if let Some(post_script) = post_script { + sqlx::query(&post_script).execute(pool).await?; + } + + Ok(rows_affected) +} \ No newline at end of file