From 2b4a9f008b89d91a8ac188c62301d30e664f311c Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Fri, 27 Sep 2024 16:40:36 -0400 Subject: [PATCH] sqlx: initial commit w/ todos example --- Cargo.lock | 562 +++++++++++++++++- Cargo.toml | 2 + sqlx-libsql/Cargo.toml | 11 + sqlx-libsql/examples/todos/Cargo.toml | 14 + sqlx-libsql/examples/todos/README.md | 41 ++ .../todos/migrations/20200718111257_todos.sql | 6 + sqlx-libsql/examples/todos/src/main.rs | 101 ++++ sqlx-libsql/src/lib.rs | 545 +++++++++++++++++ 8 files changed, 1269 insertions(+), 13 deletions(-) create mode 100644 sqlx-libsql/Cargo.toml create mode 100644 sqlx-libsql/examples/todos/Cargo.toml create mode 100644 sqlx-libsql/examples/todos/README.md create mode 100644 sqlx-libsql/examples/todos/migrations/20200718111257_todos.sql create mode 100644 sqlx-libsql/examples/todos/src/main.rs create mode 100644 sqlx-libsql/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index b93a4127d5..bf5adba107 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -917,6 +917,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -1156,13 +1159,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.0" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -1803,6 +1806,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.11" @@ -1843,6 +1857,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -1894,6 +1909,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "dyn-clone" version = "1.0.17" @@ -1906,10 +1927,10 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ - "der", + "der 0.6.1", "elliptic-curve", "rfc6979", - "signature", + "signature 1.6.4", ] [[package]] @@ -1917,6 +1938,9 @@ name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +dependencies = [ + "serde", +] [[package]] name = "elliptic-curve" @@ -1926,12 +1950,12 @@ checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ "base16ct", "crypto-bigint 0.4.9", - "der", + "der 0.6.1", "digest", "ff", "generic-array", "group", - "pkcs8", + "pkcs8 0.9.0", "rand_core", "sec1", "subtle", @@ -1994,6 +2018,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -2116,12 +2151,38 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -2242,6 +2303,17 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -2441,6 +2513,15 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "hdrhistogram" version = "7.5.4" @@ -2522,6 +2603,15 @@ dependencies = [ "vsimd", ] +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -2996,6 +3086,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "lazycell" @@ -3140,7 +3233,7 @@ dependencies = [ "doc-comment", "fallible-iterator 0.2.0", "fallible-streaming-iterator", - "hashlink", + "hashlink 0.8.4", "lazy_static", "libsql-ffi", "regex", @@ -3427,6 +3520,17 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -3692,6 +3796,23 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "newline-converter" version = "0.3.0" @@ -3774,6 +3895,23 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -3799,6 +3937,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -3867,12 +4016,50 @@ version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.70", +] + [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-sys" +version = "0.9.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "ordered-float" version = "3.9.2" @@ -3980,6 +4167,15 @@ dependencies = [ "serde", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -4067,14 +4263,35 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der 0.7.9", + "pkcs8 0.10.2", + "spki 0.7.3", +] + [[package]] name = "pkcs8" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "der", - "spki", + "der 0.6.1", + "spki 0.6.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.9", + "spki 0.7.3", ] [[package]] @@ -4666,6 +4883,26 @@ dependencies = [ "byteorder", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8 0.10.2", + "rand_core", + "signature 2.2.0", + "spki 0.7.3", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -5049,9 +5286,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ "base16ct", - "der", + "der 0.6.1", "generic-array", - "pkcs8", + "pkcs8 0.9.0", "subtle", "zeroize", ] @@ -5300,6 +5537,16 @@ dependencies = [ "rand_core", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "simdutf8" version = "0.1.4" @@ -5356,6 +5603,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -5372,6 +5622,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spki" @@ -5380,7 +5633,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", - "der", + "der 0.6.1", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der 0.7.9", ] [[package]] @@ -5397,6 +5660,234 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "sqlformat" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" +dependencies = [ + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" +dependencies = [ + "atoi", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener 5.3.1", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.14.5", + "hashlink 0.9.1", + "hex", + "indexmap 2.2.6", + "log", + "memchr", + "native-tls", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-example-sqlite-todos" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap 4.5.9", + "futures", + "sqlx", + "sqlx-libsql", + "tokio", +] + +[[package]] +name = "sqlx-libsql" +version = "0.1.0" +dependencies = [ + "futures-core", + "futures-util", + "libsql", + "log", + "sqlx-core", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.70", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" +dependencies = [ + "dotenvy", + "either", + "heck 0.5.0", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.70", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.6.0", + "byteorder", + "bytes", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.6.0", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "tracing", + "url", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -5415,6 +5906,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "strsim" version = "0.10.0" @@ -6165,6 +6667,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" + [[package]] name = "unicode-segmentation" version = "1.11.0" @@ -6183,6 +6691,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "untrusted" version = "0.9.0" @@ -6235,6 +6749,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "vergen" version = "8.3.2" @@ -6337,6 +6857,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.92" @@ -6768,6 +7294,16 @@ dependencies = [ "rustix 0.38.34", ] +[[package]] +name = "whoami" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall 0.5.2", + "wasite", +] + [[package]] name = "wiggle" version = "9.0.4" diff --git a/Cargo.toml b/Cargo.toml index 1646ff22ba..b24fc0b144 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ members = [ "libsql-wal", "libsql-storage", "libsql-storage-server", + "sqlx-libsql", + "sqlx-libsql/examples/todos" ] exclude = [ diff --git a/sqlx-libsql/Cargo.toml b/sqlx-libsql/Cargo.toml new file mode 100644 index 0000000000..891137afb5 --- /dev/null +++ b/sqlx-libsql/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "sqlx-libsql" +version = "0.1.0" +edition = "2021" + +[dependencies] +libsql = { version = "0.6", path = "../libsql" } +sqlx-core = "=0.8.2" +futures-core = "0.3" +futures-util = "0.3" +log = "0.4" diff --git a/sqlx-libsql/examples/todos/Cargo.toml b/sqlx-libsql/examples/todos/Cargo.toml new file mode 100644 index 0000000000..1d84b568a3 --- /dev/null +++ b/sqlx-libsql/examples/todos/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "sqlx-example-sqlite-todos" +version = "0.1.0" +edition = "2021" +publish = false +workspace = "../../../" + +[dependencies] +anyhow = "1.0" +futures = "0.3" +sqlx = { version = "0.8", features = [ "runtime-tokio", "tls-native-tls" ] } +sqlx-libsql = { path = "../.." } +clap = { version = "4", features = ["derive"] } +tokio = { version = "1.20.0", features = ["rt", "macros"]} diff --git a/sqlx-libsql/examples/todos/README.md b/sqlx-libsql/examples/todos/README.md new file mode 100644 index 0000000000..8bbb4d15be --- /dev/null +++ b/sqlx-libsql/examples/todos/README.md @@ -0,0 +1,41 @@ +# TODOs Example + +## Setup + +1. Declare the database URL + + ``` + export DATABASE_URL="sqlite:todos.db" + ``` + +2. Create the database. + + ``` + $ sqlx db create + ``` + +3. Run sql migrations + + ``` + $ sqlx migrate run + ``` + +## Usage + +Add a todo + +``` +cargo run -- add "todo description" +``` + +Complete a todo. + +``` +cargo run -- done +``` + +List all todos + +``` +cargo run +``` diff --git a/sqlx-libsql/examples/todos/migrations/20200718111257_todos.sql b/sqlx-libsql/examples/todos/migrations/20200718111257_todos.sql new file mode 100644 index 0000000000..5248bb9a44 --- /dev/null +++ b/sqlx-libsql/examples/todos/migrations/20200718111257_todos.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS todos +( + id INTEGER PRIMARY KEY NOT NULL, + description TEXT NOT NULL, + done BOOLEAN NOT NULL DEFAULT 0 +); diff --git a/sqlx-libsql/examples/todos/src/main.rs b/sqlx-libsql/examples/todos/src/main.rs new file mode 100644 index 0000000000..3d46056a12 --- /dev/null +++ b/sqlx-libsql/examples/todos/src/main.rs @@ -0,0 +1,101 @@ +use clap::{Parser, Subcommand}; +use sqlx_libsql::LibsqlPool; +use std::env; + +#[derive(Parser)] +struct Args { + #[command(subcommand)] + cmd: Option, +} + +#[derive(Subcommand)] +enum Command { + Add { description: String }, + Done { id: i64 }, +} + +#[tokio::main(flavor = "current_thread")] +async fn main() -> anyhow::Result<()> { + let args = Args::parse(); + let pool = LibsqlPool::connect(&env::var("DATABASE_URL")?).await?; + + match args.cmd { + Some(Command::Add { description }) => { + println!("Adding new todo with description '{description}'"); + let todo_id = add_todo(&pool, description).await?; + println!("Added new todo with id {todo_id}"); + } + Some(Command::Done { id }) => { + println!("Marking todo {id} as done"); + if complete_todo(&pool, id).await? { + println!("Todo {id} is marked as done"); + } else { + println!("Invalid id {id}"); + } + } + None => { + println!("Printing list of all todos"); + list_todos(&pool).await?; + } + } + + Ok(()) +} + +async fn add_todo(pool: &LibsqlPool, description: String) -> anyhow::Result { + let mut conn = pool.acquire().await?; + + // Insert the task, then obtain the ID of this row + let id = sqlx::query( + r#" +INSERT INTO todos ( description ) +VALUES ( ?1 ) + "#, + ) + .bind(description) + .execute(&mut *conn) + .await? + .last_insert_rowid(); + + Ok(id) +} + +async fn complete_todo(pool: &LibsqlPool, id: i64) -> anyhow::Result { + let rows_affected = sqlx::query( + r#" +UPDATE todos +SET done = TRUE +WHERE id = ?1 + "#, + ) + .bind(id) + .execute(pool) + .await? + .rows_affected(); + + Ok(rows_affected > 0) +} + +async fn list_todos(pool: &LibsqlPool) -> anyhow::Result<()> { + let recs = sqlx::query( + r#" +SELECT id, description, done +FROM todos +ORDER BY id + "#, + ) + .fetch_all(pool) + .await?; + + for _rec in recs { + // TODO(lucio): impl this + // println!( + // "- [{}] {}: {}", + // if rec.done { "x" } else { " " }, + // rec.id, + // &rec.description, + // ); + } + + Ok(()) +} diff --git a/sqlx-libsql/src/lib.rs b/sqlx-libsql/src/lib.rs new file mode 100644 index 0000000000..aafc0b4a58 --- /dev/null +++ b/sqlx-libsql/src/lib.rs @@ -0,0 +1,545 @@ +#![allow(unused)] + +use std::{ + iter::{Extend, IntoIterator}, + marker::PhantomData, + str::FromStr, +}; + +use futures_core::future::BoxFuture; +use sqlx_core::{ + arguments::Arguments, + column::Column, + connection::{ConnectOptions, Connection}, + database::Database, + encode::Encode, + executor::Executor, + row::Row, + statement::Statement, + transaction::TransactionManager, + type_info::TypeInfo, + types::Type, + value::{Value, ValueRef}, +}; + +#[derive(Debug)] +pub struct Libsql {} + +impl Database for Libsql { + type Connection = LibsqlConnection; + type TransactionManager = LibsqlTransactionManager; + type Row = LibsqlRow; + type QueryResult = LibsqlQueryResult; + type Column = LibsqlColumn; + type TypeInfo = LibsqlTypeInfo; + type Value = LibsqlValue; + type ValueRef<'r> = LibsqlValueRef<'r>; + type Arguments<'q> = LibsqlArguments<'q>; + type ArgumentBuffer<'q> = (); + type Statement<'q> = LibsqlStatement<'q>; + + const NAME: &'static str = "Libsql"; + const URL_SCHEMES: &'static [&'static str] = &["libsql"]; +} + +// #[derive(Debug)] +// pub struct LibsqlExecutor<'a> { +// _a: PhantomData<&'a ()>, +// } + +// impl<'a> Executor<'a> for LibsqlExecutor<'a> { +// type Database = Libsql; + +// fn fetch_many<'e, 'q: 'e, E>( +// self, +// query: E, +// ) -> futures_core::stream::BoxStream< +// 'e, +// Result< +// sqlx_core::Either< +// ::QueryResult, +// ::Row, +// >, +// sqlx_core::Error, +// >, +// > +// where +// 'a: 'e, +// E: 'q + sqlx_core::executor::Execute<'q, Self::Database>, +// { +// todo!() +// } + +// fn fetch_optional<'e, 'q: 'e, E>( +// self, +// query: E, +// ) -> BoxFuture<'e, Result::Row>, sqlx_core::Error>> +// where +// 'a: 'e, +// E: 'q + sqlx_core::executor::Execute<'q, Self::Database>, +// { +// todo!() +// } + +// fn prepare_with<'e, 'q: 'e>( +// self, +// sql: &'q str, +// parameters: &'e [::TypeInfo], +// ) -> BoxFuture<'e, Result<::Statement<'q>, sqlx_core::Error>> +// where +// 'a: 'e, +// { +// todo!() +// } + +// fn describe<'e, 'q: 'e>( +// self, +// sql: &'q str, +// ) -> BoxFuture<'e, Result, sqlx_core::Error>> +// where +// 'a: 'e, +// { +// todo!() +// } +// } + +impl<'a> Executor<'a> for &'a mut LibsqlConnection { + type Database = Libsql; + + fn fetch_many<'e, 'q: 'e, E>( + self, + query: E, + ) -> futures_core::stream::BoxStream< + 'e, + Result< + sqlx_core::Either< + ::QueryResult, + ::Row, + >, + sqlx_core::Error, + >, + > + where + 'a: 'e, + E: 'q + sqlx_core::executor::Execute<'q, Self::Database>, + { + todo!() + } + + fn fetch_optional<'e, 'q: 'e, E>( + self, + query: E, + ) -> BoxFuture<'e, Result::Row>, sqlx_core::Error>> + where + 'a: 'e, + E: 'q + sqlx_core::executor::Execute<'q, Self::Database>, + { + todo!() + } + + fn prepare_with<'e, 'q: 'e>( + self, + sql: &'q str, + parameters: &'e [::TypeInfo], + ) -> BoxFuture<'e, Result<::Statement<'q>, sqlx_core::Error>> + where + 'a: 'e, + { + todo!() + } + + fn describe<'e, 'q: 'e>( + self, + sql: &'q str, + ) -> BoxFuture<'e, Result, sqlx_core::Error>> + where + 'a: 'e, + { + todo!() + } +} + +pub type LibsqlPool = sqlx_core::pool::Pool; + +sqlx_core::impl_into_arguments_for_arguments!(LibsqlArguments<'q>); +sqlx_core::impl_column_index_for_row!(LibsqlRow); +sqlx_core::impl_column_index_for_statement!(LibsqlStatement); +sqlx_core::impl_acquire!(Libsql, LibsqlConnection); + +// required because some databases have a different handling of NULL +// borrowed from sqlx_sqlite +sqlx_core::impl_encode_for_option!(Libsql); + +#[derive(Debug)] +pub struct LibsqlConnection {} + +impl Connection for LibsqlConnection { + type Database = Libsql; + + type Options = LibsqlConnectionOptions; + + fn close(self) -> BoxFuture<'static, Result<(), sqlx_core::Error>> { + todo!() + } + + fn close_hard(self) -> BoxFuture<'static, Result<(), sqlx_core::Error>> { + todo!() + } + + fn ping(&mut self) -> BoxFuture<'_, Result<(), sqlx_core::Error>> { + todo!() + } + + fn begin( + &mut self, + ) -> BoxFuture< + '_, + Result, sqlx_core::Error>, + > + where + Self: Sized, + { + todo!() + } + + fn shrink_buffers(&mut self) { + todo!() + } + + fn flush(&mut self) -> BoxFuture<'_, Result<(), sqlx_core::Error>> { + todo!() + } + + fn should_flush(&self) -> bool { + todo!() + } +} + +#[derive(Debug, Clone)] +pub struct LibsqlConnectionOptions {} + +impl ConnectOptions for LibsqlConnectionOptions { + type Connection = LibsqlConnection; + + fn from_url(url: &sqlx_core::Url) -> Result { + todo!() + } + + fn connect(&self) -> BoxFuture<'_, Result> + where + Self::Connection: Sized, + { + todo!() + } + + fn log_statements(self, level: log::LevelFilter) -> Self { + todo!() + } + + fn log_slow_statements(self, level: log::LevelFilter, duration: std::time::Duration) -> Self { + todo!() + } +} + +impl FromStr for LibsqlConnectionOptions { + type Err = sqlx_core::Error; + + fn from_str(s: &str) -> Result { + todo!() + } +} + +pub struct LibsqlTransactionManager {} + +impl TransactionManager for LibsqlTransactionManager { + type Database = Libsql; + + fn begin( + conn: &mut ::Connection, + ) -> BoxFuture<'_, Result<(), sqlx_core::Error>> { + todo!() + } + + fn commit( + conn: &mut ::Connection, + ) -> BoxFuture<'_, Result<(), sqlx_core::Error>> { + todo!() + } + + fn rollback( + conn: &mut ::Connection, + ) -> BoxFuture<'_, Result<(), sqlx_core::Error>> { + todo!() + } + + fn start_rollback(conn: &mut ::Connection) { + todo!() + } +} + +pub struct LibsqlRow {} + +impl Row for LibsqlRow { + type Database = Libsql; + + fn columns(&self) -> &[::Column] { + todo!() + } + + fn try_get_raw( + &self, + index: I, + ) -> Result<::ValueRef<'_>, sqlx_core::Error> + where + I: sqlx_core::column::ColumnIndex, + { + todo!() + } +} + +#[derive(Debug, Default)] +pub struct LibsqlQueryResult { + changes: u64, + last_insert_rowid: i64, +} + +impl LibsqlQueryResult { + pub fn rows_affected(&self) -> u64 { + self.changes + } + + pub fn last_insert_rowid(&self) -> i64 { + self.last_insert_rowid + } +} + +impl Extend for LibsqlQueryResult { + fn extend>(&mut self, iter: T) { + for elem in iter { + self.changes += elem.changes; + self.last_insert_rowid = elem.last_insert_rowid; + } + } +} + +#[derive(Debug)] +pub struct LibsqlColumn {} + +impl Column for LibsqlColumn { + type Database = Libsql; + + fn ordinal(&self) -> usize { + todo!() + } + + fn name(&self) -> &str { + todo!() + } + + fn type_info(&self) -> &::TypeInfo { + todo!() + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct LibsqlTypeInfo {} + +impl TypeInfo for LibsqlTypeInfo { + fn is_null(&self) -> bool { + todo!() + } + + fn name(&self) -> &str { + todo!() + } +} + +impl std::fmt::Display for LibsqlTypeInfo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("LibsqlTypeInfo").finish() + } +} + +pub struct LibsqlValue {} + +impl Value for LibsqlValue { + type Database = Libsql; + + fn as_ref(&self) -> ::ValueRef<'_> { + todo!() + } + + fn type_info(&self) -> std::borrow::Cow<'_, ::TypeInfo> { + todo!() + } + + fn is_null(&self) -> bool { + todo!() + } +} + +pub struct LibsqlValueRef<'a> { + _f: &'a (), +} + +impl<'a> ValueRef<'a> for LibsqlValueRef<'a> { + type Database = Libsql; + + fn to_owned(&self) -> ::Value { + todo!() + } + + fn type_info(&self) -> std::borrow::Cow<'_, ::TypeInfo> { + todo!() + } + + fn is_null(&self) -> bool { + todo!() + } +} + +#[derive(Default)] +pub struct LibsqlArguments<'a> { + _a: PhantomData<&'a ()>, +} + +impl<'a> Arguments<'a> for LibsqlArguments<'a> { + type Database = Libsql; + + fn reserve(&mut self, additional: usize, size: usize) { + todo!() + } + + fn add(&mut self, value: T) -> Result<(), sqlx_core::error::BoxDynError> + where + T: 'a + + sqlx_core::encode::Encode<'a, Self::Database> + + sqlx_core::types::Type, + { + todo!() + } + + fn len(&self) -> usize { + todo!() + } +} + +impl<'a> Encode<'a, Libsql> for String { + fn encode_by_ref( + &self, + buf: &mut (), + ) -> Result { + todo!() + } +} + +impl Type for String { + fn type_info() -> ::TypeInfo { + todo!() + } +} + +impl<'a> Encode<'a, Libsql> for i64 { + fn encode_by_ref( + &self, + buf: &mut (), + ) -> Result { + todo!() + } +} + +impl Type for i64 { + fn type_info() -> ::TypeInfo { + todo!() + } +} + +pub struct LibsqlStatement<'a> { + _a: PhantomData<&'a ()>, +} + +impl<'a> Statement<'a> for LibsqlStatement<'a> { + type Database = Libsql; + + fn to_owned(&self) -> ::Statement<'static> { + todo!() + } + + fn sql(&self) -> &str { + todo!() + } + + fn parameters( + &self, + ) -> Option::TypeInfo], usize>> { + todo!() + } + + fn columns(&self) -> &[::Column] { + todo!() + } + + fn query( + &self, + ) -> sqlx_core::query::Query<'_, Self::Database, ::Arguments<'_>> + { + todo!() + } + + fn query_with<'s, A>(&'s self, arguments: A) -> sqlx_core::query::Query<'s, Self::Database, A> + where + A: sqlx_core::arguments::IntoArguments<'s, Self::Database>, + { + todo!() + } + + fn query_as( + &self, + ) -> sqlx_core::query_as::QueryAs< + '_, + Self::Database, + O, + ::Arguments<'_>, + > + where + O: for<'r> sqlx_core::from_row::FromRow<'r, ::Row>, + { + todo!() + } + + fn query_as_with<'s, O, A>( + &'s self, + arguments: A, + ) -> sqlx_core::query_as::QueryAs<'s, Self::Database, O, A> + where + O: for<'r> sqlx_core::from_row::FromRow<'r, ::Row>, + A: sqlx_core::arguments::IntoArguments<'s, Self::Database>, + { + todo!() + } + + fn query_scalar( + &self, + ) -> sqlx_core::query_scalar::QueryScalar< + '_, + Self::Database, + O, + ::Arguments<'_>, + > + where + (O,): for<'r> sqlx_core::from_row::FromRow<'r, ::Row>, + { + todo!() + } + + fn query_scalar_with<'s, O, A>( + &'s self, + arguments: A, + ) -> sqlx_core::query_scalar::QueryScalar<'s, Self::Database, O, A> + where + (O,): for<'r> sqlx_core::from_row::FromRow<'r, ::Row>, + A: sqlx_core::arguments::IntoArguments<'s, Self::Database>, + { + todo!() + } +}