Skip to content

Commit 06ab743

Browse files
authored
feat(hql): Object creations (#416)
## Description <!-- Provide a brief description of the changes in this PR --> ## Related Issues <!-- Link to any related issues using #issue_number --> Closes # ## Checklist when merging to main <!-- Mark items with "x" when completed --> - [ ] No compiler warnings (if applicable) - [ ] Code is formatted with `rustfmt` - [ ] No useless or dead code (if applicable) - [ ] Code is easy to understand - [ ] Doc comments are used for all functions, enums, structs, and fields (where appropriate) - [ ] All tests pass - [ ] Performance has not regressed (assuming change was not to fix a bug) - [ ] Version number has been updated in `helix-cli/Cargo.toml` and `helixdb/Cargo.toml` ## Additional Notes <!-- Add any additional information that would be helpful for reviewers -->
2 parents d2fefde + bc37f4b commit 06ab743

File tree

8 files changed

+423
-163
lines changed

8 files changed

+423
-163
lines changed

helix-db/src/grammar.pest

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ evaluates_to_number = {
127127
// ---------------------------------------------------------------------
128128
// Return statement
129129
// ---------------------------------------------------------------------
130-
return_stmt = { "RETURN" ~ evaluates_to_anything ~ ("," ~ evaluates_to_anything)* }
130+
return_stmt = { "RETURN" ~ (evaluates_to_anything ~ ("," ~ evaluates_to_anything)* | array_creation | object_creation) }
131131

132132
// ---------------------------------------------------------------------
133133
// Creation steps
@@ -229,6 +229,10 @@ exclude_field = { "!" ~ "{" ~ identifier ~ ("," ~ identifier)* ~ "}" }
229229
closure_step = { "|" ~ identifier ~ "|" ~ object_step }
230230
spread_object = { ".." ~ ","?}
231231
mapping_field = { (identifier ~ (":" ~ (anonymous_traversal | evaluates_to_anything | object_step))) | identifier }
232+
array_creation = { "[" ~ (identifier | object_creation ) ~ ("," ~ (identifier | object_creation))* ~ ","? ~ "]" }
233+
object_creation = { "{" ~ object_inner ~ ("," ~ object_inner)* ~ ","? ~ "}" }
234+
object_inner = { identifier ~ ":" ~ object_field }
235+
object_field = { (object_creation | array_creation | evaluates_to_anything) }
232236

233237
// ---------------------------------------------------------------------
234238
// Macros

helix-db/src/helixc/analyzer/analyzer.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ use crate::helixc::{
55
methods::{
66
migration_validation::validate_migration,
77
query_validation::validate_query,
8-
schema_methods::{SchemaVersionMap, build_field_lookups, check_schema},
8+
schema_methods::{build_field_lookups, check_schema, SchemaVersionMap},
99
},
1010
types::Type,
1111
},
1212
generator::Source as GeneratedSource,
13-
parser::helix_parser::{EdgeSchema, ExpressionType, Field, Query, Source},
13+
parser::helix_parser::{EdgeSchema, ExpressionType, Field, Query, ReturnType, Source},
1414
};
1515
use itertools::Itertools;
1616
use serde::Serialize;
@@ -250,8 +250,12 @@ impl QueryData {
250250
.return_values
251251
.iter()
252252
.flat_map(|e| {
253-
if let ExpressionType::Identifier(ident) = &e.expr {
254-
Some(ident.clone())
253+
if let ReturnType::Expression(expr) = e {
254+
if let ExpressionType::Identifier(ident) = &expr.expr {
255+
Some(ident.clone())
256+
} else {
257+
None
258+
}
255259
} else {
256260
None
257261
}

helix-db/src/helixc/analyzer/methods/query_validation.rs

Lines changed: 231 additions & 104 deletions
Large diffs are not rendered by default.

helix-db/src/helixc/generator/queries.rs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,10 @@ impl Query {
8484

8585
fn print_query(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8686
// prints the function signature
87-
self.print_input_struct(f)?;
88-
self.print_parameters(f)?;
87+
if !self.parameters.is_empty() {
88+
self.print_input_struct(f)?;
89+
self.print_parameters(f)?;
90+
}
8991
self.print_handler(f)?;
9092
writeln!(
9193
f,
@@ -95,17 +97,19 @@ impl Query {
9597

9698
// print the db boilerplate
9799
writeln!(f, "let db = Arc::clone(&input.graph.storage);")?;
98-
match self.hoisted_embedding_calls.is_empty() {
99-
true => writeln!(
100-
f,
101-
"let data = input.request.in_fmt.deserialize::<{}Input>(&input.request.body)?;",
102-
self.name
103-
)?,
104-
false => writeln!(
105-
f,
106-
"let data = input.request.in_fmt.deserialize::<{}Input>(&input.request.body)?.into_owned();",
107-
self.name
108-
)?,
100+
if !self.parameters.is_empty() {
101+
match self.hoisted_embedding_calls.is_empty() {
102+
true => writeln!(
103+
f,
104+
"let data = input.request.in_fmt.deserialize::<{}Input>(&input.request.body)?;",
105+
self.name
106+
)?,
107+
false => writeln!(
108+
f,
109+
"let data = input.request.in_fmt.deserialize::<{}Input>(&input.request.body)?.into_owned();",
110+
self.name
111+
)?,
112+
}
109113
}
110114

111115
// print embedding calls
@@ -221,10 +225,7 @@ impl Query {
221225
)?;
222226

223227
writeln!(f, "connection.iter = result.into_iter();")?;
224-
writeln!(
225-
f,
226-
"let mut connections = connections.lock().unwrap();"
227-
)?;
228+
writeln!(f, "let mut connections = connections.lock().unwrap();")?;
228229
writeln!(f, "connections.add_connection(connection);")?;
229230
writeln!(f, "drop(connections);")?;
230231
writeln!(

helix-db/src/helixc/generator/return_values.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use core::fmt;
2-
use std::fmt::Display;
2+
use std::{collections::HashMap, fmt::Display};
33

44
use crate::helixc::generator::{traversal_steps::Traversal, utils::GeneratedValue};
55

6-
76
pub struct ReturnValue {
87
pub value: ReturnValueExpr,
98
pub return_type: ReturnType,
@@ -40,8 +39,25 @@ impl Display for ReturnValue {
4039
)
4140
}
4241
ReturnType::UnnamedExpr => {
43-
write!(f, "// need to implement unnamed return value\n todo!()")?;
44-
panic!("Unnamed return value is not supported");
42+
writeln!(
43+
f,
44+
" return_vals.insert(\"data\".to_string(), ReturnValue::from_traversal_value_array_with_mixin({}.clone(), remapping_vals.borrow_mut()));",
45+
self.value
46+
)
47+
}
48+
ReturnType::HashMap => {
49+
writeln!(
50+
f,
51+
" return_vals.insert(\"data\".to_string(), ReturnValue::from({}));",
52+
self.value
53+
)
54+
}
55+
ReturnType::Array => {
56+
writeln!(
57+
f,
58+
" return_vals.insert(\"data\".to_string(), ReturnValue::from({}));",
59+
self.value
60+
)
4561
}
4662
}
4763
}
@@ -55,6 +71,8 @@ impl ReturnValue {
5571
ReturnType::NamedExpr(name) => name.inner().inner().to_string(),
5672
ReturnType::SingleExpr(name) => name.inner().inner().to_string(),
5773
ReturnType::UnnamedExpr => todo!(),
74+
ReturnType::HashMap => todo!(),
75+
ReturnType::Array => todo!(),
5876
}
5977
}
6078

@@ -88,6 +106,18 @@ impl ReturnValue {
88106
return_type: ReturnType::UnnamedExpr,
89107
}
90108
}
109+
pub fn new_array(values: Vec<ReturnValueExpr>) -> Self {
110+
Self {
111+
value: ReturnValueExpr::Array(values),
112+
return_type: ReturnType::Array,
113+
}
114+
}
115+
pub fn new_object(values: HashMap<String, ReturnValueExpr>) -> Self {
116+
Self {
117+
value: ReturnValueExpr::Object(values),
118+
return_type: ReturnType::HashMap,
119+
}
120+
}
91121
}
92122

93123
#[derive(Clone)]
@@ -97,19 +127,39 @@ pub enum ReturnType {
97127
NamedExpr(GeneratedValue),
98128
SingleExpr(GeneratedValue),
99129
UnnamedExpr,
130+
HashMap,
131+
Array,
100132
}
101133
#[derive(Clone)]
102134
pub enum ReturnValueExpr {
103135
Traversal(Traversal),
104136
Identifier(GeneratedValue),
105137
Value(GeneratedValue),
138+
Array(Vec<ReturnValueExpr>),
139+
Object(HashMap<String, ReturnValueExpr>),
106140
}
107141
impl Display for ReturnValueExpr {
108142
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109143
match self {
110144
ReturnValueExpr::Traversal(traversal) => write!(f, "{traversal}"),
111145
ReturnValueExpr::Identifier(identifier) => write!(f, "{identifier}"),
112146
ReturnValueExpr::Value(value) => write!(f, "{value}"),
147+
ReturnValueExpr::Array(values) => {
148+
write!(f, "vec![")?;
149+
// if traversal then use the other from functions
150+
for value in values {
151+
write!(f, "ReturnValue::from({value}),")?;
152+
}
153+
write!(f, "]")
154+
}
155+
ReturnValueExpr::Object(values) => {
156+
write!(f, "HashMap::from([")?;
157+
// if traversal then use the other from functions
158+
for (key, value) in values {
159+
write!(f, "(String::from(\"{key}\"), ReturnValue::from({value})),")?;
160+
}
161+
write!(f, "])")
162+
}
113163
}
114164
}
115165
}

helix-db/src/helixc/parser/helix_parser.rs

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ pub struct Query {
411411
pub name: String,
412412
pub parameters: Vec<Parameter>,
413413
pub statements: Vec<Statement>,
414-
pub return_values: Vec<Expression>,
414+
pub return_values: Vec<ReturnType>,
415415
pub loc: Loc,
416416
}
417417

@@ -502,6 +502,15 @@ pub enum ExpressionType {
502502
BM25Search(BM25Search),
503503
Empty,
504504
}
505+
506+
#[derive(Debug, Clone)]
507+
pub enum ReturnType {
508+
Array(Vec<ReturnType>),
509+
Object(HashMap<String, ReturnType>),
510+
Expression(Expression),
511+
Empty,
512+
}
513+
505514
impl Debug for ExpressionType {
506515
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
507516
match self {
@@ -2217,11 +2226,91 @@ impl HelixParser {
22172226
})
22182227
}
22192228

2220-
fn parse_return_statement(&self, pair: Pair<Rule>) -> Result<Vec<Expression>, ParserError> {
2229+
fn parse_return_statement(&self, pair: Pair<Rule>) -> Result<Vec<ReturnType>, ParserError> {
22212230
// println!("pair: {:?}", pair.clone().into_inner());
2231+
let inner = pair.into_inner();
2232+
let mut return_types = Vec::new();
2233+
for pair in inner {
2234+
match pair.as_rule() {
2235+
Rule::array_creation => {
2236+
return_types.push(ReturnType::Array(self.parse_array_creation(pair)?));
2237+
}
2238+
Rule::object_creation => {
2239+
return_types.push(ReturnType::Object(self.parse_object_creation(pair)?));
2240+
}
2241+
Rule::evaluates_to_anything => {
2242+
return_types.push(ReturnType::Expression(self.parse_expression(pair)?));
2243+
}
2244+
_ => {
2245+
return Err(ParserError::from(format!(
2246+
"Unexpected rule in return statement: {:?}",
2247+
pair.as_rule()
2248+
)));
2249+
}
2250+
}
2251+
}
2252+
Ok(return_types)
2253+
}
2254+
2255+
fn parse_array_creation(&self, pair: Pair<Rule>) -> Result<Vec<ReturnType>, ParserError> {
2256+
let pairs = pair.into_inner();
2257+
let mut objects = Vec::new();
2258+
for p in pairs {
2259+
match p.as_rule() {
2260+
Rule::identifier => {
2261+
objects.push(ReturnType::Expression(Expression {
2262+
loc: p.loc(),
2263+
expr: ExpressionType::Identifier(p.as_str().to_string()),
2264+
}));
2265+
}
2266+
_ => {
2267+
objects.push(ReturnType::Object(self.parse_object_creation(p)?));
2268+
}
2269+
}
2270+
}
2271+
Ok(objects)
2272+
}
2273+
2274+
fn parse_object_creation(
2275+
&self,
2276+
pair: Pair<Rule>,
2277+
) -> Result<HashMap<String, ReturnType>, ParserError> {
22222278
pair.into_inner()
2223-
.map(|p| self.parse_expression(p))
2224-
.collect()
2279+
.map(|p| {
2280+
let mut object_inner = p.into_inner();
2281+
let key = object_inner
2282+
.next()
2283+
.ok_or_else(|| ParserError::from("Missing object inner"))?;
2284+
let value = object_inner
2285+
.next()
2286+
.ok_or_else(|| ParserError::from("Missing object inner"))?;
2287+
let value = self.parse_object_inner(value)?;
2288+
Ok((key.as_str().to_string(), value))
2289+
})
2290+
.collect::<Result<HashMap<String, ReturnType>, _>>()
2291+
}
2292+
2293+
fn parse_object_inner(&self, object_field: Pair<Rule>) -> Result<ReturnType, ParserError> {
2294+
let object_field_inner = object_field
2295+
.into_inner()
2296+
.next()
2297+
.ok_or_else(|| ParserError::from("Missing object inner"))?;
2298+
2299+
match object_field_inner.as_rule() {
2300+
Rule::evaluates_to_anything => Ok(ReturnType::Expression(
2301+
self.parse_expression(object_field_inner)?,
2302+
)),
2303+
Rule::object_creation => Ok(ReturnType::Object(
2304+
self.parse_object_creation(object_field_inner)?,
2305+
)),
2306+
Rule::array_creation => Ok(ReturnType::Array(
2307+
self.parse_array_creation(object_field_inner)?,
2308+
)),
2309+
_ => Err(ParserError::from(format!(
2310+
"Unexpected rule in parse_object_inner: {:?}",
2311+
object_field_inner.as_rule()
2312+
))),
2313+
}
22252314
}
22262315

22272316
fn parse_expression_vec(&self, pairs: Pairs<Rule>) -> Result<Vec<Expression>, ParserError> {

0 commit comments

Comments
 (0)