1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use rbs::Value;
/// take `vec![Table{"id":1}]` columns
pub trait ColumnSet {
fn column_sets(&self) -> Value;
}
impl ColumnSet for Value {
fn column_sets(&self) -> Value {
// Fast path: empty array
let array = match self.as_array() {
Some(arr) if !arr.is_empty() => arr,
_ => return rbs::Value::Array(vec![]),
};
// Fast path: single element - directly extract non-null columns
// This avoids HashSet allocation for the common case (single row insert)
if array.len() == 1 {
if let Some(table) = array.first() {
let mut column_datas = Vec::with_capacity(table.len());
for (column, value) in table {
if *value != rbs::Value::Null {
column_datas.push(column.clone());
}
}
return rbs::Value::from(column_datas);
}
}
// Slow path: multiple elements - collect non-null columns across all rows
let mut column_set = std::collections::HashSet::with_capacity(array.len() * 8);
for item in array {
for (k, v) in item {
if *v != rbs::Value::Null {
column_set.insert(k.clone());
}
}
}
if let Some(table) = array.first() {
let mut column_datas = Vec::with_capacity(table.len());
for (column, _) in table {
if column_set.contains(&column) {
column_datas.push(column.clone());
}
}
rbs::Value::from(column_datas)
} else {
rbs::Value::Array(vec![])
}
}
}
/// create sql opt from rbs::Value
pub trait ValueOperatorSql {
fn operator_sql(&self) -> String;
}
impl ValueOperatorSql for Value {
fn operator_sql(&self) -> String {
match self {
Value::String(v) => {
if v.contains(" ") {
v.to_string()
}else{
format!("{}{}",v," = ")
}
}
Value::Ext(_, v) => {v.operator_sql()}
_=>{"".to_string()}
}
}
}
/// Filter value by specified columns
pub trait FilterByColumns {
fn filter_by_columns(&self, columns: &Value) -> Value;
}
impl FilterByColumns for Value {
fn filter_by_columns(&self, columns: &Value) -> Value {
match self {
Value::Map(map) => {
// Extract column names from the columns Value
let column_names = match columns {
Value::Array(arr) => {
if arr.is_empty() {
// Empty array means no columns to filter, return empty map
return Value::Map(rbs::value::map::ValueMap::new());
}
arr.iter()
.filter_map(|v| v.as_str())
.collect::<std::collections::HashSet<&str>>()
}
_ => {
// If columns is not an array, return original value
return self.clone();
}
};
if column_names.is_empty() {
// No valid column names, return empty map
return Value::Map(rbs::value::map::ValueMap::new());
}
let mut filtered_map = rbs::value::map::ValueMap::new();
for (key, value) in map {
if let Some(key_str) = key.as_str() {
if column_names.contains(key_str) {
filtered_map.insert(key.clone(), value.clone());
}
}
}
Value::Map(filtered_map)
}
_ => self.clone()
}
}
}