Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow objects and structs as source of named query params #75

Merged
merged 1 commit into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,19 @@ pub async fn run(ctx, i) {
}
```

Query parameters can be bound and passed by names as well:
```rust
const INSERT = "my_insert";

pub async fn prepare(ctx) {
ctx.prepare(INSERT, "INSERT INTO test.test(id, data) VALUES (:id, :data)").await?;
}

pub async fn run(ctx, i) {
ctx.execute_prepared(INSERT, #{id: 5, data: "foo"}).await
}
```

### Populating the database

Read queries are more interesting when they return non-empty result sets.
Expand Down
73 changes: 61 additions & 12 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -624,22 +624,31 @@ mod bind {
field_types,
},
) => {
let borrowed = v.borrow_ref().unwrap();
let mut fields = Vec::new();
for (field_name, field_type) in field_types {
let value = match borrowed.get_value(field_name) {
Err(_) => None,
Ok(None) => Some(CqlValue::Empty),
Ok(Some(value)) => Some(to_scylla_value(&value, field_type)?),
};
fields.push((field_name.to_string(), value))
}
let obj = v.borrow_ref().unwrap();
let fields = read_fields(|s| obj.get(s), field_types)?;
Ok(CqlValue::UserDefinedType {
keyspace: keyspace.to_string(),
type_name: type_name.to_string(),
fields,
})
}
(
Value::Struct(v),
ColumnType::UserDefinedType {
keyspace,
type_name,
field_types,
},
) => {
let obj = v.borrow_ref().unwrap();
let fields = read_fields(|s| obj.get(s), field_types)?;
Ok(CqlValue::UserDefinedType {
keyspace: keyspace.to_string(),
type_name: type_name.to_string(),
fields,
})
}

(Value::Any(obj), ColumnType::Uuid) => {
let obj = obj.borrow_ref().unwrap();
let h = obj.type_hash();
Expand Down Expand Up @@ -680,28 +689,68 @@ mod bind {
params: &Value,
types: &[ColumnSpec],
) -> Result<Vec<CqlValue>, CassError> {
let mut values = Vec::new();
match params {
Ok(match params {
Value::Tuple(tuple) => {
let mut values = Vec::new();
let tuple = tuple.borrow_ref().unwrap();
if tuple.len() != types.len() {
return Err(CassError(CassErrorKind::InvalidNumberOfQueryParams));
}
for (v, t) in tuple.iter().zip(types) {
values.push(to_scylla_value(v, &t.typ)?);
}
values
}
Value::Vec(vec) => {
let mut values = Vec::new();

let vec = vec.borrow_ref().unwrap();
for (v, t) in vec.iter().zip(types) {
values.push(to_scylla_value(v, &t.typ)?);
}
values
}
Value::Object(obj) => {
let obj = obj.borrow_ref().unwrap();
read_params(|f| obj.get(f), types)?
}
Value::Struct(obj) => {
let obj = obj.borrow_ref().unwrap();
read_params(|f| obj.get(f), types)?
}
other => {
return Err(CassError(CassErrorKind::InvalidQueryParamsObject(
other.type_info().unwrap(),
)));
}
})
}

fn read_params<'a, 'b>(
get_value: impl Fn(&String) -> Option<&'a Value>,
params: &[ColumnSpec],
) -> Result<Vec<CqlValue>, CassError> {
let mut values = Vec::with_capacity(params.len());
for column in params {
let value = match get_value(&column.name) {
Some(value) => to_scylla_value(value, &column.typ)?,
None => CqlValue::Empty,
};
values.push(value)
}
Ok(values)
}

fn read_fields<'a, 'b>(
get_value: impl Fn(&String) -> Option<&'a Value>,
fields: &[(String, ColumnType)],
) -> Result<Vec<(String, Option<CqlValue>)>, CassError> {
let mut values = Vec::with_capacity(fields.len());
for (field_name, field_type) in fields {
if let Some(value) = get_value(field_name) {
let value = Some(to_scylla_value(value, field_type)?);
values.push((field_name.to_string(), value))
};
}
Ok(values)
}
Expand Down
Loading