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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/LICENSE-DuckDB +7 -0
- data/LICENSE-QuackProtocol +21 -0
- data/LICENSE-Rust-dependencies.json +2057 -0
- data/README.md +229 -0
- data/ext/quack/Cargo.lock +1803 -0
- data/ext/quack/Cargo.toml +17 -0
- data/ext/quack/extconf.rb +4 -0
- data/ext/quack/src/lib.rs +647 -0
- data/ext/quack/vendor/quack_protocol/Cargo.lock +1907 -0
- data/ext/quack/vendor/quack_protocol/Cargo.toml +41 -0
- data/ext/quack/vendor/quack_protocol/LICENSE +21 -0
- data/ext/quack/vendor/quack_protocol/PATCHES.md +16 -0
- data/ext/quack/vendor/quack_protocol/README.md +272 -0
- data/ext/quack/vendor/quack_protocol/src/arrow/columns.rs +399 -0
- data/ext/quack/vendor/quack_protocol/src/arrow/mod.rs +134 -0
- data/ext/quack/vendor/quack_protocol/src/arrow/schema.rs +103 -0
- data/ext/quack/vendor/quack_protocol/src/arrow/tests.rs +851 -0
- data/ext/quack/vendor/quack_protocol/src/arrow/values.rs +150 -0
- data/ext/quack/vendor/quack_protocol/src/binary.rs +504 -0
- data/ext/quack/vendor/quack_protocol/src/builders.rs +217 -0
- data/ext/quack/vendor/quack_protocol/src/client.rs +1486 -0
- data/ext/quack/vendor/quack_protocol/src/constants.rs +11 -0
- data/ext/quack/vendor/quack_protocol/src/errors.rs +103 -0
- data/ext/quack/vendor/quack_protocol/src/inspection.rs +250 -0
- data/ext/quack/vendor/quack_protocol/src/json.rs +225 -0
- data/ext/quack/vendor/quack_protocol/src/lib.rs +54 -0
- data/ext/quack/vendor/quack_protocol/src/logical_types.rs +977 -0
- data/ext/quack/vendor/quack_protocol/src/messages.rs +843 -0
- data/ext/quack/vendor/quack_protocol/src/pool.rs +741 -0
- data/ext/quack/vendor/quack_protocol/src/protocol_tests.rs +759 -0
- data/ext/quack/vendor/quack_protocol/src/proxy_error.rs +77 -0
- data/ext/quack/vendor/quack_protocol/src/sql.rs +359 -0
- data/ext/quack/vendor/quack_protocol/src/tls.rs +354 -0
- data/ext/quack/vendor/quack_protocol/src/values.rs +77 -0
- data/ext/quack/vendor/quack_protocol/src/vector.rs +1364 -0
- data/ext/quack/vendor/quack_protocol/testdata/tls/key.der +0 -0
- data/ext/quack/vendor/quack_protocol/testdata/tls/spki.der +0 -0
- data/ext/quack/vendor/quack_protocol/testdata/tls/v1-cert.der +0 -0
- data/ext/quack/vendor/quack_protocol/testdata/tls/v3-cert.der +0 -0
- data/lib/quack/codec.rb +263 -0
- data/lib/quack/connection.rb +131 -0
- data/lib/quack/logical_types.rb +72 -0
- data/lib/quack/result.rb +64 -0
- data/lib/quack/sql.rb +183 -0
- data/lib/quack/types.rb +40 -0
- data/lib/quack/variant.rb +298 -0
- data/lib/quack.rb +34 -0
- 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
|
+
}
|