quickhouse 0.3.1__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {quickhouse-0.3.1 → quickhouse-0.3.3}/Cargo.lock +248 -9
  2. {quickhouse-0.3.1 → quickhouse-0.3.3}/Cargo.toml +16 -1
  3. {quickhouse-0.3.1 → quickhouse-0.3.3}/PKG-INFO +44 -4
  4. {quickhouse-0.3.1 → quickhouse-0.3.3}/README.md +41 -3
  5. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/Cargo.toml +2 -0
  6. quickhouse-0.3.3/crates/quickhouse-core/src/archive.rs +178 -0
  7. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/config.rs +38 -0
  8. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/ddl.rs +18 -2
  9. quickhouse-0.3.3/crates/quickhouse-core/src/decimal.rs +225 -0
  10. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/decode.rs +229 -19
  11. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/decode_bigquery.rs +152 -21
  12. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/decode_mysql.rs +129 -29
  13. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/lib.rs +4 -2
  14. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/sink/bigquery.rs +71 -12
  15. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/sink/clickhouse.rs +36 -5
  16. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/source/bigquery.rs +2 -1
  17. quickhouse-0.3.3/crates/quickhouse-core/src/source/mod.rs +78 -0
  18. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/source/mysql.rs +23 -20
  19. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/source/postgres.rs +20 -23
  20. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/sync.rs +521 -230
  21. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/transform.rs +122 -6
  22. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/types.rs +35 -10
  23. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-py/src/lib.rs +105 -9
  24. {quickhouse-0.3.1 → quickhouse-0.3.3}/pyproject.toml +5 -2
  25. {quickhouse-0.3.1 → quickhouse-0.3.3}/python/quickhouse/__init__.py +2 -0
  26. {quickhouse-0.3.1 → quickhouse-0.3.3}/python/quickhouse/_quickhouse.pyi +55 -0
  27. quickhouse-0.3.1/crates/quickhouse-core/src/source/mod.rs +0 -15
  28. {quickhouse-0.3.1 → quickhouse-0.3.3}/LICENSE +0 -0
  29. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/error.rs +0 -0
  30. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/memory.rs +0 -0
  31. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/sink/bigquery_proto.rs +0 -0
  32. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-core/src/sink/mod.rs +0 -0
  33. {quickhouse-0.3.1 → quickhouse-0.3.3}/crates/quickhouse-py/Cargo.toml +0 -0
  34. {quickhouse-0.3.1 → quickhouse-0.3.3}/python/quickhouse/progress.py +0 -0
  35. {quickhouse-0.3.1 → quickhouse-0.3.3}/python/quickhouse/py.typed +0 -0
@@ -606,6 +606,7 @@ dependencies = [
606
606
  "android-tzdata",
607
607
  "iana-time-zone",
608
608
  "num-traits",
609
+ "serde",
609
610
  "windows-targets",
610
611
  ]
611
612
 
@@ -686,6 +687,16 @@ dependencies = [
686
687
  "tiny-keccak",
687
688
  ]
688
689
 
690
+ [[package]]
691
+ name = "core-foundation"
692
+ version = "0.10.1"
693
+ source = "registry+https://github.com/rust-lang/crates.io-index"
694
+ checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
695
+ dependencies = [
696
+ "core-foundation-sys",
697
+ "libc",
698
+ ]
699
+
689
700
  [[package]]
690
701
  name = "core-foundation-sys"
691
702
  version = "0.8.7"
@@ -1457,6 +1468,12 @@ version = "1.10.1"
1457
1468
  source = "registry+https://github.com/rust-lang/crates.io-index"
1458
1469
  checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
1459
1470
 
1471
+ [[package]]
1472
+ name = "humantime"
1473
+ version = "2.4.0"
1474
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1475
+ checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15"
1476
+
1460
1477
  [[package]]
1461
1478
  name = "hybrid-array"
1462
1479
  version = "0.4.13"
@@ -1497,6 +1514,7 @@ dependencies = [
1497
1514
  "hyper",
1498
1515
  "hyper-util",
1499
1516
  "rustls",
1517
+ "rustls-native-certs",
1500
1518
  "tokio",
1501
1519
  "tokio-rustls",
1502
1520
  "tower-service",
@@ -1701,6 +1719,12 @@ dependencies = [
1701
1719
  "rustversion",
1702
1720
  ]
1703
1721
 
1722
+ [[package]]
1723
+ name = "integer-encoding"
1724
+ version = "3.0.4"
1725
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1726
+ checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02"
1727
+
1704
1728
  [[package]]
1705
1729
  name = "ipnet"
1706
1730
  version = "2.12.0"
@@ -1915,6 +1939,16 @@ dependencies = [
1915
1939
  "regex-automata",
1916
1940
  ]
1917
1941
 
1942
+ [[package]]
1943
+ name = "md-5"
1944
+ version = "0.10.6"
1945
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1946
+ checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
1947
+ dependencies = [
1948
+ "cfg-if",
1949
+ "digest 0.10.7",
1950
+ ]
1951
+
1918
1952
  [[package]]
1919
1953
  name = "md-5"
1920
1954
  version = "0.11.0"
@@ -2190,12 +2224,57 @@ dependencies = [
2190
2224
  "objc2-core-foundation",
2191
2225
  ]
2192
2226
 
2227
+ [[package]]
2228
+ name = "object_store"
2229
+ version = "0.11.2"
2230
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2231
+ checksum = "3cfccb68961a56facde1163f9319e0d15743352344e7808a11795fb99698dcaf"
2232
+ dependencies = [
2233
+ "async-trait",
2234
+ "base64 0.22.1",
2235
+ "bytes",
2236
+ "chrono",
2237
+ "futures",
2238
+ "humantime",
2239
+ "hyper",
2240
+ "itertools 0.13.0",
2241
+ "md-5 0.10.6",
2242
+ "parking_lot",
2243
+ "percent-encoding",
2244
+ "quick-xml",
2245
+ "rand 0.8.7",
2246
+ "reqwest",
2247
+ "ring",
2248
+ "serde",
2249
+ "serde_json",
2250
+ "snafu",
2251
+ "tokio",
2252
+ "tracing",
2253
+ "url",
2254
+ "walkdir",
2255
+ ]
2256
+
2193
2257
  [[package]]
2194
2258
  name = "once_cell"
2195
2259
  version = "1.21.4"
2196
2260
  source = "registry+https://github.com/rust-lang/crates.io-index"
2197
2261
  checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
2198
2262
 
2263
+ [[package]]
2264
+ name = "openssl-probe"
2265
+ version = "0.2.1"
2266
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2267
+ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
2268
+
2269
+ [[package]]
2270
+ name = "ordered-float"
2271
+ version = "2.10.1"
2272
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2273
+ checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
2274
+ dependencies = [
2275
+ "num-traits",
2276
+ ]
2277
+
2199
2278
  [[package]]
2200
2279
  name = "parking_lot"
2201
2280
  version = "0.12.5"
@@ -2219,6 +2298,45 @@ dependencies = [
2219
2298
  "windows-link",
2220
2299
  ]
2221
2300
 
2301
+ [[package]]
2302
+ name = "parquet"
2303
+ version = "53.4.1"
2304
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2305
+ checksum = "2f8cf58b29782a7add991f655ff42929e31a7859f5319e53db9e39a714cb113c"
2306
+ dependencies = [
2307
+ "ahash 0.8.12",
2308
+ "arrow-array",
2309
+ "arrow-buffer",
2310
+ "arrow-cast",
2311
+ "arrow-data",
2312
+ "arrow-ipc",
2313
+ "arrow-schema",
2314
+ "arrow-select",
2315
+ "base64 0.22.1",
2316
+ "bytes",
2317
+ "chrono",
2318
+ "futures",
2319
+ "half",
2320
+ "hashbrown 0.15.5",
2321
+ "num",
2322
+ "num-bigint",
2323
+ "object_store",
2324
+ "paste",
2325
+ "seq-macro",
2326
+ "snap",
2327
+ "thrift",
2328
+ "tokio",
2329
+ "twox-hash",
2330
+ "zstd",
2331
+ "zstd-sys",
2332
+ ]
2333
+
2334
+ [[package]]
2335
+ name = "paste"
2336
+ version = "1.0.15"
2337
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2338
+ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
2339
+
2222
2340
  [[package]]
2223
2341
  name = "pem"
2224
2342
  version = "3.0.6"
@@ -2303,7 +2421,7 @@ dependencies = [
2303
2421
  "bytes",
2304
2422
  "fallible-iterator",
2305
2423
  "hmac",
2306
- "md-5",
2424
+ "md-5 0.11.0",
2307
2425
  "memchr",
2308
2426
  "rand 0.10.2",
2309
2427
  "sha2 0.11.0",
@@ -2504,9 +2622,19 @@ dependencies = [
2504
2622
  "syn 2.0.119",
2505
2623
  ]
2506
2624
 
2625
+ [[package]]
2626
+ name = "quick-xml"
2627
+ version = "0.37.5"
2628
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2629
+ checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
2630
+ dependencies = [
2631
+ "memchr",
2632
+ "serde",
2633
+ ]
2634
+
2507
2635
  [[package]]
2508
2636
  name = "quickhouse-core"
2509
- version = "0.3.1"
2637
+ version = "0.3.3"
2510
2638
  dependencies = [
2511
2639
  "anyhow",
2512
2640
  "arrow",
@@ -2521,6 +2649,8 @@ dependencies = [
2521
2649
  "google-cloud-gax",
2522
2650
  "google-cloud-googleapis",
2523
2651
  "mysql_async",
2652
+ "object_store",
2653
+ "parquet",
2524
2654
  "prost",
2525
2655
  "prost-types",
2526
2656
  "reqwest",
@@ -2540,7 +2670,7 @@ dependencies = [
2540
2670
 
2541
2671
  [[package]]
2542
2672
  name = "quickhouse-py"
2543
- version = "0.3.1"
2673
+ version = "0.3.3"
2544
2674
  dependencies = [
2545
2675
  "pyo3",
2546
2676
  "quickhouse-core",
@@ -2744,6 +2874,7 @@ dependencies = [
2744
2874
  "encoding_rs",
2745
2875
  "futures-core",
2746
2876
  "futures-util",
2877
+ "h2",
2747
2878
  "http",
2748
2879
  "http-body",
2749
2880
  "http-body-util",
@@ -2758,6 +2889,7 @@ dependencies = [
2758
2889
  "pin-project-lite",
2759
2890
  "quinn",
2760
2891
  "rustls",
2892
+ "rustls-native-certs",
2761
2893
  "rustls-pki-types",
2762
2894
  "serde",
2763
2895
  "serde_json",
@@ -2883,6 +3015,18 @@ dependencies = [
2883
3015
  "zeroize",
2884
3016
  ]
2885
3017
 
3018
+ [[package]]
3019
+ name = "rustls-native-certs"
3020
+ version = "0.8.4"
3021
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3022
+ checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
3023
+ dependencies = [
3024
+ "openssl-probe",
3025
+ "rustls-pki-types",
3026
+ "schannel",
3027
+ "security-framework",
3028
+ ]
3029
+
2886
3030
  [[package]]
2887
3031
  name = "rustls-pemfile"
2888
3032
  version = "2.2.0"
@@ -2894,9 +3038,9 @@ dependencies = [
2894
3038
 
2895
3039
  [[package]]
2896
3040
  name = "rustls-pki-types"
2897
- version = "1.15.0"
3041
+ version = "1.15.1"
2898
3042
  source = "registry+https://github.com/rust-lang/crates.io-index"
2899
- checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046"
3043
+ checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96"
2900
3044
  dependencies = [
2901
3045
  "web-time",
2902
3046
  "zeroize",
@@ -2926,12 +3070,30 @@ version = "1.0.23"
2926
3070
  source = "registry+https://github.com/rust-lang/crates.io-index"
2927
3071
  checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
2928
3072
 
3073
+ [[package]]
3074
+ name = "same-file"
3075
+ version = "1.0.6"
3076
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3077
+ checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
3078
+ dependencies = [
3079
+ "winapi-util",
3080
+ ]
3081
+
2929
3082
  [[package]]
2930
3083
  name = "saturating"
2931
3084
  version = "0.1.0"
2932
3085
  source = "registry+https://github.com/rust-lang/crates.io-index"
2933
3086
  checksum = "ece8e78b2f38ec51c51f5d475df0a7187ba5111b2a28bdc761ee05b075d40a71"
2934
3087
 
3088
+ [[package]]
3089
+ name = "schannel"
3090
+ version = "0.1.29"
3091
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3092
+ checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
3093
+ dependencies = [
3094
+ "windows-sys 0.61.2",
3095
+ ]
3096
+
2935
3097
  [[package]]
2936
3098
  name = "scopeguard"
2937
3099
  version = "1.2.0"
@@ -2944,12 +3106,41 @@ version = "4.1.0"
2944
3106
  source = "registry+https://github.com/rust-lang/crates.io-index"
2945
3107
  checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
2946
3108
 
3109
+ [[package]]
3110
+ name = "security-framework"
3111
+ version = "3.7.0"
3112
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3113
+ checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
3114
+ dependencies = [
3115
+ "bitflags 2.13.1",
3116
+ "core-foundation",
3117
+ "core-foundation-sys",
3118
+ "libc",
3119
+ "security-framework-sys",
3120
+ ]
3121
+
3122
+ [[package]]
3123
+ name = "security-framework-sys"
3124
+ version = "2.17.0"
3125
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3126
+ checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
3127
+ dependencies = [
3128
+ "core-foundation-sys",
3129
+ "libc",
3130
+ ]
3131
+
2947
3132
  [[package]]
2948
3133
  name = "semver"
2949
3134
  version = "1.0.28"
2950
3135
  source = "registry+https://github.com/rust-lang/crates.io-index"
2951
3136
  checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
2952
3137
 
3138
+ [[package]]
3139
+ name = "seq-macro"
3140
+ version = "0.3.6"
3141
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3142
+ checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
3143
+
2953
3144
  [[package]]
2954
3145
  name = "serde"
2955
3146
  version = "1.0.229"
@@ -3101,6 +3292,33 @@ version = "1.15.2"
3101
3292
  source = "registry+https://github.com/rust-lang/crates.io-index"
3102
3293
  checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
3103
3294
 
3295
+ [[package]]
3296
+ name = "snafu"
3297
+ version = "0.8.9"
3298
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3299
+ checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2"
3300
+ dependencies = [
3301
+ "snafu-derive",
3302
+ ]
3303
+
3304
+ [[package]]
3305
+ name = "snafu-derive"
3306
+ version = "0.8.9"
3307
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3308
+ checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451"
3309
+ dependencies = [
3310
+ "heck",
3311
+ "proc-macro2",
3312
+ "quote",
3313
+ "syn 2.0.119",
3314
+ ]
3315
+
3316
+ [[package]]
3317
+ name = "snap"
3318
+ version = "1.1.2"
3319
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3320
+ checksum = "199905e6153d6405f9728fe44daace35f8f837bbf830bb6e85fbd5828709a886"
3321
+
3104
3322
  [[package]]
3105
3323
  name = "socket2"
3106
3324
  version = "0.5.10"
@@ -3299,6 +3517,17 @@ dependencies = [
3299
3517
  "cfg-if",
3300
3518
  ]
3301
3519
 
3520
+ [[package]]
3521
+ name = "thrift"
3522
+ version = "0.17.0"
3523
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3524
+ checksum = "7e54bc85fc7faa8bc175c4bab5b92ba8d9a3ce893d0e9f42cc455c8ab16a9e09"
3525
+ dependencies = [
3526
+ "byteorder",
3527
+ "integer-encoding",
3528
+ "ordered-float",
3529
+ ]
3530
+
3302
3531
  [[package]]
3303
3532
  name = "time"
3304
3533
  version = "0.3.54"
@@ -3803,6 +4032,16 @@ version = "0.9.5"
3803
4032
  source = "registry+https://github.com/rust-lang/crates.io-index"
3804
4033
  checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
3805
4034
 
4035
+ [[package]]
4036
+ name = "walkdir"
4037
+ version = "2.5.0"
4038
+ source = "registry+https://github.com/rust-lang/crates.io-index"
4039
+ checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
4040
+ dependencies = [
4041
+ "same-file",
4042
+ "winapi-util",
4043
+ ]
4044
+
3806
4045
  [[package]]
3807
4046
  name = "want"
3808
4047
  version = "0.3.1"
@@ -4323,18 +4562,18 @@ dependencies = [
4323
4562
 
4324
4563
  [[package]]
4325
4564
  name = "zstd-safe"
4326
- version = "7.2.4"
4565
+ version = "7.2.1"
4327
4566
  source = "registry+https://github.com/rust-lang/crates.io-index"
4328
- checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
4567
+ checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059"
4329
4568
  dependencies = [
4330
4569
  "zstd-sys",
4331
4570
  ]
4332
4571
 
4333
4572
  [[package]]
4334
4573
  name = "zstd-sys"
4335
- version = "2.0.16+zstd.1.5.7"
4574
+ version = "2.0.13+zstd.1.5.6"
4336
4575
  source = "registry+https://github.com/rust-lang/crates.io-index"
4337
- checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
4576
+ checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa"
4338
4577
  dependencies = [
4339
4578
  "cc",
4340
4579
  "pkg-config",
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/quickhouse-core", "crates/quickhouse-py"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.3.1"
6
+ version = "0.3.3"
7
7
  edition = "2021"
8
8
  license = "MIT"
9
9
  authors = ["quickhouse contributors"]
@@ -50,6 +50,21 @@ base64 = "0.22"
50
50
  # verify the wire format. Pinned to the versions the bigquery crate resolves.
51
51
  prost = "0.13"
52
52
  prost-types = "0.13"
53
+ # For the opt-in S3 data-lake archival path (ClickHouse destination only):
54
+ # pinned to the exact arrow 53.x release line so `RecordBatch`es already
55
+ # flowing through this crate's decoders pass straight into the Parquet
56
+ # writer with zero conversion — a newer `parquet` would pull in a second,
57
+ # incompatible `arrow-array` version (verified via `cargo tree`).
58
+ parquet = { version = "53", default-features = false, features = ["arrow", "async", "object_store", "zstd", "snap"] }
59
+ # Pinned to exactly the version `parquet` 53.4.0 itself depends on
60
+ # (object_store = "0.11.0") — a newer object_store would resolve as a SECOND,
61
+ # incompatible copy in the dependency graph (verified: this crate's own
62
+ # `ObjectStore`/`Path` types wouldn't type-check against parquet's).
63
+ # `aws` feature builds on reqwest/rustls (not native-tls), matching this
64
+ # workspace's pure-rustls stack; it also pulls in `aws-lc-rs` as a rustls
65
+ # crypto backend, but the process-wide `ring` install in sync.rs already
66
+ # handles exactly this "another dependency's rustls backend" scenario.
67
+ object_store = { version = "=0.11.2", default-features = false, features = ["aws"] }
53
68
 
54
69
  # Faster release builds for the shipped wheel.
55
70
  [profile.release]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quickhouse
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -15,6 +15,8 @@ Requires-Dist: psycopg[binary]>=3.1 ; extra == 'test'
15
15
  Requires-Dist: pymysql>=1.1 ; extra == 'test'
16
16
  Requires-Dist: clickhouse-connect>=0.7 ; extra == 'test'
17
17
  Requires-Dist: tqdm>=4.60 ; extra == 'test'
18
+ Requires-Dist: boto3>=1.34 ; extra == 'test'
19
+ Requires-Dist: pyarrow>=14 ; extra == 'test'
18
20
  Provides-Extra: progress
19
21
  Provides-Extra: test
20
22
  License-File: LICENSE
@@ -131,6 +133,26 @@ Application Default Credentials. As a **destination** it also takes
131
133
  `write_method`: the default `"insert_all"` (simple, proven) or the opt-in
132
134
  `"storage_write"` (the gRPC Storage Write API — free and higher-throughput).
133
135
 
136
+ A ClickHouse destination can also archive every synced batch to S3 as a data
137
+ lake — a secondary, best-effort-free backup independent of ClickHouse's own
138
+ retention:
139
+
140
+ ```python
141
+ qh.ClickHouse(
142
+ "http://host:8123", database="analytics",
143
+ archive=qh.S3Archive(bucket="my-data-lake", prefix="quickhouse"),
144
+ )
145
+ ```
146
+
147
+ This streams Parquet — one file per parallel partition, never fully buffered
148
+ in memory — to `s3://{bucket}/{prefix}/{dest_table}/dt=<date>/run=<id>/
149
+ part-<partition>.parquet`, a Hive-style layout directly queryable by Athena,
150
+ Spark, or DuckDB. Credentials fall back to the standard AWS chain (env vars,
151
+ IAM role) unless overridden; pass `endpoint=` for an S3-compatible service
152
+ like MinIO. A persistent upload failure fails the whole `sync()` call, same as
153
+ a ClickHouse insert failure. Storage/request costs are billed by AWS as usual
154
+ (free on a self-hosted MinIO).
155
+
134
156
  The DDL knobs (`engine`, `partition_by`, `order_by`, `primary_key`, `key`) are
135
157
  interpreted per destination — for ClickHouse they shape the `MergeTree`
136
158
  DDL; for BigQuery they map to partitioning and clustering. quickhouse creates
@@ -144,7 +166,13 @@ atomically — a crash mid-run never leaves the destination partial. For a
144
166
  BigQuery destination that swap runs as a query (a billed scan of the staged
145
167
  data), not a free copy job — BigQuery's copy jobs can silently skip rows still
146
168
  sitting in a table's streaming buffer, so a real query is what keeps this
147
- correct rather than just fast.
169
+ correct rather than just fast. One accepted tradeoff on the ClickHouse path:
170
+ an insert retried after a lost acknowledgment (not after a crash — the
171
+ transfer is still running) can duplicate one batch's rows in the staging
172
+ table, since `mode="full"` has no engine-level dedup like `ReplacingMergeTree`
173
+ — rare, and harmless for `key`-based incremental syncs, but worth knowing if
174
+ you see an unexpected small over-count on a full-refresh right after a
175
+ transient network blip.
148
176
 
149
177
  **Incremental** tracks a high-water mark (the `watermark` column) in a small
150
178
  state table in the destination and copies only newer rows. Updated rows are
@@ -152,6 +180,12 @@ deduplicated on `key` — via ClickHouse's `ReplacingMergeTree`, or a `MERGE`
152
180
  upsert on BigQuery (where `key` is therefore required). Re-running with no new
153
181
  data does nothing.
154
182
 
183
+ Both modes stage through a per-run-unique table (`{dest}_quickhouse_tmp_<id>`)
184
+ that's dropped when the run finishes, including on failure. The unique name is
185
+ what makes rapid re-runs and whole-call retries safe on BigQuery, whose
186
+ streaming ingestion rejects writes into a table recently recreated under the
187
+ same name.
188
+
155
189
  For daily syncs that need to catch late-arriving or edited rows, set
156
190
  `lookback_seconds` to re-scan a trailing window (e.g. `3 * 86400` for the last
157
191
  three days) — the dedup above keeps that overlap from creating duplicates.
@@ -196,8 +230,14 @@ timestamps across as-is, and booleans preserved. A few deliberate choices worth
196
230
  knowing:
197
231
 
198
232
  - **Arbitrary-precision decimals** (`numeric`/`DECIMAL`/`NUMERIC`) default to
199
- `Float64`, since precision can't be recovered from the type alone. Pin an
200
- exact type with `type_overrides` (e.g. `"Decimal(18, 2)"`).
233
+ `Float64`, since precision can't be recovered from the type alone pin an
234
+ exact type with `type_overrides` (e.g. `"Decimal(18, 2)"`, `P <= 38`) and the
235
+ value is decoded exactly (no `Float64` round-trip), not just declared with
236
+ the right destination type. A value that doesn't fit the declared precision,
237
+ or is NaN/Infinity (PostgreSQL `numeric` only), coerces to `NULL` with a
238
+ warning, same as the out-of-range-date handling below. `P > 38`
239
+ (`Decimal256`) isn't supported yet and is rejected as a config error up
240
+ front, rather than silently falling back to `Float64`.
201
241
  - **`TIME`** columns transfer as canonical text into a `String` column
202
242
  (ClickHouse has no time-of-day type).
203
243
  - **Out-of-range dates** (and MySQL zero-dates like `0000-00-00`) coerce to
@@ -101,6 +101,26 @@ Application Default Credentials. As a **destination** it also takes
101
101
  `write_method`: the default `"insert_all"` (simple, proven) or the opt-in
102
102
  `"storage_write"` (the gRPC Storage Write API — free and higher-throughput).
103
103
 
104
+ A ClickHouse destination can also archive every synced batch to S3 as a data
105
+ lake — a secondary, best-effort-free backup independent of ClickHouse's own
106
+ retention:
107
+
108
+ ```python
109
+ qh.ClickHouse(
110
+ "http://host:8123", database="analytics",
111
+ archive=qh.S3Archive(bucket="my-data-lake", prefix="quickhouse"),
112
+ )
113
+ ```
114
+
115
+ This streams Parquet — one file per parallel partition, never fully buffered
116
+ in memory — to `s3://{bucket}/{prefix}/{dest_table}/dt=<date>/run=<id>/
117
+ part-<partition>.parquet`, a Hive-style layout directly queryable by Athena,
118
+ Spark, or DuckDB. Credentials fall back to the standard AWS chain (env vars,
119
+ IAM role) unless overridden; pass `endpoint=` for an S3-compatible service
120
+ like MinIO. A persistent upload failure fails the whole `sync()` call, same as
121
+ a ClickHouse insert failure. Storage/request costs are billed by AWS as usual
122
+ (free on a self-hosted MinIO).
123
+
104
124
  The DDL knobs (`engine`, `partition_by`, `order_by`, `primary_key`, `key`) are
105
125
  interpreted per destination — for ClickHouse they shape the `MergeTree`
106
126
  DDL; for BigQuery they map to partitioning and clustering. quickhouse creates
@@ -114,7 +134,13 @@ atomically — a crash mid-run never leaves the destination partial. For a
114
134
  BigQuery destination that swap runs as a query (a billed scan of the staged
115
135
  data), not a free copy job — BigQuery's copy jobs can silently skip rows still
116
136
  sitting in a table's streaming buffer, so a real query is what keeps this
117
- correct rather than just fast.
137
+ correct rather than just fast. One accepted tradeoff on the ClickHouse path:
138
+ an insert retried after a lost acknowledgment (not after a crash — the
139
+ transfer is still running) can duplicate one batch's rows in the staging
140
+ table, since `mode="full"` has no engine-level dedup like `ReplacingMergeTree`
141
+ — rare, and harmless for `key`-based incremental syncs, but worth knowing if
142
+ you see an unexpected small over-count on a full-refresh right after a
143
+ transient network blip.
118
144
 
119
145
  **Incremental** tracks a high-water mark (the `watermark` column) in a small
120
146
  state table in the destination and copies only newer rows. Updated rows are
@@ -122,6 +148,12 @@ deduplicated on `key` — via ClickHouse's `ReplacingMergeTree`, or a `MERGE`
122
148
  upsert on BigQuery (where `key` is therefore required). Re-running with no new
123
149
  data does nothing.
124
150
 
151
+ Both modes stage through a per-run-unique table (`{dest}_quickhouse_tmp_<id>`)
152
+ that's dropped when the run finishes, including on failure. The unique name is
153
+ what makes rapid re-runs and whole-call retries safe on BigQuery, whose
154
+ streaming ingestion rejects writes into a table recently recreated under the
155
+ same name.
156
+
125
157
  For daily syncs that need to catch late-arriving or edited rows, set
126
158
  `lookback_seconds` to re-scan a trailing window (e.g. `3 * 86400` for the last
127
159
  three days) — the dedup above keeps that overlap from creating duplicates.
@@ -166,8 +198,14 @@ timestamps across as-is, and booleans preserved. A few deliberate choices worth
166
198
  knowing:
167
199
 
168
200
  - **Arbitrary-precision decimals** (`numeric`/`DECIMAL`/`NUMERIC`) default to
169
- `Float64`, since precision can't be recovered from the type alone. Pin an
170
- exact type with `type_overrides` (e.g. `"Decimal(18, 2)"`).
201
+ `Float64`, since precision can't be recovered from the type alone pin an
202
+ exact type with `type_overrides` (e.g. `"Decimal(18, 2)"`, `P <= 38`) and the
203
+ value is decoded exactly (no `Float64` round-trip), not just declared with
204
+ the right destination type. A value that doesn't fit the declared precision,
205
+ or is NaN/Infinity (PostgreSQL `numeric` only), coerces to `NULL` with a
206
+ warning, same as the out-of-range-date handling below. `P > 38`
207
+ (`Decimal256`) isn't supported yet and is rejected as a config error up
208
+ front, rather than silently falling back to `Float64`.
171
209
  - **`TIME`** columns transfer as canonical text into a `String` column
172
210
  (ClickHouse has no time-of-day type).
173
211
  - **Out-of-range dates** (and MySQL zero-dates like `0000-00-00`) coerce to
@@ -36,6 +36,8 @@ time.workspace = true
36
36
  base64.workspace = true
37
37
  prost.workspace = true
38
38
  prost-types.workspace = true
39
+ parquet.workspace = true
40
+ object_store.workspace = true
39
41
 
40
42
  [dev-dependencies]
41
43
  anyhow.workspace = true