-
Notifications
You must be signed in to change notification settings - Fork 111
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
Feature request: be able to build queries directly in rust, bypassing the script parser #224
Comments
That sounds very useful indeed. I've been trying to use cozo in a project of mine (rusty, of course) for the past few months. It kind of works, but I have thought about writing some wrapper myself multiple times because it's not very pretty and feels error-prone (if you want to stay type-safe, you need to My current (also ugly) workaround are these two macros, which provide some assistance for very basic DB operations and nothing else. I think the existence of this illustrates the pain one currently goes through when using cozo in some project: #[macro_export]
macro_rules! build_query {
($payload:expr, $params:expr) => {{
use cozo::DataValue;
use std::collections::BTreeMap;
// Build parameters map
let mut params_map: BTreeMap<String, DataValue> = Default::default();
let mut parameters_init = String::new();
if $params.len() > 0 {
for (name, value) in $params {
let _: &str = name; // only for type annotation
params_map.insert(name.to_string(), value);
}
// First line: Initialize parameters, make them available in CozoScript
use itertools::Itertools;
parameters_init += "?[";
parameters_init += ¶ms_map
.iter()
.map(|(name, _)| name)
.format(", ")
.to_string();
parameters_init += "] <- [[";
parameters_init += ¶ms_map
.iter()
.map(|(name, _)| format!("${}", name))
.format(", ")
.to_string();
parameters_init += "]]";
}
// Return query string and parameters map
(format!("{}\n\n{}", parameters_init, $payload), params_map)
}};
}
use build_query;
#[macro_export]
macro_rules! run_query {
($db:expr, $payload:expr, $params:expr, $mutability:expr) => {{
let (query, parameters) = crate::state::queries::build_query!($payload, $params);
$db.run_script(query.as_str(), parameters, $mutability)
}};
} An example insert-query wrapper function now looks like this: pub fn add(
db: &DbInstance,
id: &AppId,
last_access: &DateTime<Utc>,
name: &str,
description: &str,
) -> anyhow::Result<()> {
let params = vec![
(
"id",
DataValue::Str(serde_json::to_string(&id).unwrap().into()),
),
(
"last_access",
DataValue::Num(Num::Int(last_access.timestamp())),
),
("name", DataValue::Str(name.into())),
("description", DataValue::Str(description.into())),
];
match run_query!(
&db,
":insert apps {id => last_access, name, description}",
params,
cozo::ScriptMutability::Mutable
) {
Ok(_) => Ok(()),
Err(report) => bail!(report),
}
} As I said, I'm still rather new to cozo so I don't want to judge any of the dev's decision and I'm grateful for their (your) work. Maybe there are better ways already. But to me as a novice, it's at least not ergonomic ;) |
I'm not sure if this is a bad idea, but I'd like to do some security filtering on user queries:
AFAICT recursing the datalog and making changes should be pretty simple and comprehensive, if it's basically a typed tree of enums/structs. I'd be happy with something explicitly unstable. |
I made a PR, let's see how this goes... |
What I wanted to do was be able to write cozo queries directly in rust, and use the various rust structs in the cozo lib to bypass the cozoscript parser. Then I wouldn't have to mess with formatting strings, and it would potentially be a lot cleaner.
However all those structs are all crate private, so I can't bypass the parser. I'm talking about
InputProgram
and the various other structs contained therein - I'd like to be able to instantiate those myself, and pass them to whatever function executes the parsed script.The text was updated successfully, but these errors were encountered: