quack-ruby 0.1.0

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 (50) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/LICENSE-DuckDB +7 -0
  4. data/LICENSE-QuackProtocol +21 -0
  5. data/LICENSE-Rust-dependencies.json +2057 -0
  6. data/README.md +229 -0
  7. data/ext/quack/Cargo.lock +1803 -0
  8. data/ext/quack/Cargo.toml +17 -0
  9. data/ext/quack/extconf.rb +4 -0
  10. data/ext/quack/src/lib.rs +647 -0
  11. data/ext/quack/vendor/quack_protocol/Cargo.lock +1907 -0
  12. data/ext/quack/vendor/quack_protocol/Cargo.toml +41 -0
  13. data/ext/quack/vendor/quack_protocol/LICENSE +21 -0
  14. data/ext/quack/vendor/quack_protocol/PATCHES.md +16 -0
  15. data/ext/quack/vendor/quack_protocol/README.md +272 -0
  16. data/ext/quack/vendor/quack_protocol/src/arrow/columns.rs +399 -0
  17. data/ext/quack/vendor/quack_protocol/src/arrow/mod.rs +134 -0
  18. data/ext/quack/vendor/quack_protocol/src/arrow/schema.rs +103 -0
  19. data/ext/quack/vendor/quack_protocol/src/arrow/tests.rs +851 -0
  20. data/ext/quack/vendor/quack_protocol/src/arrow/values.rs +150 -0
  21. data/ext/quack/vendor/quack_protocol/src/binary.rs +504 -0
  22. data/ext/quack/vendor/quack_protocol/src/builders.rs +217 -0
  23. data/ext/quack/vendor/quack_protocol/src/client.rs +1486 -0
  24. data/ext/quack/vendor/quack_protocol/src/constants.rs +11 -0
  25. data/ext/quack/vendor/quack_protocol/src/errors.rs +103 -0
  26. data/ext/quack/vendor/quack_protocol/src/inspection.rs +250 -0
  27. data/ext/quack/vendor/quack_protocol/src/json.rs +225 -0
  28. data/ext/quack/vendor/quack_protocol/src/lib.rs +54 -0
  29. data/ext/quack/vendor/quack_protocol/src/logical_types.rs +977 -0
  30. data/ext/quack/vendor/quack_protocol/src/messages.rs +843 -0
  31. data/ext/quack/vendor/quack_protocol/src/pool.rs +741 -0
  32. data/ext/quack/vendor/quack_protocol/src/protocol_tests.rs +759 -0
  33. data/ext/quack/vendor/quack_protocol/src/proxy_error.rs +77 -0
  34. data/ext/quack/vendor/quack_protocol/src/sql.rs +359 -0
  35. data/ext/quack/vendor/quack_protocol/src/tls.rs +354 -0
  36. data/ext/quack/vendor/quack_protocol/src/values.rs +77 -0
  37. data/ext/quack/vendor/quack_protocol/src/vector.rs +1364 -0
  38. data/ext/quack/vendor/quack_protocol/testdata/tls/key.der +0 -0
  39. data/ext/quack/vendor/quack_protocol/testdata/tls/spki.der +0 -0
  40. data/ext/quack/vendor/quack_protocol/testdata/tls/v1-cert.der +0 -0
  41. data/ext/quack/vendor/quack_protocol/testdata/tls/v3-cert.der +0 -0
  42. data/lib/quack/codec.rb +263 -0
  43. data/lib/quack/connection.rb +131 -0
  44. data/lib/quack/logical_types.rb +72 -0
  45. data/lib/quack/result.rb +64 -0
  46. data/lib/quack/sql.rb +183 -0
  47. data/lib/quack/types.rb +40 -0
  48. data/lib/quack/variant.rb +298 -0
  49. data/lib/quack.rb +34 -0
  50. metadata +136 -0
@@ -0,0 +1,217 @@
1
+ use indexmap::IndexMap;
2
+
3
+ use crate::errors::{QuackError, Result};
4
+ use crate::logical_types::{
5
+ ChildType, LogicalType, LogicalTypeId, LogicalTypes, get_child_type, get_struct_children,
6
+ struct_child_key,
7
+ };
8
+ use crate::vector::{DataChunk, DecodedVector, TimeUnit, TimestampUnit, Value, VectorType};
9
+
10
+ #[derive(Clone, Debug, PartialEq)]
11
+ pub struct ColumnInput {
12
+ pub name: Option<String>,
13
+ pub logical_type: LogicalType,
14
+ pub values: Vec<Value>,
15
+ }
16
+
17
+ #[derive(Clone, Debug, PartialEq)]
18
+ pub struct ColumnDefinition {
19
+ pub name: String,
20
+ pub logical_type: LogicalType,
21
+ }
22
+
23
+ pub fn column(
24
+ logical_type: LogicalType,
25
+ values: impl IntoIterator<Item = Value>,
26
+ name: impl Into<Option<String>>,
27
+ ) -> ColumnInput {
28
+ ColumnInput {
29
+ name: name.into(),
30
+ logical_type,
31
+ values: values.into_iter().collect(),
32
+ }
33
+ }
34
+
35
+ pub fn data_chunk(columns: Vec<ColumnInput>) -> Result<DataChunk> {
36
+ if columns.is_empty() {
37
+ return Err(QuackError::protocol(
38
+ "a Quack DataChunk must contain at least one column",
39
+ ));
40
+ }
41
+ let row_count = columns[0].values.len();
42
+ let mut types = Vec::with_capacity(columns.len());
43
+ let mut decoded_columns = Vec::with_capacity(columns.len());
44
+ let mut names = Vec::with_capacity(columns.len());
45
+
46
+ for (index, input) in columns.into_iter().enumerate() {
47
+ if input.values.len() != row_count {
48
+ return Err(QuackError::protocol(format!(
49
+ "column {index} has {} values, expected {row_count}",
50
+ input.values.len()
51
+ )));
52
+ }
53
+ names.push(input.name.unwrap_or_else(|| format!("column{index}")));
54
+ types.push(input.logical_type.clone());
55
+ decoded_columns.push(DecodedVector {
56
+ logical_type: input.logical_type,
57
+ vector_type: VectorType::Flat,
58
+ values: input.values,
59
+ });
60
+ }
61
+
62
+ Ok(DataChunk {
63
+ row_count,
64
+ types,
65
+ columns: decoded_columns,
66
+ column_names: Some(names),
67
+ })
68
+ }
69
+
70
+ pub fn data_chunk_from_rows(
71
+ rows: &[IndexMap<String, Value>],
72
+ columns: Option<Vec<ColumnDefinition>>,
73
+ ) -> Result<DataChunk> {
74
+ let definitions = match columns {
75
+ Some(columns) => columns,
76
+ None => infer_column_definitions(rows)?,
77
+ };
78
+ let inputs = definitions
79
+ .iter()
80
+ .map(|definition| {
81
+ let values = rows
82
+ .iter()
83
+ .map(|row| {
84
+ normalize_append_value(
85
+ row.get(&definition.name).cloned().unwrap_or(Value::Null),
86
+ &definition.logical_type,
87
+ )
88
+ })
89
+ .collect::<Result<Vec<_>>>()?;
90
+ Ok(ColumnInput {
91
+ name: Some(definition.name.clone()),
92
+ logical_type: definition.logical_type.clone(),
93
+ values,
94
+ })
95
+ })
96
+ .collect::<Result<Vec<_>>>()?;
97
+ data_chunk(inputs)
98
+ }
99
+
100
+ fn infer_column_definitions(rows: &[IndexMap<String, Value>]) -> Result<Vec<ColumnDefinition>> {
101
+ let first = rows.first().ok_or_else(|| {
102
+ QuackError::protocol("cannot infer append row columns from an empty row set")
103
+ })?;
104
+ first
105
+ .keys()
106
+ .map(|name| {
107
+ Ok(ColumnDefinition {
108
+ name: name.clone(),
109
+ logical_type: infer_logical_type(
110
+ &rows
111
+ .iter()
112
+ .map(|row| row.get(name).cloned().unwrap_or(Value::Null))
113
+ .collect::<Vec<_>>(),
114
+ )?,
115
+ })
116
+ })
117
+ .collect()
118
+ }
119
+
120
+ fn infer_logical_type(values: &[Value]) -> Result<LogicalType> {
121
+ let value = values
122
+ .iter()
123
+ .find(|value| !value.is_null())
124
+ .ok_or_else(|| QuackError::protocol("cannot infer logical type from only null values"))?;
125
+ Ok(match value {
126
+ Value::Null => unreachable!(),
127
+ Value::Bool(_) => LogicalTypes::boolean(),
128
+ Value::Int(value) if *value >= i32::MIN as i64 && *value <= i32::MAX as i64 => {
129
+ LogicalTypes::integer()
130
+ }
131
+ Value::Int(_) => LogicalTypes::bigint(),
132
+ Value::UInt(value) if *value <= u32::MAX as u64 => LogicalTypes::uinteger(),
133
+ Value::UInt(_) => LogicalTypes::ubigint(),
134
+ Value::HugeInt(_) => LogicalTypes::hugeint(),
135
+ Value::UHugeInt(_) => LogicalTypes::uhugeint(),
136
+ Value::Float(_) => LogicalTypes::float(),
137
+ Value::Double(_) => LogicalTypes::double(),
138
+ Value::String(_) => LogicalTypes::varchar(),
139
+ Value::Bytes(_) => LogicalTypes::blob(),
140
+ Value::Decimal(value) => LogicalTypes::decimal(value.width, value.scale),
141
+ Value::Date(_) => LogicalTypes::date(),
142
+ Value::Time(value) => match value.unit {
143
+ TimeUnit::Micros => LogicalTypes::time(),
144
+ TimeUnit::Nanos => LogicalTypes::time_ns(),
145
+ },
146
+ Value::TimeTz(_) => LogicalTypes::time_tz(),
147
+ Value::Timestamp(value) => match value.unit {
148
+ TimestampUnit::Seconds => LogicalTypes::timestamp_seconds(),
149
+ TimestampUnit::Millis => LogicalTypes::timestamp_millis(),
150
+ TimestampUnit::Micros if value.timezone_utc => LogicalTypes::timestamp_tz(),
151
+ TimestampUnit::Micros => LogicalTypes::timestamp(),
152
+ TimestampUnit::Nanos => LogicalTypes::timestamp_nanos(),
153
+ },
154
+ Value::Interval(_) => LogicalTypes::interval(),
155
+ Value::List(items) => LogicalTypes::list(infer_logical_type(items)?),
156
+ Value::Struct(row) => LogicalTypes::r#struct(
157
+ row.keys()
158
+ .map(|name| {
159
+ let child_values = values
160
+ .iter()
161
+ .map(|value| match value {
162
+ Value::Struct(row) => row.get(name).cloned().unwrap_or(Value::Null),
163
+ _ => Value::Null,
164
+ })
165
+ .collect::<Vec<_>>();
166
+ Ok(ChildType {
167
+ name: name.clone(),
168
+ logical_type: infer_logical_type(&child_values)?,
169
+ })
170
+ })
171
+ .collect::<Result<Vec<_>>>()?,
172
+ ),
173
+ })
174
+ }
175
+
176
+ fn normalize_append_value(value: Value, logical_type: &LogicalType) -> Result<Value> {
177
+ if value.is_null() {
178
+ return Ok(Value::Null);
179
+ }
180
+ match value {
181
+ Value::List(values)
182
+ if matches!(
183
+ logical_type.id,
184
+ LogicalTypeId::List | LogicalTypeId::Map | LogicalTypeId::Array
185
+ ) =>
186
+ {
187
+ let child_type = get_child_type(logical_type)?;
188
+ Ok(Value::List(
189
+ values
190
+ .into_iter()
191
+ .map(|value| normalize_append_value(value, child_type))
192
+ .collect::<Result<Vec<_>>>()?,
193
+ ))
194
+ }
195
+ Value::Struct(row)
196
+ if matches!(
197
+ logical_type.id,
198
+ LogicalTypeId::Struct | LogicalTypeId::Tuple
199
+ ) =>
200
+ {
201
+ let children = get_struct_children(logical_type)?;
202
+ let mut normalized = IndexMap::new();
203
+ for (index, child) in children.iter().enumerate() {
204
+ let key = struct_child_key(logical_type, index, child);
205
+ normalized.insert(
206
+ key.clone(),
207
+ normalize_append_value(
208
+ row.get(&key).cloned().unwrap_or(Value::Null),
209
+ &child.logical_type,
210
+ )?,
211
+ );
212
+ }
213
+ Ok(Value::Struct(normalized))
214
+ }
215
+ other => Ok(other),
216
+ }
217
+ }