diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 66eff9dc57..9bc9f8d7ea 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -13,10 +13,10 @@ on: jobs: check-membership: if: | - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/aider') && !contains(github.event.comment.user.login, '[bot]')) || - (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/aider') && !contains(github.event.comment.user.login, '[bot]')) || - (github.event_name == 'pull_request_review' && contains(github.event.review.body, '/aider') && !contains(github.event.review.user.login, '[bot]')) || - (github.event_name == 'issues' && contains(github.event.issue.body, '/aider') && !contains(github.event.issue.user.login, '[bot]')) + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/ai') && !contains(github.event.comment.user.login, '[bot]')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/ai') && !contains(github.event.comment.user.login, '[bot]')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '/ai') && !contains(github.event.review.user.login, '[bot]')) || + (github.event_name == 'issues' && contains(github.event.issue.body, '/ai') && !contains(github.event.issue.user.login, '[bot]')) runs-on: ubicloud-standard-2 outputs: is_member: ${{ steps.check-membership.outputs.is_member }} @@ -82,4 +82,4 @@ jobs: - Bash(npm run generate-backend-client): Generate the backend client. You need this to run npm run check. - Bash(cargo check): Run the cargo check script. You should run this tool after making changes to the backend code. - Bash(curl https://sh.rustup.rs -sSf | sh): Install Rust. You need this to run cargo check." - trigger_phrase: "/aider" + trigger_phrase: "/ai" diff --git a/CHANGELOG.md b/CHANGELOG.md index af899a02cb..d87147c4e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [1.493.0](https://github.com/windmill-labs/windmill/compare/v1.492.1...v1.493.0) (2025-05-27) + + +### Features + +* add aws oidc support for instance s3 storage ([#5810](https://github.com/windmill-labs/windmill/issues/5810)) ([5b96bcc](https://github.com/windmill-labs/windmill/commit/5b96bccedd6e68fea631580dd49338301ad0305f)) +* duckdb sql lang support ([#5761](https://github.com/windmill-labs/windmill/issues/5761)) ([fdefd4b](https://github.com/windmill-labs/windmill/commit/fdefd4be9398b9610a539360353fd61b521732d4)) +* **python:** inline script metadata (PEP 723) ([#5712](https://github.com/windmill-labs/windmill/issues/5712)) ([2622253](https://github.com/windmill-labs/windmill/commit/26222539e66bce7e88f86a7e5917e6ca99350865)) + + +### Bug Fixes + +* add missing http_trigger_version_seq grants ([#5816](https://github.com/windmill-labs/windmill/issues/5816)) ([306f3ea](https://github.com/windmill-labs/windmill/commit/306f3eabd1c03fa904b0e59438de124a0e680597)) +* avoid monaco memory leak ([0d459d5](https://github.com/windmill-labs/windmill/commit/0d459d5d223728270854e37715ecc1663ede9870)) +* error handler node rendering at top level ([feae9b0](https://github.com/windmill-labs/windmill/commit/feae9b09240ba306c007013a36d2aefb0b273766)) +* **frontend:** auto completion and render of tailwind classes in app editor ([#5817](https://github.com/windmill-labs/windmill/issues/5817)) ([5897e7e](https://github.com/windmill-labs/windmill/commit/5897e7e01b8839425c30c2a97481ef7bb9090661)) + ## [1.492.1](https://github.com/windmill-labs/windmill/compare/v1.492.0...v1.492.1) (2025-05-22) diff --git a/backend/.gitignore b/backend/.gitignore index 4ca669fc53..f75b9d1eaa 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -5,4 +5,5 @@ oauth2.json tracing.folded heaptrack* index/ -windmill-api/openapi-*.* \ No newline at end of file +windmill-api/openapi-*.* +.duckdb/* \ No newline at end of file diff --git a/backend/Cargo.lock b/backend/Cargo.lock index eaf6ef8e37..f752eaecbd 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -286,25 +286,57 @@ dependencies = [ "serde", ] +[[package]] +name = "arrow" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5ec52ba94edeed950e4a41f75d35376df196e8cb04437f7280a5aa49f20f796" +dependencies = [ + "arrow-arith 54.3.1", + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-cast 54.3.1", + "arrow-data 54.3.1", + "arrow-ord 54.3.1", + "arrow-row 54.3.1", + "arrow-schema 54.3.1", + "arrow-select 54.3.1", + "arrow-string 54.3.1", +] + [[package]] name = "arrow" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1bb018b6960c87fd9d025009820406f74e83281185a8bdcb44880d2aa5c9a87" dependencies = [ - "arrow-arith", - "arrow-array", - "arrow-buffer", - "arrow-cast", + "arrow-arith 55.1.0", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-cast 55.1.0", "arrow-csv", - "arrow-data", + "arrow-data 55.1.0", "arrow-ipc", "arrow-json", - "arrow-ord", - "arrow-row", - "arrow-schema", - "arrow-select", - "arrow-string", + "arrow-ord 55.1.0", + "arrow-row 55.1.0", + "arrow-schema 55.1.0", + "arrow-select 55.1.0", + "arrow-string 55.1.0", +] + +[[package]] +name = "arrow-arith" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc766fdacaf804cb10c7c70580254fcdb5d55cdfda2bc57b02baf5223a3af9e" +dependencies = [ + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "chrono", + "num", ] [[package]] @@ -313,14 +345,30 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44de76b51473aa888ecd6ad93ceb262fb8d40d1f1154a4df2f069b3590aa7575" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "chrono", "num", ] +[[package]] +name = "arrow-array" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12fcdb3f1d03f69d3ec26ac67645a8fe3f878d77b5ebb0b15d64a116c212985" +dependencies = [ + "ahash 0.8.12", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "chrono", + "half", + "hashbrown 0.15.3", + "num", +] + [[package]] name = "arrow-array" version = "55.1.0" @@ -328,9 +376,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ed77e22744475a9a53d00026cf8e166fe73cf42d89c4c4ae63607ee1cfcc3f" dependencies = [ "ahash 0.8.12", - "arrow-buffer", - "arrow-data", - "arrow-schema", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "chrono", "chrono-tz", "half", @@ -338,6 +386,17 @@ dependencies = [ "num", ] +[[package]] +name = "arrow-buffer" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "263f4801ff1839ef53ebd06f99a56cecd1dbaf314ec893d93168e2e860e0291c" +dependencies = [ + "bytes", + "half", + "num", +] + [[package]] name = "arrow-buffer" version = "55.1.0" @@ -349,17 +408,38 @@ dependencies = [ "num", ] +[[package]] +name = "arrow-cast" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede6175fbc039dfc946a61c1b6d42fd682fcecf5ab5d148fbe7667705798cac9" +dependencies = [ + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "arrow-select 54.3.1", + "atoi", + "base64 0.22.1", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num", + "ryu", +] + [[package]] name = "arrow-cast" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f39e1d774ece9292697fcbe06b5584401b26bd34be1bec25c33edae65c2420ff" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", - "arrow-select", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", + "arrow-select 55.1.0", "atoi", "base64 0.22.1", "chrono", @@ -376,9 +456,9 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9055c972a07bf12c2a827debfd34f88d3b93da1941d36e1d9fee85eebe38a12a" dependencies = [ - "arrow-array", - "arrow-cast", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-cast 55.1.0", + "arrow-schema 55.1.0", "chrono", "csv", "csv-core", @@ -386,14 +466,26 @@ dependencies = [ "regex", ] +[[package]] +name = "arrow-data" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61cfdd7d99b4ff618f167e548b2411e5dd2c98c0ddebedd7df433d34c20a4429" +dependencies = [ + "arrow-buffer 54.3.1", + "arrow-schema 54.3.1", + "half", + "num", +] + [[package]] name = "arrow-data" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf75ac27a08c7f48b88e5c923f267e980f27070147ab74615ad85b5c5f90473d" dependencies = [ - "arrow-buffer", - "arrow-schema", + "arrow-buffer 55.1.0", + "arrow-schema 55.1.0", "half", "num", ] @@ -404,10 +496,10 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a222f0d93772bd058d1268f4c28ea421a603d66f7979479048c429292fac7b2e" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "flatbuffers", "lz4_flex", ] @@ -418,11 +510,11 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9085342bbca0f75e8cb70513c0807cc7351f1fbf5cb98192a67d5e3044acb033" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-cast 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "chrono", "half", "indexmap 2.9.0", @@ -434,17 +526,43 @@ dependencies = [ "simdutf8", ] +[[package]] +name = "arrow-ord" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0a3334a743bd2a1479dbc635540617a3923b4b2f6870f37357339e6b5363c21" +dependencies = [ + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "arrow-select 54.3.1", +] + [[package]] name = "arrow-ord" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2f1065a5cad7b9efa9e22ce5747ce826aa3855766755d4904535123ef431e7" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", - "arrow-select", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", + "arrow-select 55.1.0", +] + +[[package]] +name = "arrow-row" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d1d7a7291d2c5107e92140f75257a99343956871f3d3ab33a7b41532f79cb68" +dependencies = [ + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "half", ] [[package]] @@ -453,19 +571,42 @@ version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3703a0e3e92d23c3f756df73d2dc9476873f873a76ae63ef9d3de17fda83b2d8" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "half", ] +[[package]] +name = "arrow-schema" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cfaf5e440be44db5413b75b72c2a87c1f8f0627117d110264048f2969b99e9" +dependencies = [ + "bitflags 2.9.1", +] + [[package]] name = "arrow-schema" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73a47aa0c771b5381de2b7f16998d351a6f4eb839f1e13d48353e17e873d969b" +[[package]] +name = "arrow-select" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69efcd706420e52cd44f5c4358d279801993846d1c2a8e52111853d61d55a619" +dependencies = [ + "ahash 0.8.12", + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "num", +] + [[package]] name = "arrow-select" version = "55.1.0" @@ -473,24 +614,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24b7b85575702b23b85272b01bc1c25a01c9b9852305e5d0078c79ba25d995d4" dependencies = [ "ahash 0.8.12", - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", "num", ] +[[package]] +name = "arrow-string" +version = "54.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21546b337ab304a32cfc0770f671db7411787586b45b78b4593ae78e64e2b03" +dependencies = [ + "arrow-array 54.3.1", + "arrow-buffer 54.3.1", + "arrow-data 54.3.1", + "arrow-schema 54.3.1", + "arrow-select 54.3.1", + "memchr", + "num", + "regex", + "regex-syntax 0.8.5", +] + [[package]] name = "arrow-string" version = "55.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9260fddf1cdf2799ace2b4c2fc0356a9789fa7551e0953e35435536fecefebbd" dependencies = [ - "arrow-array", - "arrow-buffer", - "arrow-data", - "arrow-schema", - "arrow-select", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-data 55.1.0", + "arrow-schema 55.1.0", + "arrow-select 55.1.0", "memchr", "num", "regex", @@ -633,7 +791,7 @@ dependencies = [ "bytes", "http 1.3.1", "rand 0.8.5", - "reqwest 0.12.15", + "reqwest 0.12.16", "serde", "serde-aux", "serde_json", @@ -833,9 +991,9 @@ dependencies = [ [[package]] name = "aws-sdk-sqs" -version = "1.70.0" +version = "1.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b742e0981caafc34a57b36d6e492786e2a11638766f49e1c92dec1b55f33d16b" +checksum = "0519921fc7065a54b8dec1d10de2893d99a61d030b9f8eb00ee83eb62d2a2676" dependencies = [ "aws-credential-types", "aws-runtime", @@ -855,9 +1013,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.70.0" +version = "1.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83447efb7179d8e2ad2afb15ceb9c113debbc2ecdf109150e338e2e28b86190b" +checksum = "95a4fd09d6e863655d99cd2260f271c6d1030dc6bfad68e19e126d2e4c8ceb18" dependencies = [ "aws-credential-types", "aws-runtime", @@ -877,9 +1035,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.71.0" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f9bfbbda5e2b9fe330de098f14558ee8b38346408efe9f2e9cee82dc1636a4" +checksum = "3224ab02ebb3074467a33d57caf6fcb487ca36f3697fdd381b0428dc72380696" dependencies = [ "aws-credential-types", "aws-runtime", @@ -899,9 +1057,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.71.0" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17b984a66491ec08b4f4097af8911251db79296b3e4a763060b45805746264f" +checksum = "f6933f189ed1255e78175fbd73fb200c0aae7240d220ed3346f567b0ddca3083" dependencies = [ "aws-credential-types", "aws-runtime", @@ -989,7 +1147,7 @@ dependencies = [ "hyper 0.14.32", "hyper 1.6.0", "hyper-rustls 0.24.2", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.6", "hyper-util", "pin-project-lite", "rustls 0.21.12", @@ -1838,6 +1996,12 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cbc" version = "0.1.2" @@ -1849,9 +2013,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.23" +version = "1.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" +checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" dependencies = [ "jobserver", "libc", @@ -1964,14 +2128,14 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading 0.8.7", + "libloading 0.8.8", ] [[package]] name = "clap" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", "clap_derive", @@ -1979,9 +2143,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstream", "anstyle", @@ -2213,9 +2377,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -2445,7 +2609,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813" dependencies = [ "bitflags 2.9.1", - "libloading 0.8.7", + "libloading 0.8.8", "winapi", ] @@ -2599,9 +2763,9 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe060b978f74ab446be722adb8a274e052e005bf6dfd171caadc3abaad10080" dependencies = [ - "arrow", + "arrow 55.1.0", "arrow-ipc", - "arrow-schema", + "arrow-schema 55.1.0", "async-trait", "bytes", "bzip2", @@ -2654,7 +2818,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61fe34f401bd03724a1f96d12108144f8cd495a3cdda2bf5e091822fb80b7e66" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "dashmap 6.1.0", "datafusion-common", @@ -2680,7 +2844,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4411b8e3bce5e0fc7521e44f201def2e2d5d1b5f176fb56e8cdc9942c890f00" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "datafusion-catalog", "datafusion-common", @@ -2704,7 +2868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0734015d81c8375eb5d4869b7f7ecccc2ee8d6cb81948ef737cd0e7b743bd69c" dependencies = [ "ahash 0.8.12", - "arrow", + "arrow 55.1.0", "arrow-ipc", "base64 0.22.1", "half", @@ -2738,7 +2902,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04e602dcdf2f50c2abf297cc2203c73531e6f48b29516af7695d338cf2a778b1" dependencies = [ - "arrow", + "arrow 55.1.0", "async-compression", "async-trait", "bytes", @@ -2774,7 +2938,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bb2253952dc32296ed5b84077cb2e0257fea4be6373e1c376426e17ead4ef6" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "bytes", "datafusion-catalog", @@ -2799,7 +2963,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8c7f47a5d2fe03bfa521ec9bafdb8a5c82de8377f60967c3663f00c8790352" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "bytes", "datafusion-catalog", @@ -2824,7 +2988,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27d15868ea39ed2dc266728b554f6304acd473de2142281ecfa1294bb7415923" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "bytes", "datafusion-catalog", @@ -2861,7 +3025,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06f004d100f49a3658c9da6fb0c3a9b760062d96cd4ad82ccc3b7b69a9fb2f84" dependencies = [ - "arrow", + "arrow 55.1.0", "dashmap 6.1.0", "datafusion-common", "datafusion-expr", @@ -2880,7 +3044,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a4e4ce3802609be38eeb607ee72f6fe86c3091460de9dbfae9e18db423b3964" dependencies = [ - "arrow", + "arrow 55.1.0", "chrono", "datafusion-common", "datafusion-doc", @@ -2901,7 +3065,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "422ac9cf3b22bbbae8cdf8ceb33039107fde1b5492693168f13bd566b1bcc839" dependencies = [ - "arrow", + "arrow 55.1.0", "datafusion-common", "indexmap 2.9.0", "itertools 0.14.0", @@ -2914,8 +3078,8 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ddf0a0a2db5d2918349c978d42d80926c6aa2459cd8a3c533a84ec4bb63479e" dependencies = [ - "arrow", - "arrow-buffer", + "arrow 55.1.0", + "arrow-buffer 55.1.0", "base64 0.22.1", "blake2", "blake3", @@ -2944,7 +3108,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "408a05dafdc70d05a38a29005b8b15e21b0238734dab1e98483fcb58038c5aba" dependencies = [ "ahash 0.8.12", - "arrow", + "arrow 55.1.0", "datafusion-common", "datafusion-doc", "datafusion-execution", @@ -2965,7 +3129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "756d21da2dd6c9bef97af1504970ff56cbf35d03fbd4ffd62827f02f4d2279d4" dependencies = [ "ahash 0.8.12", - "arrow", + "arrow 55.1.0", "datafusion-common", "datafusion-expr-common", "datafusion-physical-expr-common", @@ -2977,8 +3141,8 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d8d50f6334b378930d992d801a10ac5b3e93b846b39e4a05085742572844537" dependencies = [ - "arrow", - "arrow-ord", + "arrow 55.1.0", + "arrow-ord 55.1.0", "datafusion-common", "datafusion-doc", "datafusion-execution", @@ -2998,7 +3162,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc9a97220736c8fff1446e936be90d57216c06f28969f9ffd3b72ac93c958c8a" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "datafusion-catalog", "datafusion-common", @@ -3052,7 +3216,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "084d9f979c4b155346d3c34b18f4256e6904ded508e9554d90fed416415c3515" dependencies = [ - "arrow", + "arrow 55.1.0", "chrono", "datafusion-common", "datafusion-expr", @@ -3072,7 +3236,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64c536062b0076f4e30084065d805f389f9fe38af0ca75bcbac86bc5e9fbab65" dependencies = [ "ahash 0.8.12", - "arrow", + "arrow 55.1.0", "datafusion-common", "datafusion-expr", "datafusion-expr-common", @@ -3094,7 +3258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8a92b53b3193fac1916a1c5b8e3f4347c526f6822e56b71faa5fb372327a863" dependencies = [ "ahash 0.8.12", - "arrow", + "arrow 55.1.0", "datafusion-common", "datafusion-expr-common", "hashbrown 0.14.5", @@ -3107,7 +3271,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fa0a5ac94c7cf3da97bedabd69d6bbca12aef84b9b37e6e9e8c25286511b5e2" dependencies = [ - "arrow", + "arrow 55.1.0", "datafusion-common", "datafusion-execution", "datafusion-expr", @@ -3127,9 +3291,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "690c615db468c2e5fe5085b232d8b1c088299a6c63d87fd960a354a71f7acb55" dependencies = [ "ahash 0.8.12", - "arrow", - "arrow-ord", - "arrow-schema", + "arrow 55.1.0", + "arrow-ord 55.1.0", + "arrow-schema 55.1.0", "async-trait", "chrono", "datafusion-common", @@ -3156,7 +3320,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad229a134c7406c057ece00c8743c0c34b97f4e72f78b475fe17b66c5e14fa4f" dependencies = [ - "arrow", + "arrow 55.1.0", "async-trait", "dashmap 6.1.0", "datafusion-common", @@ -3180,7 +3344,7 @@ version = "47.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64f6ab28b72b664c21a27b22a2ff815fd390ed224c26e89a93b5a8154a4e8607" dependencies = [ - "arrow", + "arrow 55.1.0", "bigdecimal", "datafusion-common", "datafusion-expr", @@ -3506,7 +3670,7 @@ dependencies = [ "http 1.3.1", "http-body-util", "hyper 1.6.0", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.6", "hyper-util", "ipnet", "percent-encoding", @@ -4112,7 +4276,7 @@ dependencies = [ "deno_tls", "http-body-util", "hyper 1.6.0", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.6", "hyper-util", "log", "once_cell", @@ -4573,9 +4737,9 @@ dependencies = [ [[package]] name = "dlopen2_derive" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", @@ -4640,6 +4804,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "duckdb" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ac283b6621e3becf8014d1efa655522794075834c72f744573debef9c9f6c8" +dependencies = [ + "arrow 54.3.1", + "cast", + "fallible-iterator 0.3.0", + "fallible-streaming-iterator", + "hashlink 0.9.1", + "libduckdb-sys", + "memchr", + "num-integer", + "rust_decimal", + "smallvec", + "strum 0.25.0", +] + [[package]] name = "dunce" version = "1.0.5" @@ -5807,7 +5990,7 @@ dependencies = [ "google-cloud-token", "home", "jsonwebtoken 9.3.1", - "reqwest 0.12.15", + "reqwest 0.12.16", "serde", "serde_json", "thiserror 1.0.69", @@ -5850,7 +6033,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d901aeb453fd80e51d64df4ee005014f6cf39f2d736dd64f7239c132d9d39a6a" dependencies = [ - "reqwest 0.12.15", + "reqwest 0.12.16", "thiserror 1.0.69", "tokio", ] @@ -5916,9 +6099,9 @@ dependencies = [ [[package]] name = "gpu-descriptor" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ "bitflags 2.9.1", "gpu-descriptor-types", @@ -6394,11 +6577,10 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" dependencies = [ - "futures-util", "http 1.3.1", "hyper 1.6.0", "hyper-util", @@ -6408,7 +6590,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.2", "tower-service", - "webpki-roots 0.26.11", + "webpki-roots 1.0.0", ] [[package]] @@ -6455,22 +6637,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710" +checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", "http 1.3.1", "http-body 1.0.1", "hyper 1.6.0", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration 0.6.1", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -6796,6 +6984,16 @@ dependencies = [ "serde", ] +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-macro" version = "0.3.7" @@ -6984,7 +7182,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.8.7", + "libloading 0.8.8", "pkg-config", ] @@ -7149,6 +7347,22 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +[[package]] +name = "libduckdb-sys" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cac9d03484c43fefac8b2066a253c9b0b3b0cd02cbe02a9ea2312f7e382618" +dependencies = [ + "autocfg", + "cc", + "flate2", + "pkg-config", + "serde", + "serde_json", + "tar", + "vcpkg", +] + [[package]] name = "libffi" version = "3.2.0" @@ -7180,9 +7394,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", "windows-targets 0.53.0", @@ -7742,13 +7956,13 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -8425,7 +8639,7 @@ dependencies = [ "getrandom 0.2.16", "http 1.3.1", "rand 0.8.5", - "reqwest 0.12.15", + "reqwest 0.12.16", "serde", "serde_json", "serde_path_to_error", @@ -8474,7 +8688,7 @@ dependencies = [ "percent-encoding", "quick-xml 0.37.5", "rand 0.9.0", - "reqwest 0.12.15", + "reqwest 0.12.16", "ring 0.17.14", "serde", "serde_json", @@ -8532,11 +8746,11 @@ checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea" [[package]] name = "onig" -version = "6.4.0" +version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "libc", "once_cell", "onig_sys", @@ -8544,9 +8758,9 @@ dependencies = [ [[package]] name = "onig_sys" -version = "69.8.1" +version = "69.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" dependencies = [ "cc", "pkg-config", @@ -8950,13 +9164,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be7b2d778f6b841d37083ebdf32e33a524acde1266b5884a8ca29bf00dfa1231" dependencies = [ "ahash 0.8.12", - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", + "arrow-array 55.1.0", + "arrow-buffer 55.1.0", + "arrow-cast 55.1.0", + "arrow-data 55.1.0", "arrow-ipc", - "arrow-schema", - "arrow-select", + "arrow-schema 55.1.0", + "arrow-select 55.1.0", "base64 0.22.1", "brotli 8.0.1", "bytes", @@ -10162,9 +10376,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "2bf597b113be201cb2269b4c39b39a804d01b99ee95a4278f0ed04e45cff1c71" dependencies = [ "async-compression", "base64 0.22.1", @@ -10177,7 +10391,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.6.0", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.6", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -10191,26 +10405,24 @@ dependencies = [ "quinn", "rustls 0.23.27", "rustls-native-certs 0.8.1", - "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.2", - "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tokio-rustls 0.26.2", "tokio-util", "tower 0.5.2", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.11", - "windows-registry", + "webpki-roots 1.0.0", ] [[package]] @@ -10222,7 +10434,7 @@ dependencies = [ "anyhow", "async-trait", "http 1.3.1", - "reqwest 0.12.15", + "reqwest 0.12.16", "serde", "thiserror 1.0.69", "tower-service", @@ -10241,7 +10453,7 @@ dependencies = [ "http 1.3.1", "hyper 1.6.0", "parking_lot 0.11.2", - "reqwest 0.12.15", + "reqwest 0.12.16", "reqwest-middleware", "retry-policies", "thiserror 1.0.69", @@ -11003,7 +11215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ "bitflags 2.9.1", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -11492,9 +11704,9 @@ checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -12975,14 +13187,14 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.3", + "mio 1.0.4", "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", @@ -13360,12 +13572,15 @@ dependencies = [ "bitflags 2.9.1", "bytes", "futures-core", + "futures-util", "http 1.3.1", "http-body 1.0.1", "http-body-util", + "iri-string", "pin-project-lite", "tokio", "tokio-util", + "tower 0.5.2", "tower-layer", "tower-service", "tracing", @@ -13456,7 +13671,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3beec919fbdf99d719de8eda6adae3281f8a5b71ae40431f44dc7423053d34" dependencies = [ "loki-api", - "reqwest 0.12.15", + "reqwest 0.12.16", "serde", "serde_json", "snap", @@ -13670,7 +13885,7 @@ checksum = "90b70b37e9074642bc5f60bb23247fd072a84314ca9e71cdf8527593406a0dd3" dependencies = [ "gemm 0.18.2", "half", - "libloading 0.8.7", + "libloading 0.8.8", "memmap2 0.9.5", "num", "num-traits", @@ -13979,9 +14194,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ "getrandom 0.3.3", "js-sys", @@ -14346,7 +14561,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.7", + "libloading 0.8.8", "log", "metal", "naga", @@ -14452,7 +14667,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "axum", @@ -14472,7 +14687,7 @@ dependencies = [ "prometheus", "quote", "rand 0.9.0", - "reqwest 0.12.15", + "reqwest 0.12.16", "rustls 0.23.27", "serde", "serde_json", @@ -14503,7 +14718,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "argon2", @@ -14562,7 +14777,7 @@ dependencies = [ "rand 0.9.0", "rdkafka", "regex", - "reqwest 0.12.15", + "reqwest 0.12.16", "rmcp", "rsa", "rumqttc", @@ -14612,7 +14827,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.492.1" +version = "1.493.0" dependencies = [ "base64 0.22.1", "chrono", @@ -14627,7 +14842,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "1.492.1" +version = "1.493.0" dependencies = [ "chrono", "serde", @@ -14640,7 +14855,7 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "serde", @@ -14654,7 +14869,7 @@ dependencies = [ [[package]] name = "windmill-common" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "async-stream", @@ -14696,7 +14911,7 @@ dependencies = [ "quick_cache", "rand 0.9.0", "regex", - "reqwest 0.12.15", + "reqwest 0.12.16", "reqwest-middleware", "reqwest-retry", "semver 1.0.26", @@ -14730,7 +14945,7 @@ dependencies = [ [[package]] name = "windmill-git-sync" -version = "1.492.1" +version = "1.493.0" dependencies = [ "regex", "serde", @@ -14744,7 +14959,7 @@ dependencies = [ [[package]] name = "windmill-indexer" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "bytes", @@ -14767,7 +14982,7 @@ dependencies = [ [[package]] name = "windmill-macros" -version = "1.492.1" +version = "1.493.0" dependencies = [ "itertools 0.14.0", "lazy_static", @@ -14779,7 +14994,7 @@ dependencies = [ [[package]] name = "windmill-parser" -version = "1.492.1" +version = "1.493.0" dependencies = [ "convert_case 0.6.0", "serde", @@ -14788,7 +15003,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "lazy_static", @@ -14800,7 +15015,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "serde_json", @@ -14812,7 +15027,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "gosyn", @@ -14824,7 +15039,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "lazy_static", @@ -14836,7 +15051,7 @@ dependencies = [ [[package]] name = "windmill-parser-java" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "serde_json", @@ -14848,7 +15063,7 @@ dependencies = [ [[package]] name = "windmill-parser-nu" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "nu-parser", @@ -14859,7 +15074,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "itertools 0.14.0", @@ -14870,7 +15085,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "itertools 0.14.0", @@ -14881,7 +15096,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "async-recursion", @@ -14904,7 +15119,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -14921,7 +15136,7 @@ dependencies = [ [[package]] name = "windmill-parser-sql" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "lazy_static", @@ -14933,7 +15148,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "lazy_static", @@ -14951,7 +15166,7 @@ dependencies = [ [[package]] name = "windmill-parser-wasm" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "getrandom 0.2.16", @@ -14975,7 +15190,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "serde_json", @@ -14985,7 +15200,7 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "async-recursion", @@ -15002,7 +15217,7 @@ dependencies = [ "lazy_static", "prometheus", "regex", - "reqwest 0.12.15", + "reqwest 0.12.16", "serde", "serde_json", "serde_urlencoded", @@ -15018,7 +15233,7 @@ dependencies = [ [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.492.1" +version = "1.493.0" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -15028,7 +15243,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.492.1" +version = "1.493.0" dependencies = [ "anyhow", "async-recursion", @@ -15056,6 +15271,7 @@ dependencies = [ "deno_web", "deno_webidl", "dotenv", + "duckdb", "dyn-iter", "flume", "futures", @@ -15079,7 +15295,7 @@ dependencies = [ "prometheus", "rand 0.9.0", "regex", - "reqwest 0.12.15", + "reqwest 0.12.16", "reqwest-middleware", "rust_decimal", "serde", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 069aca4367..df56800ce3 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.492.1" +version = "1.493.0" authors.workspace = true edition.workspace = true @@ -32,7 +32,7 @@ members = [ ] [workspace.package] -version = "1.492.1" +version = "1.493.0" authors = ["Ruben Fiszel "] edition = "2021" @@ -87,13 +87,14 @@ python = ["windmill-worker/python", "windmill-api/python"] rust = ["windmill-worker/rust"] mysql = ["windmill-worker/mysql"] oracledb = ["windmill-worker/oracledb"] +duckdb = ["windmill-worker/duckdb"] mssql = ["windmill-worker/mssql"] bigquery = ["windmill-worker/bigquery"] php = ["windmill-worker/php"] csharp = ["windmill-worker/csharp"] nu = ["windmill-worker/nu"] java = ["windmill-worker/java"] -all_languages = [ "python", "deno_core", "rust", "mysql", "oracledb", "mssql", "bigquery", "csharp", "nu", "php", "java"] +all_languages = [ "python", "deno_core", "rust", "mysql", "oracledb", "duckdb", "mssql", "bigquery", "csharp", "nu", "php", "java"] [patch.crates-io] @@ -238,6 +239,7 @@ json-pointer = "^0" itertools = "^0" regex = "^1" semver = "^1" +duckdb = { version = "1.2.2", features = ["bundled"] } v8 = "=130.0.7" # Exact version NOTE: Do not forget to update version and hash in flake.nix deno_fetch = "0.214.0" diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 04b305d5a2..be1e897bcd 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -6899b8151329218a1df59964dac57e0e004ae25a \ No newline at end of file +32039f675060b5996951708368bdefe14278d5cd \ No newline at end of file diff --git a/backend/migrations/20250515084520_duckdb_support.down.sql b/backend/migrations/20250515084520_duckdb_support.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20250515084520_duckdb_support.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250515084520_duckdb_support.up.sql b/backend/migrations/20250515084520_duckdb_support.up.sql new file mode 100644 index 0000000000..869fcc07dc --- /dev/null +++ b/backend/migrations/20250515084520_duckdb_support.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'duckdb'; +UPDATE config set config = jsonb_set(config, '{worker_tags}', config->'worker_tags' || '["duckdb"]'::jsonb) where name = 'worker__default' and config @> '{"worker_tags": ["deno", "python3", "go", "bash", "powershell", "dependency", "flow", "hub", "other", "bun", "php", "rust", "ansible", "csharp", "nu", "java"]}'::jsonb AND NOT config->'worker_tags' @> '"duckdb"'::jsonb; diff --git a/backend/migrations/20250526173025_http_trigger_seq_grants.down.sql b/backend/migrations/20250526173025_http_trigger_seq_grants.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20250526173025_http_trigger_seq_grants.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250526173025_http_trigger_seq_grants.up.sql b/backend/migrations/20250526173025_http_trigger_seq_grants.up.sql new file mode 100644 index 0000000000..bf09f0a555 --- /dev/null +++ b/backend/migrations/20250526173025_http_trigger_seq_grants.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +GRANT ALL ON SEQUENCE http_trigger_version_seq TO windmill_user; +GRANT ALL ON SEQUENCE http_trigger_version_seq TO windmill_admin; \ No newline at end of file diff --git a/backend/parsers/windmill-parser-sql/src/lib.rs b/backend/parsers/windmill-parser-sql/src/lib.rs index 21ebe45f7b..0fe72f0296 100644 --- a/backend/parsers/windmill-parser-sql/src/lib.rs +++ b/backend/parsers/windmill-parser-sql/src/lib.rs @@ -83,6 +83,21 @@ pub fn parse_bigquery_sig(code: &str) -> anyhow::Result { } } +pub fn parse_duckdb_sig(code: &str) -> anyhow::Result { + let parsed = parse_duckdb_file(&code)?; + if let Some(args) = parsed { + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: None, + has_preprocessor: None, + }) + } else { + Err(anyhow!("Error parsing sql".to_string())) + } +} + pub fn parse_snowflake_sig(code: &str) -> anyhow::Result { let parsed = parse_snowflake_file(&code)?; if let Some(x) = parsed { @@ -212,6 +227,9 @@ lazy_static::lazy_static! { // -- @name (type) = default static ref RE_ARG_BIGQUERY: Regex = Regex::new(r#"(?m)^-- @(\w+) \((\w+(?:\[\])?)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); + // -- $name (type) = default + static ref RE_ARG_DUCKDB: Regex = Regex::new(r#"(?m)^-- \$(\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); + static ref RE_ARG_SNOWFLAKE: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap(); @@ -577,6 +595,35 @@ fn parse_bigquery_file(code: &str) -> anyhow::Result>> { Ok(Some(args)) } +fn parse_duckdb_file(code: &str) -> anyhow::Result>> { + let mut args: Vec = vec![]; + + for cap in RE_ARG_DUCKDB.captures_iter(code) { + let name = cap.get(1).map(|x| x.as_str().to_string()).unwrap(); + let typ = cap + .get(2) + .map(|x| x.as_str().to_string().to_lowercase()) + .unwrap(); + let default = cap.get(3).map(|x| x.as_str().to_string()); + let has_default = default.is_some(); + let parsed_typ = parse_duckdb_typ(typ.as_str()); + + let parsed_default = default.and_then(|x| parsed_default(&parsed_typ, x)); + + args.push(Arg { + name, + typ: parsed_typ, + default: parsed_default, + otyp: Some(typ), + has_default, + oidx: None, + }); + } + + args.append(&mut parse_sql_sanitized_interpolation(code)); + Ok(Some(args)) +} + fn parse_snowflake_file(code: &str) -> anyhow::Result>> { let mut args: Vec = vec![]; @@ -729,6 +776,33 @@ pub fn parse_bigquery_typ(typ: &str) -> Typ { } } +pub fn parse_duckdb_typ(typ: &str) -> Typ { + if typ.ends_with("[]") { + let base_typ = parse_duckdb_typ(typ.strip_suffix("[]").unwrap()); + Typ::List(Box::new(base_typ)) + } else { + match typ { + "varchar" | "char" | "bpchar" | "text" | "string" => Typ::Str(None), + "blob" | "bytea" | "binary" | "varbinary" | "bitstring" => Typ::Bytes, + "boolean" | "bool" | "bit" | "logical" => Typ::Bool, + "bigint" | "int8" | "long" | "integer" | "int4" | "int" | "smallint" | "int2" + | "short" | "tinyint" | "int1" | "signed" | "ubigint" | "uhugeint" | "uinteger" + | "usmallint" | "utinyint" => Typ::Int, + "decimal" | "numeric" | "double" | "float8" | "float" | "float4" | "real" => Typ::Float, + "date" + | "time" + | "timestamp with time zone" + | "timestamptz" + | "timestamp" + | "datetime" => Typ::Datetime, + "uuid" | "json" => Typ::Str(None), + "interval" | "hugeint" => Typ::Str(None), + "s3object" => Typ::Resource("S3Object".to_string()), + _ => Typ::Str(None), + } + } +} + pub fn parse_snowflake_typ(typ: &str) -> Typ { match typ { "varchar" => Typ::Str(None), diff --git a/backend/parsers/windmill-parser-wasm/src/lib.rs b/backend/parsers/windmill-parser-wasm/src/lib.rs index cd280e7af5..4270c28c60 100644 --- a/backend/parsers/windmill-parser-wasm/src/lib.rs +++ b/backend/parsers/windmill-parser-wasm/src/lib.rs @@ -96,6 +96,12 @@ pub fn parse_oracledb(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_oracledb_sig(code)) } +#[cfg(feature = "sql-parser")] +#[wasm_bindgen] +pub fn parse_duckdb(code: &str) -> String { + wrap_sig(windmill_parser_sql::parse_duckdb_sig(code)) +} + #[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_bigquery(code: &str) -> String { diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index fd3e81f209..95d3427410 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.492.1 + version: 1.493.0 title: Windmill API contact: @@ -14242,7 +14242,8 @@ components: ansible, csharp, nu, - java + java, + duckdb # for related places search: ADD_NEW_LANG ] diff --git a/backend/windmill-api/src/workspaces_export.rs b/backend/windmill-api/src/workspaces_export.rs index c58d773f66..cd2be0f708 100644 --- a/backend/windmill-api/src/workspaces_export.rs +++ b/backend/windmill-api/src/workspaces_export.rs @@ -360,6 +360,7 @@ pub(crate) async fn tarball_workspace( ScriptLang::Bigquery => "bq.sql", ScriptLang::Snowflake => "sf.sql", ScriptLang::Mssql => "ms.sql", + ScriptLang::DuckDb => "duckdb.sql", ScriptLang::Graphql => "gql", ScriptLang::Nativets => "fetch.ts", ScriptLang::Bun | ScriptLang::Bunnative => { diff --git a/backend/windmill-common/src/client.rs b/backend/windmill-common/src/client.rs index 95d9f64bd2..0c5394c6e6 100644 --- a/backend/windmill-common/src/client.rs +++ b/backend/windmill-common/src/client.rs @@ -2,7 +2,11 @@ use anyhow::Context; use reqwest::{Body, Response}; use serde::de::DeserializeOwned; -use crate::utils::HTTP_CLIENT; +use crate::{ + error::{self, to_anyhow}, + s3_helpers::{DuckdbConnectionSettingsQueryV2, DuckdbConnectionSettingsResponse}, + utils::HTTP_CLIENT, +}; #[derive(Clone)] pub struct AuthedClient { @@ -197,4 +201,44 @@ impl AuthedClient { _ => Err(anyhow::anyhow!(response.text().await.unwrap_or_default()))?, } } + + pub async fn get_duckdb_connection_settings( + &self, + s3: &DuckdbConnectionSettingsQueryV2, + ) -> error::Result { + let url = format!( + "{}/api/w/{}/job_helpers/v2/duckdb_connection_settings", + self.base_internal_url, &self.workspace + ); + let response = self + .force_client + .as_ref() + .unwrap_or(&HTTP_CLIENT) + .post(url) + .header( + reqwest::header::CONTENT_TYPE, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .header( + reqwest::header::ACCEPT, + reqwest::header::HeaderValue::from_static("application/json"), + ) + .header( + reqwest::header::AUTHORIZATION, + reqwest::header::HeaderValue::from_str(&format!("Bearer {}", self.token)) + .map_err(|e| error::Error::BadConfig(e.to_string()))?, + ) + .body(serde_json::to_string(&s3).map_err(to_anyhow)?) + .send() + .await + .context(format!("Sent get_duckdb_connection_settings request",)) + .map_err(error::Error::from)?; + match response.status().as_u16() { + 200u16 => Ok(response + .json::() + .await + .context("decoding duckdb_connection_settings response as json")?), + _ => Err(anyhow::anyhow!(response.text().await.unwrap_or_default()))?, + } + } } diff --git a/backend/windmill-common/src/s3_helpers.rs b/backend/windmill-common/src/s3_helpers.rs index 29f59cf07c..7e7c48851e 100644 --- a/backend/windmill-common/src/s3_helpers.rs +++ b/backend/windmill-common/src/s3_helpers.rs @@ -891,3 +891,20 @@ pub async fn convert_json_line_stream>( Ok(tokio_stream::wrappers::ReceiverStream::new(rx)) } + +#[derive(Deserialize, Serialize)] +pub struct DuckdbConnectionSettingsResponse { + pub connection_settings_str: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub azure_container_path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub s3_bucket: Option, +} + +#[derive(Deserialize, Serialize)] +pub struct DuckdbConnectionSettingsQueryV2 { + #[serde(skip_serializing_if = "Option::is_none")] + pub s3_resource_path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub storage: Option, +} diff --git a/backend/windmill-common/src/schema.rs b/backend/windmill-common/src/schema.rs index 2b24ead0d3..71ecd220d1 100644 --- a/backend/windmill-common/src/schema.rs +++ b/backend/windmill-common/src/schema.rs @@ -349,7 +349,7 @@ pub fn should_validate_schema(code: &str, lang: &ScriptLang) -> bool { let comment = match lang { Nativets | Bun | Bunnative | Deno | Php | CSharp | Java => "//", Python3 | Go | Bash | Powershell | Graphql | Ansible | Nu => "#", - Postgresql | Mysql | Bigquery | Snowflake | Mssql | OracleDB => "--", + Postgresql | Mysql | Bigquery | Snowflake | Mssql | OracleDB | DuckDb => "--", Rust => "//!", // for related places search: ADD_NEW_LANG }; diff --git a/backend/windmill-common/src/scripts.rs b/backend/windmill-common/src/scripts.rs index e0391767f8..dda9daf0f4 100644 --- a/backend/windmill-common/src/scripts.rs +++ b/backend/windmill-common/src/scripts.rs @@ -46,13 +46,13 @@ pub enum ScriptLang { Graphql, Mssql, OracleDB, + DuckDb, Php, Rust, Ansible, CSharp, Nu, - Java, - // for related places search: ADD_NEW_LANG + Java, // for related places search: ADD_NEW_LANG } impl ScriptLang { @@ -73,6 +73,7 @@ impl ScriptLang { ScriptLang::Mssql => "mssql", ScriptLang::Graphql => "graphql", ScriptLang::OracleDB => "oracledb", + ScriptLang::DuckDb => "duckdb", ScriptLang::Php => "php", ScriptLang::Rust => "rust", ScriptLang::Ansible => "ansible", diff --git a/backend/windmill-common/src/worker.rs b/backend/windmill-common/src/worker.rs index aa1a715758..6b11fa086f 100644 --- a/backend/windmill-common/src/worker.rs +++ b/backend/windmill-common/src/worker.rs @@ -79,6 +79,7 @@ lazy_static::lazy_static! { "csharp".to_string(), "nu".to_string(), "java".to_string(), + "duckdb".to_string(), // for related places search: ADD_NEW_LANG "dependency".to_string(), "flow".to_string(), diff --git a/backend/windmill-worker/Cargo.toml b/backend/windmill-worker/Cargo.toml index 4dccc3213c..dbc8f2ab27 100644 --- a/backend/windmill-worker/Cargo.toml +++ b/backend/windmill-worker/Cargo.toml @@ -31,6 +31,7 @@ csharp = ["dep:windmill-parser-csharp"] rust = ["dep:windmill-parser-rust"] nu = ["dep:windmill-parser-nu"] java = ["dep:windmill-parser-java"] +duckdb = [] [dependencies] windmill-queue.workspace = true @@ -92,6 +93,7 @@ deno_permissions = { workspace = true, optional = true } deno_io = { workspace = true, optional = true } deno_error = { workspace = true, optional = true } async-stream.workspace = true +duckdb.workspace = true postgres-native-tls.workspace = true native-tls.workspace = true diff --git a/backend/windmill-worker/src/duckdb_executor.rs b/backend/windmill-worker/src/duckdb_executor.rs new file mode 100644 index 0000000000..8ee78292d3 --- /dev/null +++ b/backend/windmill-worker/src/duckdb_executor.rs @@ -0,0 +1,664 @@ +use std::collections::HashMap; +use std::env; + +use duckdb::types::TimeUnit; +use duckdb::{params_from_iter, Row}; +use rust_decimal::prelude::FromPrimitive; +use rust_decimal::Decimal; +use serde_json::value::RawValue; +use serde_json::{json, Value}; +use tokio::fs::remove_file; +use tokio::task; +use uuid::Uuid; +use windmill_common::error::{to_anyhow, Error, Result}; +use windmill_common::s3_helpers::{ + DuckdbConnectionSettingsQueryV2, DuckdbConnectionSettingsResponse, S3Object, +}; +use windmill_common::worker::{to_raw_value, Connection}; +use windmill_parser_sql::{parse_duckdb_sig, parse_sql_blocks}; +use windmill_queue::{CanceledBy, MiniPulledJob}; + +use crate::common::{build_args_values, OccupancyMetrics}; +use crate::handle_child::run_future_with_polling_update_job_poller; +#[cfg(feature = "mysql")] +use crate::mysql_executor::MysqlDatabase; +use crate::pg_executor::PgDatabase; +use crate::sanitized_sql_params::sanitize_and_interpolate_unsafe_sql_args; +use windmill_common::client::AuthedClient; + +fn do_duckdb_inner( + conn: &duckdb::Connection, + query: &str, + job_args: &HashMap, + skip_collect: bool, + column_order: &mut Option>, +) -> Result> { + let mut rows_vec = vec![]; + + let (query, job_args) = interpolate_named_args(query, &job_args); + + let mut stmt = conn + .prepare(&query) + .map_err(|e| Error::ExecutionErr(e.to_string()))?; + + let mut rows = stmt + .query(params_from_iter(job_args)) + .map_err(|e| Error::ExecutionErr(e.to_string()))?; + + if skip_collect { + return Ok(to_raw_value(&json!([]))); + } + + // Statement needs to be stepped at least once or stmt.column_names() will panic + let mut column_names = None; + loop { + let row = rows.next(); + match row { + Ok(Some(row)) => { + // Set column names if not already set + let stmt = row.as_ref(); + let column_names = match column_names.as_ref() { + Some(column_names) => column_names, + None => { + column_names = Some(stmt.column_names()); + column_names.as_ref().unwrap() + } + }; + + let row = row_to_value(row, &column_names.as_slice()) + .map_err(|e| Error::ExecutionErr(e.to_string()))?; + rows_vec.push(row); + } + Ok(None) => break, + Err(e) => { + return Err(Error::ExecutionErr(e.to_string())); + } + } + } + + if let (Some(column_order), Some(column_names)) = (column_order.as_mut(), column_names) { + *column_order = column_names.clone(); + } + + return Ok(to_raw_value(&rows_vec)); +} + +pub async fn do_duckdb( + job: &MiniPulledJob, + client: &AuthedClient, + query: &str, + conn: &Connection, + mem_peak: &mut i32, + canceled_by: &mut Option, + worker_name: &str, + column_order_ref: &mut Option>, + occupancy_metrics: &mut OccupancyMetrics, +) -> Result> { + let result_f = async { + let sig = parse_duckdb_sig(query)?.args; + let mut job_args = build_args_values(job, client, conn).await?; + + let (query, _) = &sanitize_and_interpolate_unsafe_sql_args(query, &sig, &job_args)?; + // Prevent interpolate_named_args from detecting argument identifiers in the signature for + // the first query block + let query = trunc_sig(query); + + let (_query_with_transformed_s3_uris, mut used_storages) = + transform_s3_uris(query, client).await?; + let query = _query_with_transformed_s3_uris.as_deref().unwrap_or(query); + + let job_args = { + let mut m: HashMap = HashMap::new(); + for sig_arg in sig.into_iter() { + let json_value = job_args + .remove(&sig_arg.name) + .or_else(|| sig_arg.default) + .unwrap_or_else(|| json!(null)); + + if matches!(&sig_arg.otyp.as_ref().map(String::as_str), Some("s3object")) { + let s3_obj = serde_json::from_value::(json_value).map_err(|e| { + Error::ExecutionErr(format!("Failed to deserialize S3Object: {}", e)) + })?; + let duckdb_conn_settings: windmill_common::s3_helpers::DuckdbConnectionSettingsResponse = client + .get_duckdb_connection_settings(&DuckdbConnectionSettingsQueryV2 { + s3_resource_path: None, + storage: s3_obj.storage.clone(), + }) + .await?; + + let uri = match ( + &duckdb_conn_settings.s3_bucket, + &duckdb_conn_settings.azure_container_path, + ) { + (Some(s3_bucket), None) => format!("s3://{}/{}", s3_bucket, &s3_obj.s3), + (None, Some(az_container)) => format!("{}/{}", az_container, &s3_obj.s3), + _ => { + return Err(Error::ExecutionErr( + "S3Object must have either s3_bucket or azure_container_path" + .to_string(), + )); + } + }; + m.insert(sig_arg.name, duckdb::types::Value::Text(uri)); + used_storages.insert(s3_obj.storage, duckdb_conn_settings); + } else { + let duckdb_value = json_value_to_duckdb_value( + &json_value, + sig_arg + .otyp + .clone() + .unwrap_or_else(|| "text".to_string()) + .as_str(), + client, + )?; + m.insert(sig_arg.name, duckdb_value); + } + } + m + }; + + let query_block_list = parse_sql_blocks(query); + + // Replace windmill resource ATTACH statements with the real instructions + let query_block_list = { + let mut v = vec![]; + for query_block in query_block_list.iter() { + match parse_attach_db_resource(query_block) { + Some(parsed) => v.extend( + transform_attach_db_resource_query(&parsed, &job.id, client).await?, + ), + None => v.push(query_block.to_string()), + }; + } + v + }; + + // duckdb::Connection is not Send so we do it in a single blocking task + let (result, column_order) = task::spawn_blocking(move || { + let conn = duckdb::Connection::open_in_memory() + .map_err(|e| Error::ConnectingToDatabase(e.to_string()))?; + + for (_, DuckdbConnectionSettingsResponse { connection_settings_str, .. }) in + used_storages.into_iter() + { + conn.execute_batch(&connection_settings_str) + .map_err(|e| Error::ExecutionErr(e.to_string()))?; + } + + let mut result: Option> = None; + let mut column_order = None; + for (query_block_index, query_block) in query_block_list.iter().enumerate() { + result = Some( + do_duckdb_inner( + &conn, + query_block.as_str(), + &job_args, + query_block_index != query_block_list.len() - 1, + &mut column_order, + ) + .map_err(|e| Error::ExecutionErr(e.to_string()))?, + ); + } + let result = result.unwrap_or_else(|| to_raw_value(&json!([]))); + Ok::<_, Error>((result, column_order)) + }) + .await + .map_err(to_anyhow)??; + + *column_order_ref = column_order; + + // BigQuery cleanup + let bq_credentials_path = make_bq_credentials_path(&job.id); + env::remove_var("GOOGLE_APPLICATION_CREDENTIALS"); + if matches!(tokio::fs::try_exists(&bq_credentials_path).await, Ok(true)) { + remove_file(&bq_credentials_path).await.map_err(to_anyhow)?; + } + Ok(result) + }; + + let result = run_future_with_polling_update_job_poller( + job.id, + job.timeout, + conn, + mem_peak, + canceled_by, + result_f, + worker_name, + &job.workspace_id, + &mut Some(occupancy_metrics), + Box::pin(futures::stream::once(async { 0 })), + ) + .await?; + + Ok(result) +} + +fn row_to_value(row: &Row<'_>, column_names: &[String]) -> Result> { + let mut obj = serde_json::Map::new(); + for (i, key) in column_names.iter().enumerate() { + let value: duckdb::types::Value = + row.get(i).map_err(|e| Error::ExecutionErr(e.to_string()))?; + let json_value = match value { + duckdb::types::Value::Null => serde_json::Value::Null, + duckdb::types::Value::Boolean(b) => serde_json::Value::Bool(b), + duckdb::types::Value::TinyInt(i) => serde_json::Value::Number(i.into()), + duckdb::types::Value::SmallInt(i) => serde_json::Value::Number(i.into()), + duckdb::types::Value::Int(i) => serde_json::Value::Number(i.into()), + duckdb::types::Value::BigInt(i) => serde_json::Value::Number(i.into()), + duckdb::types::Value::HugeInt(i) => serde_json::Value::String(i.to_string()), + duckdb::types::Value::UTinyInt(u) => serde_json::Value::Number(u.into()), + duckdb::types::Value::USmallInt(u) => serde_json::Value::Number(u.into()), + duckdb::types::Value::UInt(u) => serde_json::Value::Number(u.into()), + duckdb::types::Value::UBigInt(u) => serde_json::Value::Number(u.into()), + duckdb::types::Value::Float(f) => serde_json::Value::Number( + serde_json::Number::from_f64(f as f64) + .ok_or_else(|| Error::ExecutionErr("Could not convert to f64".to_string()))?, + ), + duckdb::types::Value::Double(f) => serde_json::Value::Number( + serde_json::Number::from_f64(f) + .ok_or_else(|| Error::ExecutionErr("Could not convert to f64".to_string()))?, + ), + duckdb::types::Value::Decimal(d) => serde_json::Value::String(d.to_string()), + duckdb::types::Value::Timestamp(_, ts) => serde_json::Value::String(ts.to_string()), + duckdb::types::Value::Text(s) => serde_json::Value::String(s), + duckdb::types::Value::Blob(b) => serde_json::Value::Array( + b.into_iter() + .map(|byte| serde_json::Value::Number(byte.into())) + .collect(), + ), + duckdb::types::Value::Date32(d) => serde_json::Value::Number(d.into()), + duckdb::types::Value::Time64(_, t) => serde_json::Value::String(t.to_string()), + duckdb::types::Value::Interval { months, days, nanos } => serde_json::json!({ + "months": months, + "days": days, + "nanos": nanos + }), + duckdb::types::Value::List(values) => serde_json::Value::Array( + values + .into_iter() + .map(|v| serde_json::Value::String(format!("{:?}", v))) + .collect(), + ), + duckdb::types::Value::Enum(e) => serde_json::Value::String(e), + duckdb::types::Value::Struct(fields) => serde_json::Value::Object( + fields + .iter() + .map(|(k, v)| (k.clone(), serde_json::Value::String(format!("{:?}", v)))) + .collect(), + ), + duckdb::types::Value::Array(values) => serde_json::Value::Array( + values + .into_iter() + .map(|v| serde_json::Value::String(format!("{:?}", v))) + .collect(), + ), + duckdb::types::Value::Map(map) => serde_json::Value::Object( + map.iter() + .map(|(k, v)| { + ( + format!("{:?}", k), + serde_json::Value::String(format!("{:?}", v)), + ) + }) + .collect(), + ), + duckdb::types::Value::Union(value) => { + serde_json::Value::String(format!("{:?}", *value)) + } + }; + obj.insert(key.clone(), json_value); + } + serde_json::value::to_raw_value(&obj).map_err(|e| e.into()) +} + +fn json_value_to_duckdb_value( + json_value: &serde_json::Value, + arg_type: &str, + client: &AuthedClient, +) -> Result { + let arg_type = arg_type.to_lowercase(); + let duckdb_value = match json_value { + serde_json::Value::Null => duckdb::types::Value::Null, + serde_json::Value::Bool(b) => duckdb::types::Value::Boolean(*b), + + serde_json::Value::String(s) + if matches!( + arg_type.as_str(), + "timestamp" | "timestamptz" | "timestamp with time zone" | "datetime" + ) => + { + string_to_duckdb_timestamp(&s)? + } + serde_json::Value::String(s) if arg_type.as_str() == "date" => string_to_duckdb_date(&s)?, + serde_json::Value::String(s) if arg_type.as_str() == "time" => string_to_duckdb_time(&s)?, + serde_json::Value::String(s) => duckdb::types::Value::Text(s.clone()), + + serde_json::Value::Number(n) if n.is_i64() => { + let v = n.as_i64().unwrap(); + match arg_type.as_str() { + "tinyint" | "int1" => duckdb::types::Value::TinyInt(v as i8), + "smallint" | "int2" | "short" => duckdb::types::Value::SmallInt(v as i16), + "integer" | "int4" | "int" | "signed" => duckdb::types::Value::Int(v as i32), + "bigint" | "int8" | "long" => duckdb::types::Value::BigInt(v), + "hugeint" => duckdb::types::Value::HugeInt(v as i128), + "float" | "float4" | "real" => duckdb::types::Value::Float(v as f32), + "double" | "float8" => duckdb::types::Value::Double(v as f64), + _ => duckdb::types::Value::BigInt(v), // default fallback + } + } + + serde_json::Value::Number(n) if n.is_u64() => { + let v = n.as_u64().unwrap(); + match arg_type.as_str() { + "utinyint" => duckdb::types::Value::UTinyInt(v as u8), + "usmallint" => duckdb::types::Value::USmallInt(v as u16), + "uinteger" => duckdb::types::Value::UInt(v as u32), + "ubigint" | "uhugeint" => duckdb::types::Value::UBigInt(v), + _ => duckdb::types::Value::UBigInt(v), // default fallback + } + } + + serde_json::Value::Number(n) if n.is_f64() => { + let v = n.as_f64().unwrap(); + match arg_type.as_str() { + "float" | "float4" | "real" => duckdb::types::Value::Float(v as f32), + "double" | "float8" => duckdb::types::Value::Double(v), + "decimal" | "numeric" => { + duckdb::types::Value::Decimal(Decimal::from_f64(v).ok_or_else(|| { + Error::ExecutionErr("Could not convert f64 to Decimal".to_string()) + })?) + } + _ => duckdb::types::Value::Double(v), // default fallback + } + } + + serde_json::Value::Array(arr) => duckdb::types::Value::Array( + arr.iter() + .map(|val| json_value_to_duckdb_value(val, arg_type.as_str(), client)) + .collect::>>()?, + ), + serde_json::Value::Object(map) => duckdb::types::Value::Struct( + map.iter() + .map(|(k, v)| { + Ok::<_, Error>(( + k.clone(), + json_value_to_duckdb_value(v, arg_type.as_str(), client)?, + )) + }) + .collect::>>()? + .into(), + ), + + value @ _ => { + return Err(Error::ExecutionErr(format!( + "Unsupported type in query: {:?} and signature {arg_type:?}", + value + ))) + } + }; + Ok(duckdb_value) +} + +fn string_to_duckdb_timestamp(s: &str) -> Result { + let ts = chrono::DateTime::parse_from_rfc3339(s) + .map_err(|e: chrono::ParseError| Error::ExecutionErr(e.to_string()))?; + Ok(duckdb::types::Value::Timestamp( + TimeUnit::Millisecond, + ts.timestamp_millis(), + )) +} + +fn string_to_duckdb_date(s: &str) -> Result { + use chrono::Datelike; + let date = chrono::NaiveDate::parse_from_str(s, "%Y-%m-%d").unwrap(); + Ok(duckdb::types::Value::Date32(date.num_days_from_ce())) +} + +fn string_to_duckdb_time(s: &str) -> Result { + use chrono::Timelike; + let time = chrono::NaiveTime::parse_from_str(s, "%H:%M:%S").unwrap(); + Ok(duckdb::types::Value::Time64( + TimeUnit::Microsecond, + time.num_seconds_from_midnight() as i64, + )) +} + +struct ParsedAttachDbResource<'a> { + resource_path: &'a str, + name: &'a str, + db_type: &'a str, + extra_args: Option<&'a str>, +} +fn parse_attach_db_resource<'a>(query: &'a str) -> Option> { + lazy_static::lazy_static! { + static ref RE: regex::Regex = regex::Regex::new(r"ATTACH '\$res:([^']+)' AS (\S+) \(TYPE (\w+)(.*)\)").unwrap(); + } + + for cap in RE.captures_iter(query) { + if let (Some(resource_path), Some(name), Some(db_type)) = + (cap.get(1), cap.get(2), cap.get(3)) + { + let extra_args = cap.get(4).map(|m| query[m.start()..m.end()].trim()); + return Some(ParsedAttachDbResource { + resource_path: query[resource_path.start()..resource_path.end()].trim(), + name: query[name.start()..name.end()].trim(), + db_type: query[db_type.start()..db_type.end()].trim(), + extra_args, + }); + } + } + None +} + +async fn transform_attach_db_resource_query( + parsed: &ParsedAttachDbResource<'_>, + job_id: &Uuid, + client: &AuthedClient, +) -> Result> { + match parsed.db_type.to_lowercase().as_str() { + "postgres" => { + let resource: PgDatabase = client + .get_resource_value_interpolated(parsed.resource_path, Some(job_id.to_string())) + .await?; + + let attach_str = format!( + "ATTACH 'dbname={} {} host={} {} {}' AS {} (TYPE postgres{});", + resource.dbname, + resource + .user + .map(|u| format!("user={}", u)) + .unwrap_or_default(), + resource.host, + resource + .password + .map(|p| format!("password={}", p)) + .unwrap_or_default(), + resource + .port + .map(|p| format!("port={}", p)) + .unwrap_or_default(), + parsed.name, + parsed.extra_args.unwrap_or("") + ); + + Ok(vec![ + "INSTALL postgres;".to_string(), + "LOAD postgres;".to_string(), + attach_str, + ]) + } + "mysql" => { + #[cfg(not(feature = "mysql"))] + return Err(Error::ExecutionErr( + "MySQL feature is not enabled".to_string(), + )); + + #[cfg(feature = "mysql")] + { + let resource: MysqlDatabase = client + .get_resource_value_interpolated(parsed.resource_path, Some(job_id.to_string())) + .await?; + + let attach_str = format!( + "ATTACH 'database={} host={} ssl_mode={} {} {} {}' AS {} (TYPE mysql{});", + resource.database, + resource.host, + resource + .ssl + .map(|ssl| if ssl { "required" } else { "disabled" }) + .unwrap_or("preferred"), + resource + .password + .map(|p| format!("password={}", p)) + .unwrap_or_default(), + resource + .port + .map(|p| format!("port={}", p)) + .unwrap_or_default(), + resource + .user + .map(|u| format!("user={}", u)) + .unwrap_or_default(), + parsed.name, + parsed.extra_args.unwrap_or("") + ); + + Ok(vec![ + "INSTALL mysql;".to_string(), + "LOAD mysql;".to_string(), + attach_str, + ]) + } + } + "bigquery" => { + let resource: Value = client + .get_resource_value_interpolated(parsed.resource_path, Some(job_id.to_string())) + .await?; + // duckdb's bigquery extension requires a json file as credentials + let bq_credentials_path = make_bq_credentials_path(job_id); + env::set_var("GOOGLE_APPLICATION_CREDENTIALS", &bq_credentials_path); + tokio::fs::write(&bq_credentials_path, resource.to_string()) + .await + .map_err(|e| { + Error::ExecutionErr(format!( + "Failed to write BigQuery credentials to {}: {}", + &bq_credentials_path, e + )) + })?; + let project_id: String = serde_json::from_value( + resource + .get("project_id") + .ok_or_else(|| { + Error::ExecutionErr("BigQuery resource must contain project_id".to_string()) + })? + .to_owned(), + ) + .map_err(|_e| Error::ExecutionErr("failed project_id deserialize".to_string()))?; + let attach_str = format!( + "ATTACH 'project={}' as {} (TYPE bigquery{});", + project_id, + parsed.name, + parsed.extra_args.unwrap_or("") + ) + .to_string(); + Ok(vec![ + "INSTALL bigquery FROM community;".to_string(), + "LOAD bigquery;".to_string(), + attach_str, + ]) + } + _ => Err(Error::ExecutionErr(format!( + "Unsupported db type in DuckDB ATTACH: {}", + parsed.db_type + ))), + } +} + +// Returns the transformed query and the set of storages used +async fn transform_s3_uris( + query: &str, + client: &AuthedClient, +) -> Result<( + Option, + HashMap, DuckdbConnectionSettingsResponse>, +)> { + let mut transformed_query = None; + lazy_static::lazy_static! { + static ref RE: regex::Regex = regex::Regex::new(r"'s3://([^'/]*)/([^']+)'").unwrap(); + } + let mut used_storages = HashMap::new(); + for cap in RE.captures_iter(query) { + if let (storage, Some(s3_path)) = (cap.get(1), cap.get(2)) { + let s3_path = s3_path.as_str(); + let storage = match storage.map(|m| m.as_str()) { + Some("") | None => None, + Some(s) => Some(s.to_string()), + }; + let original_str_lit = + format!("'s3://{}/{}'", storage.as_deref().unwrap_or(""), s3_path); + let duckdb_conn_settings = client + .get_duckdb_connection_settings(&DuckdbConnectionSettingsQueryV2 { + s3_resource_path: None, + storage: storage.clone(), + }) + .await?; + let url = match &duckdb_conn_settings { + DuckdbConnectionSettingsResponse { s3_bucket: Some(bucket), .. } => { + format!("'s3://{bucket}/{s3_path}'") + } + DuckdbConnectionSettingsResponse { azure_container_path: Some(base), .. } => { + format!("'{base}/{s3_path}'") + } + _ => { + return Err(Error::ExecutionErr( + "DuckDB connection settings response must have either s3_bucket or azure_container_path".to_string(), + ))?; + } + }; + transformed_query = Some( + transformed_query + .unwrap_or(query.to_string()) + .replace(&original_str_lit, &url), + ); + used_storages.insert(storage, duckdb_conn_settings); + } + } + Ok((transformed_query, used_storages)) +} + +// BigQuery extension requires a json file as credentials +// The file path is set as an env var by do_duckdb +// It is created by transform_attach_db_resource_query (when bigquery is detected) +// and deleted by do_duckdb after the query is executed +fn make_bq_credentials_path(job_id: &Uuid) -> String { + format!("/tmp/service-account-credentials-{}.json", job_id) +} + +// duckdb-rs does not support named parameters, +// and it raises an error when passing unused arguments. We cannot prepare batch statements +// but only single SQL statements so it doesn't work when all arguments are not used by +// every single statement. +fn interpolate_named_args<'a>( + query: &str, + args: &'a HashMap, +) -> (String, Vec<&'a duckdb::types::Value>) { + let mut query = query.to_string(); + + let mut values = vec![]; + for (arg_name, arg_value) in args { + let pat = format!("${}", arg_name); + if !query.contains(&pat) { + continue; + } + values.push(arg_value); + query = query.replace(&pat, &format!("${}", values.len())); + } + (query, values) +} + +fn trunc_sig(query: &str) -> &str { + let idx = query.rfind("-- $").unwrap_or(query.len()); + // find next \n starting from idx and return everything after it + let idx = query[idx..].find('\n').map(|i| i + idx).unwrap_or(0); + &query[idx..] +} diff --git a/backend/windmill-worker/src/lib.rs b/backend/windmill-worker/src/lib.rs index 4ea56c090e..fa6eb10960 100644 --- a/backend/windmill-worker/src/lib.rs +++ b/backend/windmill-worker/src/lib.rs @@ -20,6 +20,8 @@ mod csharp_executor; #[cfg(feature = "enterprise")] mod dedicated_worker; mod deno_executor; +#[cfg(feature = "duckdb")] +mod duckdb_executor; mod global_cache; mod go_executor; mod graphql_executor; diff --git a/backend/windmill-worker/src/mysql_executor.rs b/backend/windmill-worker/src/mysql_executor.rs index ffd84db175..04403e4e08 100644 --- a/backend/windmill-worker/src/mysql_executor.rs +++ b/backend/windmill-worker/src/mysql_executor.rs @@ -32,13 +32,13 @@ use crate::{ }; #[derive(Deserialize)] -struct MysqlDatabase { - host: String, - user: Option, - password: Option, - port: Option, - database: String, - ssl: Option, +pub struct MysqlDatabase { + pub host: String, + pub user: Option, + pub password: Option, + pub port: Option, + pub database: String, + pub ssl: Option, } fn do_mysql_inner<'a>( diff --git a/backend/windmill-worker/src/pg_executor.rs b/backend/windmill-worker/src/pg_executor.rs index 67c2d945aa..2c7fe123dc 100644 --- a/backend/windmill-worker/src/pg_executor.rs +++ b/backend/windmill-worker/src/pg_executor.rs @@ -47,14 +47,14 @@ use lazy_static::lazy_static; use urlencoding::encode; use windmill_common::client::AuthedClient; #[derive(Deserialize)] -struct PgDatabase { - host: String, - user: Option, - password: Option, - port: Option, - sslmode: Option, - dbname: String, - root_certificate_pem: Option, +pub struct PgDatabase { + pub host: String, + pub user: Option, + pub password: Option, + pub port: Option, + pub sslmode: Option, + pub dbname: String, + pub root_certificate_pem: Option, } lazy_static! { diff --git a/backend/windmill-worker/src/windmill-client.js b/backend/windmill-worker/src/windmill-client.js index 3ae15e7453..1ecf28e664 100644 --- a/backend/windmill-worker/src/windmill-client.js +++ b/backend/windmill-worker/src/windmill-client.js @@ -2998,6 +2998,8 @@ var $RawScript = { "mssql", "graphql", "nativets", + "duckdb", + // for related places search: ADD_NEW_LANG ], }, path: { diff --git a/backend/windmill-worker/src/worker.rs b/backend/windmill-worker/src/worker.rs index 221650389a..e15c24ef70 100644 --- a/backend/windmill-worker/src/worker.rs +++ b/backend/windmill-worker/src/worker.rs @@ -145,6 +145,9 @@ use crate::ansible_executor::handle_ansible_job; #[cfg(feature = "mysql")] use crate::mysql_executor::do_mysql; +#[cfg(feature = "duckdb")] +use crate::duckdb_executor::do_duckdb; + #[cfg(feature = "oracledb")] use crate::oracledb_executor::do_oracledb; @@ -2614,6 +2617,30 @@ async fn handle_code_execution_job( ) .await; } + } else if language == Some(ScriptLang::DuckDb) { + #[allow(unreachable_code)] + #[cfg(not(feature = "duckdb"))] + { + return Err(Error::internal_err( + "Duck DB requires the duckdb feature to be enabled".to_string(), + )); + } + + #[cfg(feature = "duckdb")] + { + return do_duckdb( + job, + &client, + &code, + conn, + mem_peak, + canceled_by, + worker_name, + column_order, + occupancy_metrics, + ) + .await; + } } else if language == Some(ScriptLang::Graphql) { return do_graphql( job, @@ -3021,6 +3048,7 @@ fn parse_sig_of_lang( ScriptLang::Snowflake => Some(windmill_parser_sql::parse_snowflake_sig(code)?), ScriptLang::Graphql => None, ScriptLang::Mssql => Some(windmill_parser_sql::parse_mssql_sig(code)?), + ScriptLang::DuckDb => Some(windmill_parser_sql::parse_duckdb_sig(code)?), ScriptLang::OracleDB => Some(windmill_parser_sql::parse_oracledb_sig(code)?), #[cfg(feature = "php")] ScriptLang::Php => Some(windmill_parser_php::parse_php_signature( diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index a03010948b..eec410a62d 100644 --- a/benchmarks/lib.ts +++ b/benchmarks/lib.ts @@ -2,7 +2,7 @@ import { sleep } from "https://deno.land/x/sleep@v1.2.1/mod.ts"; import * as windmill from "https://deno.land/x/windmill@v1.174.0/mod.ts"; import * as api from "https://deno.land/x/windmill@v1.174.0/windmill-api/index.ts"; -export const VERSION = "v1.492.1"; +export const VERSION = "v1.493.0"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ diff --git a/cli/bootstrap/script_bootstrap.ts b/cli/bootstrap/script_bootstrap.ts index 2ac67bdb83..e9e8a12db5 100644 --- a/cli/bootstrap/script_bootstrap.ts +++ b/cli/bootstrap/script_bootstrap.ts @@ -76,6 +76,7 @@ func main() (interface{}, error) { bash: `echo "Hello world" `, + duckdb: `SELECT 'Hello world' AS message`, oracledb: `SELECT 'Hello world' AS message`, powershell: `Write-Output "Hello world"`, @@ -126,5 +127,5 @@ public class Main { } } `, -// for related places search: ADD_NEW_LANG + // for related places search: ADD_NEW_LANG }; diff --git a/cli/build.sh b/cli/build.sh index bf00b99a57..e228750b51 100755 --- a/cli/build.sh +++ b/cli/build.sh @@ -1,3 +1,4 @@ #!/bin/bash +# Note for mac OS users: you need to install gnu-sed with `brew install gnu-sed` and use `gsed` instead of `sed`. ./gen_wm_client.sh deno run -A dnt.ts diff --git a/cli/main.ts b/cli/main.ts index e87c8b14a5..e2b81700bf 100644 --- a/cli/main.ts +++ b/cli/main.ts @@ -63,7 +63,7 @@ export { // } // }); -export const VERSION = "1.492.1"; +export const VERSION = "1.493.0"; const command = new Command() .name("wmill") diff --git a/cli/metadata.ts b/cli/metadata.ts index 3a83143182..ee39d0b9da 100644 --- a/cli/metadata.ts +++ b/cli/metadata.ts @@ -528,6 +528,9 @@ export async function inferSchema( { name: "database", typ: { resource: "postgresql" } }, ...inferedSchema.args, ]; + } else if (language === "duckdb") { + const { parse_sql } = await import("./wasm/regex/windmill_parser_wasm.js"); + inferedSchema = JSON.parse(parse_sql(content)); } else if (language === "graphql") { const { parse_graphql } = await import( "./wasm/regex/windmill_parser_wasm.js" diff --git a/cli/script.ts b/cli/script.ts index 3896d19c5c..e12c15d9ba 100644 --- a/cli/script.ts +++ b/cli/script.ts @@ -547,6 +547,8 @@ export function filePathExtensionFromContentType( return ".my.sql"; } else if (language === "bigquery") { return ".bq.sql"; + } else if (language === "duckdb") { + return ".duckdb.sql"; } else if (language === "oracledb") { return ".odb.sql"; } else if (language === "snowflake") { @@ -573,7 +575,7 @@ export function filePathExtensionFromContentType( return ".nu"; } else if (language === "java") { return ".java"; - // for related places search: ADD_NEW_LANG + // for related places search: ADD_NEW_LANG } else { throw new Error("Invalid language: " + language); } @@ -593,6 +595,7 @@ export const exts = [ ".odb.sql", ".sf.sql", ".ms.sql", + ".duckdb.sql", ".sql", ".gql", ".ps1", @@ -601,9 +604,8 @@ export const exts = [ ".cs", ".nu", ".playbook.yml", - ".java" - // for related places search: ADD_NEW_LANG - + ".java", + // for related places search: ADD_NEW_LANG ]; export function removeExtensionToPath(path: string): string { diff --git a/cli/script_common.ts b/cli/script_common.ts index a41d7dee8c..39906e7bb9 100644 --- a/cli/script_common.ts +++ b/cli/script_common.ts @@ -9,6 +9,7 @@ export type ScriptLanguage = | "postgresql" | "mysql" | "bigquery" + | "duckdb" | "oracledb" | "snowflake" | "mssql" @@ -19,7 +20,7 @@ export type ScriptLanguage = | "nu" | "ansible" | "java"; - // for related places search: ADD_NEW_LANG +// for related places search: ADD_NEW_LANG export function inferContentTypeFromFilePath( contentPath: string, @@ -43,6 +44,8 @@ export function inferContentTypeFromFilePath( return "bigquery"; } else if (contentPath.endsWith(".odb.sql")) { return "oracledb"; + } else if (contentPath.endsWith(".duckdb.sql")) { + return "duckdb"; } else if (contentPath.endsWith(".sf.sql")) { return "snowflake"; } else if (contentPath.endsWith(".ms.sql")) { @@ -67,7 +70,7 @@ export function inferContentTypeFromFilePath( return "nu"; } else if (contentPath.endsWith(".java")) { return "java"; - // for related places search: ADD_NEW_LANG + // for related places search: ADD_NEW_LANG } else { throw new Error( "Invalid language: " + contentPath.substring(contentPath.lastIndexOf(".")) diff --git a/cli/sync.ts b/cli/sync.ts index 867b8c4d17..456afcadf9 100644 --- a/cli/sync.ts +++ b/cli/sync.ts @@ -344,6 +344,7 @@ export function newPathAssigner(defaultTs: "bun" | "deno"): PathAssigner { else if (language == "nu") ext = "nu"; else if (language == "ansible") ext = "playbook.yml"; else if (language == "java") ext = "java"; + else if (language == "duckdb") ext = "duckdb.sql"; // for related places search: ADD_NEW_LANG else ext = "no_ext"; diff --git a/cli/wasm/regex/windmill_parser_wasm.js b/cli/wasm/regex/windmill_parser_wasm.js index 5418fad879..7867ab4a35 100644 --- a/cli/wasm/regex/windmill_parser_wasm.js +++ b/cli/wasm/regex/windmill_parser_wasm.js @@ -1,5 +1,6 @@ + let WASM_VECTOR_LEN = 0; let cachedUint8ArrayMemory0 = null; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 899306ebf0..eeaa3fea44 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.492.1", + "version": "1.493.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.492.1", + "version": "1.493.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -74,7 +74,7 @@ "windmill-parser-wasm-nu": "^1.474.1", "windmill-parser-wasm-php": "^1.429.0", "windmill-parser-wasm-py": "^1.477.1", - "windmill-parser-wasm-regex": "^1.481.0", + "windmill-parser-wasm-regex": "^1.492.1", "windmill-parser-wasm-rust": "^1.429.0", "windmill-parser-wasm-ts": "^1.486.1", "windmill-parser-wasm-yaml": "^1.429.0", @@ -12837,9 +12837,9 @@ "integrity": "sha512-EY3mSMWpqFPzd7fsLg2/hSfQFU8HpW9nplFwm4JHHCDbcTpBzlvzjPJoHAAGO5kMzowAxjqi5ai/mXjeUWuiSg==" }, "node_modules/windmill-parser-wasm-regex": { - "version": "1.481.0", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-regex/-/windmill-parser-wasm-regex-1.481.0.tgz", - "integrity": "sha512-QY9NOaF0M55SBEbbcAkHoXppjdS2gb2NlwqhlZ1ciYWTtIrbZoL5K8xoG4FbB5vWRHxInG1aRdA2tb+JP180yA==" + "version": "1.492.1", + "resolved": "https://registry.npmjs.org/windmill-parser-wasm-regex/-/windmill-parser-wasm-regex-1.492.1.tgz", + "integrity": "sha512-CBdjz3x00z2xA4BRZv8/hsuHcpZgL28UKTjYVSj5O9XMYlY9g0LNsEQ5TTl/oVyFBs62/CPyvWwGvW4oSAObzg==" }, "node_modules/windmill-parser-wasm-rust": { "version": "1.429.0", diff --git a/frontend/package.json b/frontend/package.json index 51c7820491..9f792acac3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "windmill-components", - "version": "1.492.1", + "version": "1.493.0", "scripts": { "dev": "vite dev", "build": "vite build", @@ -143,7 +143,7 @@ "windmill-parser-wasm-nu": "^1.474.1", "windmill-parser-wasm-php": "^1.429.0", "windmill-parser-wasm-py": "^1.477.1", - "windmill-parser-wasm-regex": "^1.481.0", + "windmill-parser-wasm-regex": "^1.492.1", "windmill-parser-wasm-rust": "^1.429.0", "windmill-parser-wasm-ts": "^1.486.1", "windmill-parser-wasm-yaml": "^1.429.0", @@ -371,6 +371,10 @@ "types": "./package/components/SimpleEditor.svelte.d.ts", "svelte": "./package/components/SimpleEditor.svelte", "default": "./package/components/SimpleEditor.svelte" + }, + "./tailwindUtils": { + "types": "./package/components/apps/editor/componentsPanel/tailwindUtils.d.ts", + "default": "./package/components/apps/editor/componentsPanel/tailwindUtils.js" } }, "files": [ @@ -506,6 +510,9 @@ ], "components/icons/store": [ "./package/components/icons/store.d.ts" + ], + "tailwindUtils": [ + "./package/components/apps/editor/componentsPanel/tailwindUtils.d.ts" ] } }, diff --git a/frontend/src/lib/components/Editor.svelte b/frontend/src/lib/components/Editor.svelte index 35c4576251..aa1aa5f0b0 100644 --- a/frontend/src/lib/components/Editor.svelte +++ b/frontend/src/lib/components/Editor.svelte @@ -115,7 +115,7 @@ import { workspaceStore } from '$lib/stores' import { type Preview, ResourceService, UserService } from '$lib/gen' import type { Text } from 'yjs' - import { initializeVscode } from '$lib/components/vscode' + import { initializeVscode, keepModelAroundToAvoidDisposalOfWorkers } from '$lib/components/vscode' import { initializeMode } from 'monaco-graphql/esm/initializeMode.js' import type { MonacoGraphQLAPI } from 'monaco-graphql/esm/api.js' @@ -133,6 +133,7 @@ import EditorTheme from './EditorTheme.svelte' import { BIGQUERY_TYPES, + DUCKDB_TYPES, MSSQL_TYPES, MYSQL_TYPES, ORACLEDB_TYPES, @@ -482,7 +483,9 @@ ? MSSQL_TYPES : scriptLang === 'oracledb' ? ORACLEDB_TYPES - : [] + : scriptLang === 'duckdb' + ? DUCKDB_TYPES + : [] ).map((t) => ({ label: t, kind: languages.CompletionItemKind.Function, @@ -1263,6 +1266,8 @@ folding }) + keepModelAroundToAvoidDisposalOfWorkers() + // updateEditorKeybindingsMode(editor, 'vim', undefined) let ataModel: NodeJS.Timeout | undefined = undefined @@ -1352,6 +1357,7 @@ try { closeWebsockets() vimDisposable?.dispose() + console.log('disposing editor', editor, model) model?.dispose() editor && editor.dispose() console.log('disposed editor') diff --git a/frontend/src/lib/components/HighlightCode.svelte b/frontend/src/lib/components/HighlightCode.svelte index ac4357e5ca..bf196c7868 100644 --- a/frontend/src/lib/components/HighlightCode.svelte +++ b/frontend/src/lib/components/HighlightCode.svelte @@ -55,6 +55,8 @@ return sql case 'oracledb': return sql + case 'duckdb': + return sql case 'powershell': return powershell case 'php': @@ -66,10 +68,10 @@ case 'nu': return python case 'ansible': - return yaml; + return yaml case 'java': - return java; - // for related places search: ADD_NEW_LANG + return java + // for related places search: ADD_NEW_LANG default: return typescript } diff --git a/frontend/src/lib/components/SimpleEditor.svelte b/frontend/src/lib/components/SimpleEditor.svelte index 3cc814b855..d3c498054d 100644 --- a/frontend/src/lib/components/SimpleEditor.svelte +++ b/frontend/src/lib/components/SimpleEditor.svelte @@ -7,6 +7,16 @@ import '@codingame/monaco-vscode-standalone-css-language-features' import '@codingame/monaco-vscode-standalone-typescript-language-features' import '@codingame/monaco-vscode-standalone-html-language-features' + import { + editor as meditor, + KeyCode, + KeyMod, + Uri as mUri, + languages, + type IRange, + type IDisposable + } from 'monaco-editor' + languages.typescript.javascriptDefaults.setCompilerOptions({ target: languages.typescript.ScriptTarget.Latest, allowNonTsExtensions: true, @@ -44,15 +54,15 @@ import { BROWSER } from 'esm-env' import { createHash, editorConfig, langToExt, updateOptions } from '$lib/editorUtils' - import { - editor as meditor, - KeyCode, - KeyMod, - Uri as mUri, - languages, - type IRange, - type IDisposable - } from 'monaco-editor' + // import { + // editor as meditor, + // KeyCode, + // KeyMod, + // Uri as mUri, + // languages, + // type IRange, + // type IDisposable + // } from 'monaco-editor' import { allClasses } from './apps/editor/componentsPanel/cssUtils' @@ -60,7 +70,7 @@ import libStdContent from '$lib/es6.d.ts.txt?raw' import domContent from '$lib/dom.d.ts.txt?raw' - import { initializeVscode } from './vscode' + import { initializeVscode, keepModelAroundToAvoidDisposalOfWorkers } from './vscode' import EditorTheme from './EditorTheme.svelte' import { vimMode } from '$lib/stores' import { initVim } from './monaco_keybindings' @@ -348,6 +358,7 @@ snippetsPreventQuickSuggestions: disableSuggestions } }) + keepModelAroundToAvoidDisposalOfWorkers() let timeoutModel: NodeJS.Timeout | undefined = undefined editor.onDidChangeModelContent((event) => { @@ -467,33 +478,46 @@ } function addTailwindClassCompletions() { + // Define a custom word definition for Tailwind classes + languages.setMonarchTokensProvider('tailwindcss', { + tokenizer: { + root: [[/[a-zA-Z0-9-]+/, 'tailwind-class']] + } + }) + languages.registerCompletionItemProvider('tailwindcss', { + triggerCharacters: ['-'], provideCompletionItems: function (model, position, context, token) { - const word = model.getWordUntilPosition(position) + const wordUntilPosition = model.getWordUntilPosition(position) + const lineContent = model.getLineContent(position.lineNumber) + + // Get the text from the start of the line to the cursor + const textUntilPosition = lineContent.substring(0, position.column - 1) + // Find the last space before the cursor + const lastSpaceIndex = textUntilPosition.lastIndexOf(' ') + const startColumn = lastSpaceIndex === -1 ? 1 : lastSpaceIndex + 2 + const range = { startLineNumber: position.lineNumber, - startColumn: word.startColumn, + startColumn: startColumn, endLineNumber: position.lineNumber, - endColumn: word.endColumn + endColumn: position.column } - if (word && word.word) { - const currentWord = word.word + const currentWord = wordUntilPosition.word - const suggestions = tailwindClasses - .filter((className) => className.includes(currentWord)) - .map((className) => ({ - label: className, - kind: languages.CompletionItemKind.Class, - insertText: className, - documentation: 'Custom CSS class', - range: range - })) + const suggestions = tailwindClasses + .filter((className) => className.includes(currentWord)) + .map((className) => ({ + label: className, + kind: languages.CompletionItemKind.Class, + insertText: className, + documentation: 'Tailwind CSS class', + range: range, + preselect: true + })) - return { suggestions } - } - - return { suggestions: [] } + return { suggestions } } }) } diff --git a/frontend/src/lib/components/TemplateEditor.svelte b/frontend/src/lib/components/TemplateEditor.svelte index 941c72fc74..22d3fc6776 100644 --- a/frontend/src/lib/components/TemplateEditor.svelte +++ b/frontend/src/lib/components/TemplateEditor.svelte @@ -1,3 +1,21 @@ + + - diff --git a/frontend/src/lib/components/apps/editor/AppPreview.svelte b/frontend/src/lib/components/apps/editor/AppPreview.svelte index 2cc07c05bc..1438f0712c 100644 --- a/frontend/src/lib/components/apps/editor/AppPreview.svelte +++ b/frontend/src/lib/components/apps/editor/AppPreview.svelte @@ -243,7 +243,6 @@ - diff --git a/frontend/src/lib/components/common/languageIcons/LanguageIcon.svelte b/frontend/src/lib/components/common/languageIcons/LanguageIcon.svelte index 9dd3c9860a..6a3de43bf9 100644 --- a/frontend/src/lib/components/common/languageIcons/LanguageIcon.svelte +++ b/frontend/src/lib/components/common/languageIcons/LanguageIcon.svelte @@ -22,6 +22,7 @@ import CSharpIcon from '$lib/components/icons/CSharpIcon.svelte' import NuIcon from '$lib/components/icons/NuIcon.svelte' import JavaIcon from '$lib/components/icons/JavaIcon.svelte' + import DuckDbIcon from '$lib/components/icons/DuckDbIcon.svelte' export let lang: | SupportedLanguage @@ -49,6 +50,7 @@ postgresql: 'Postgresql', bigquery: 'BigQuery', oracledb: 'Oracle Database', + duckdb: 'DuckDB', snowflake: 'Snowflake', mysql: 'MySQL', mssql: 'MS SQL Server', @@ -59,7 +61,7 @@ csharp: 'C#', nu: 'Nu', java: 'Java' - // for related places search: ADD_NEW_LANG + // for related places search: ADD_NEW_LANG } const langToComponent: Record< @@ -91,8 +93,9 @@ ansible: AnsibleIcon, csharp: CSharpIcon, nu: NuIcon, - java: JavaIcon - // for related places search: ADD_NEW_LANG + java: JavaIcon, + duckdb: DuckDbIcon + // for related places search: ADD_NEW_LANG } let subIconScale = width === 30 ? 0.6 : 0.8 diff --git a/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts b/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts index 9952199fd2..4662a62f8f 100644 --- a/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts +++ b/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts @@ -161,15 +161,15 @@ export class Autocompletor { modifiedCode: string = '' applyZone: | { - startLineNumber: number - endLineNumber: number - } + startLineNumber: number + endLineNumber: number + } | undefined = undefined lastChangePosition: | { - lineNumber: number - column: number - } + lineNumber: number + column: number + } | undefined = undefined abortController: AbortController | undefined = undefined @@ -180,12 +180,12 @@ export class Autocompletor { predictedChange: | { - position: { - lineNumber: number - column: number - } - distance: number - } + position: { + lineNumber: number + column: number + } + distance: number + } | undefined = undefined tabWidget: meditor.IContentWidget | undefined = undefined @@ -240,18 +240,18 @@ export class Autocompletor { let closestPosition: | { - lineNumber: number - column: number - } + lineNumber: number + column: number + } | undefined = undefined let closestDistance = Infinity for (const change of this.visualChanges) { if (change.type === 'deleted') { const distance = Math.min( Math.abs(change.range.startLine - position.lineNumber) + - Math.abs(change.range.startColumn - position.column) / 10000, + Math.abs(change.range.startColumn - position.column) / 10000, Math.abs(change.range.endLine - position.lineNumber) + - Math.abs(change.range.endColumn - position.column) / 10000 + Math.abs(change.range.endColumn - position.column) / 10000 ) if (distance < closestDistance) { closestDistance = distance diff --git a/frontend/src/lib/components/graph/graphBuilder.ts b/frontend/src/lib/components/graph/graphBuilder.ts index 0011106ade..ab851db42e 100644 --- a/frontend/src/lib/components/graph/graphBuilder.ts +++ b/frontend/src/lib/components/graph/graphBuilder.ts @@ -166,7 +166,7 @@ export function graphBuilder( disableMoveIds: options?.disableMoveIds, enableTrigger: sourceId === 'Input', // If the index is -1, it means that the target module is not in the modules array, so we set it to the length of the array - index: index >= 0 ? index : mods?.length ?? 0, + index: index >= 0 ? index : (mods?.length ?? 0), ...extra, insertable: extra.insertable && !options?.disableInsert && prefix == undefined } @@ -635,7 +635,7 @@ export function graphBuilder( if (failureModule) { let toAdd: Record = {} Object.keys(extra.flowModuleStates ?? {}).forEach((id) => { - if (id.startsWith('failure-')) { + if (id.startsWith('failure')) { const failureState = extra.flowModuleStates?.[id] as GraphModuleState | undefined if (failureState?.parent_module) { toAdd[failureState.parent_module] = id diff --git a/frontend/src/lib/components/icons/DuckDbIcon.svelte b/frontend/src/lib/components/icons/DuckDbIcon.svelte new file mode 100644 index 0000000000..7229a377a6 --- /dev/null +++ b/frontend/src/lib/components/icons/DuckDbIcon.svelte @@ -0,0 +1,19 @@ + + + + + + + diff --git a/frontend/src/lib/components/meltComponents/Menu.svelte b/frontend/src/lib/components/meltComponents/Menu.svelte index b6d5510426..3f860004c4 100644 --- a/frontend/src/lib/components/meltComponents/Menu.svelte +++ b/frontend/src/lib/components/meltComponents/Menu.svelte @@ -18,6 +18,7 @@ export let clickOutsideExcludeIds: string[] = [] export let menuClass: string = '' export let open = false + export let renderContent: boolean = false // Use the passed createMenu function const { @@ -81,7 +82,7 @@ - {#if open} + {#if open || renderContent}
= { bigquery: BIGQUERY_TYPES, diff --git a/frontend/src/lib/infer.ts b/frontend/src/lib/infer.ts index 5dcb6772f3..6582930715 100644 --- a/frontend/src/lib/infer.ts +++ b/frontend/src/lib/infer.ts @@ -9,6 +9,7 @@ import initRegexParsers, { parse_sql, parse_mysql, parse_oracledb, + parse_duckdb, parse_bigquery, parse_snowflake, parse_graphql, @@ -96,7 +97,9 @@ export async function inferArgs( } let inlineDBResource: string | undefined = undefined - if (['postgresql', 'mysql', 'bigquery', 'snowflake', 'mssql', 'oracledb'].includes(language ?? '')) { + if ( + ['postgresql', 'mysql', 'bigquery', 'snowflake', 'mssql', 'oracledb'].includes(language ?? '') + ) { await initWasmRegex() inlineDBResource = parse_db_resource(code) } @@ -147,6 +150,9 @@ export async function inferArgs( ...inferedSchema.args ] } + } else if (language == 'duckdb') { + await initWasmRegex() + inferedSchema = JSON.parse(parse_duckdb(code)) } else if (language == 'snowflake') { inferedSchema = JSON.parse(parse_snowflake(code)) if (inlineDBResource === undefined) { @@ -194,7 +200,7 @@ export async function inferArgs( } else if (language == 'java') { await initWasmJava() inferedSchema = JSON.parse(parse_java(code)) - // for related places search: ADD_NEW_LANG + // for related places search: ADD_NEW_LANG } else { return null } diff --git a/frontend/src/lib/inferArgSig.ts b/frontend/src/lib/inferArgSig.ts index ae4ad83794..68d3fc814e 100644 --- a/frontend/src/lib/inferArgSig.ts +++ b/frontend/src/lib/inferArgSig.ts @@ -5,23 +5,21 @@ export function argSigToJsonSchemaType( | string | { resource: string | null } | { - list: - | (string | { object: { key: string; typ: any }[] }) - | { str: any } - | { object: { key: string; typ: any }[] } - | null - } + list: + | (string | { object: { key: string; typ: any }[] }) + | { str: any } + | { object: { key: string; typ: any }[] } + | null + } | { dynselect: string } | { str: string[] | null } | { object: { key: string; typ: any }[] } | { - oneof: [ - { + oneof: { label: string properties: { key: string; typ: any }[] - } - ] - }, + }[] + }, oldS: SchemaProperty ): void { const newS: SchemaProperty = { type: '' } diff --git a/frontend/src/lib/script_helpers.ts b/frontend/src/lib/script_helpers.ts index ceb6644c42..07c05974dc 100644 --- a/frontend/src/lib/script_helpers.ts +++ b/frontend/src/lib/script_helpers.ts @@ -307,6 +307,19 @@ INSERT INTO demo VALUES (@P1, @P2); UPDATE demo SET col2 = @P3 WHERE col2 = @P2; ` +const DUCKDB_INIT_CODE = `-- $friends_csv (s3object) +-- $name (text) = Ben + +ATTACH '$res:u/demo/amazed_postgresql' AS db (TYPE postgres); +CREATE TABLE IF NOT EXISTS db.public.friends (name text); + +INSERT INTO db.public.friends + SELECT name FROM read_csv($friends_csv); + +SELECT 'Hello ' || $name || ', you have ' || + (SELECT COUNT(*) FROM read_csv($friends_csv)) || ' new friends !'; +` + const GRAPHQL_INIT_CODE = `query($name4: String, $name2: Int, $name3: [String]) { demo(name1: $name1, name2: $name2, name3: $name3) { name1, @@ -1134,6 +1147,9 @@ export const INITIAL_CODE = { mssql: { script: MSSQL_INIT_CODE }, + duckdb: { + script: DUCKDB_INIT_CODE + }, graphql: { script: GRAPHQL_INIT_CODE }, @@ -1258,6 +1274,8 @@ export function initialCode( return INITIAL_CODE.mssql.script } else if (language == 'graphql') { return INITIAL_CODE.graphql.script + } else if (language == 'duckdb') { + return INITIAL_CODE.duckdb.script } else if (language == 'php') { return INITIAL_CODE.php.script } else if (language == 'rust') { diff --git a/frontend/src/lib/scripts.ts b/frontend/src/lib/scripts.ts index bc8a44b434..961ae72488 100644 --- a/frontend/src/lib/scripts.ts +++ b/frontend/src/lib/scripts.ts @@ -38,6 +38,8 @@ export function scriptLangToEditorLang( return 'sql' } else if (lang == 'mssql') { return 'sql' + } else if (lang == 'duckdb') { + return 'sql' } else if (lang == 'python3') { return 'python' } else if (lang == 'bash') { @@ -140,7 +142,8 @@ const scriptLanguagesArray: [SupportedLanguage | 'docker' | 'bunnative', string] ['csharp', 'C#'], ['docker', 'Docker'], ['nu', 'Nu'], - ['java', 'Java'] + ['java', 'Java'], + ['duckdb', 'DuckDB'] // for related places search: ADD_NEW_LANG ] export function processLangs(selected: string | undefined, langs: string[]): string[] { @@ -150,7 +153,7 @@ export function processLangs(selected: string | undefined, langs: string[]): str let ls = langs.filter((lang) => lang !== 'nativets') //those languages are newer and may not be in the saved list - let nl = ['bunnative', 'rust', 'ansible', 'csharp', 'nu', 'java'] + let nl = ['bunnative', 'rust', 'ansible', 'csharp', 'nu', 'java', 'duckdb'] // for related places search: ADD_NEW_LANG nl.forEach((lang) => { if (!ls.includes(lang)) { diff --git a/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte b/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte index 35f23fc9e7..cab4ef6adb 100644 --- a/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte @@ -755,7 +755,7 @@ priority: {job.priority}
{/if} - {#if job.tag && !['deno', 'python3', 'flow', 'other', 'go', 'postgresql', 'mysql', 'bigquery', 'snowflake', 'mssql', 'graphql', 'oracledb', 'nativets', 'bash', 'powershell', 'php', 'rust', 'other', 'ansible', 'csharp', 'nu', 'java', 'dependency'].includes(job.tag)} + {#if job.tag && !['deno', 'python3', 'flow', 'other', 'go', 'postgresql', 'mysql', 'bigquery', 'snowflake', 'mssql', 'graphql', 'oracledb', 'nativets', 'bash', 'powershell', 'php', 'rust', 'other', 'ansible', 'csharp', 'nu', 'java', 'duckdb', 'dependency'].includes(job.tag)}
Tag: {job.tag} diff --git a/frontend/tailwind.config.cjs b/frontend/tailwind.config.cjs index f65a852949..908f2516df 100644 --- a/frontend/tailwind.config.cjs +++ b/frontend/tailwind.config.cjs @@ -1,4 +1,5 @@ const plugin = require('tailwindcss/plugin') +const { tailwindClasses } = require('./src/lib/components/apps/editor/componentsPanel/tailwindUtils') const lightTheme = { surface: '#ffffff', @@ -80,7 +81,8 @@ const config = { 'autocomplete-list-item', 'autocomplete-list-item-create', 'selected', - 'wm-tab-selected' + 'wm-tab-selected', + ...tailwindClasses ], theme: { colors: { diff --git a/lsp/Pipfile b/lsp/Pipfile index 43a4bff2fc..6644913e7a 100644 --- a/lsp/Pipfile +++ b/lsp/Pipfile @@ -4,8 +4,8 @@ verify_ssl = true name = "pypi" [packages] -wmill = ">=1.492.1" -wmill_pg = ">=1.492.1" +wmill = ">=1.493.0" +wmill_pg = ">=1.493.0" sendgrid = "*" mysql-connector-python = "*" pymongo = "*" diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index 2fe9558a19..5c0ecb1043 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.492.1 + version: 1.493.0 title: OpenFlow Spec contact: name: Ruben Fiszel diff --git a/powershell-client/WindmillClient/WindmillClient.psd1 b/powershell-client/WindmillClient/WindmillClient.psd1 index 46f6c80082..6861712c96 100644 --- a/powershell-client/WindmillClient/WindmillClient.psd1 +++ b/powershell-client/WindmillClient/WindmillClient.psd1 @@ -12,7 +12,7 @@ RootModule = 'WindmillClient.psm1' # Version number of this module. - ModuleVersion = '1.492.1' + ModuleVersion = '1.493.0' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/python-client/wmill/pyproject.toml b/python-client/wmill/pyproject.toml index 4ef3ce0c9b..532b391203 100644 --- a/python-client/wmill/pyproject.toml +++ b/python-client/wmill/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill" -version = "1.492.1" +version = "1.493.0" description = "A client library for accessing Windmill server wrapping the Windmill client API" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/python-client/wmill_pg/pyproject.toml b/python-client/wmill_pg/pyproject.toml index 035c60e4ea..6a193ccd74 100644 --- a/python-client/wmill_pg/pyproject.toml +++ b/python-client/wmill_pg/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill-pg" -version = "1.492.1" +version = "1.493.0" description = "An extension client for the wmill client library focused on pg" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/typescript-client/jsr.json b/typescript-client/jsr.json index 369565be3b..e44a9ce65e 100644 --- a/typescript-client/jsr.json +++ b/typescript-client/jsr.json @@ -1,6 +1,6 @@ { "name": "@windmill/windmill", - "version": "1.492.1", + "version": "1.493.0", "exports": "./src/index.ts", "publish": { "exclude": ["!src", "./s3Types.ts", "./client.ts"] diff --git a/typescript-client/package.json b/typescript-client/package.json index 0fe5add40c..4aebdc42ff 100644 --- a/typescript-client/package.json +++ b/typescript-client/package.json @@ -1,7 +1,7 @@ { "name": "windmill-client", "description": "Windmill SDK client for browsers and Node.js", - "version": "1.492.1", + "version": "1.493.0", "author": "Ruben Fiszel", "license": "Apache 2.0", "devDependencies": { diff --git a/version.txt b/version.txt index 76f3392713..3ec53108de 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.492.1 +1.493.0