Skip to content
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
43 changes: 35 additions & 8 deletions prqlc/prqlc/src/semantic/resolver/transforms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,18 +303,45 @@ impl Resolver<'_> {
.with_span(pattern.span));
}

"tuple_every" => {
"tuple_reduce" => {
// yes, this is not a transform, but this is the most appropriate place for it

let [list] = unpack::<1>(func.args);
let list = list.kind.into_tuple().unwrap();
let [init, func, list] = unpack::<3>(func.args);
let list_items = list.kind.into_tuple().unwrap();
let num_items = list_items.len();
let mut list_iter = list_items.into_iter();

let mut res = init.clone();

if let ExprKind::Literal(Literal::String(init_val)) = &init.kind {
if init_val == "__missing" {
match num_items {
0 => return Err(Error::new(Reason::Expected {
who: Some("tuple".to_string()),
expected:
"to have at least one entry when initial value is not provided"
.to_string(),
found: "empty tuple".to_string(),
})
.with_span(list.span)
.push_hint("try adding an initial:<value> parameter")),
1 => {
let item = list_iter.next().unwrap();
return Ok(item);
}
_ => {
res = list_iter.next().unwrap();
}
}
}
}

let mut res = None;
for item in list {
res = maybe_binop(res, &["std", "and"], Some(item));
for item in list_iter {
res = self.fold_expr(Expr::new(ExprKind::FuncCall(FuncCall::new_simple(
func.clone(),
vec![res, item],
))))?;
}
let res =
res.unwrap_or_else(|| Expr::new(ExprKind::Literal(Literal::Boolean(true))));

return Ok(res);
}
Expand Down
8 changes: 4 additions & 4 deletions prqlc/prqlc/src/semantic/std.prql
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,13 @@ let window = func
let append = `default_db.bottom`<relation> top<relation> -> <relation> internal append
let intersect = `default_db.bottom`<relation> top<relation> -> <relation> (
t = top
join (b = bottom) (tuple_every (tuple_map _eq (tuple_zip t.* b.*)))
join (b = bottom) (tuple_reduce std.and (tuple_map _eq (tuple_zip t.* b.*)))
select t.*
)
let remove = `default_db.bottom`<relation> top<relation> -> <relation> (
t = top
join side:left (b = bottom) (tuple_every (tuple_map _eq (tuple_zip t.* b.*)))
filter (tuple_every (tuple_map _is_null b.*))
join side:left (b = bottom) (tuple_reduce std.and (tuple_map _eq (tuple_zip t.* b.*)))
filter (tuple_reduce std.and (tuple_map _is_null b.*))
select t.*
)
let loop = func
Expand Down Expand Up @@ -199,7 +199,7 @@ let as = `noresolve.type` column -> internal std.as
let in = pattern value -> <bool> internal in

## Tuple functions
let tuple_every = func list -> <bool> internal tuple_every
let tuple_reduce = func initial:"__missing" fn <func> list -> internal tuple_reduce
let tuple_map = func fn <func> list -> internal tuple_map
let tuple_zip = func a b -> internal tuple_zip
let _eq = func a -> internal _eq
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ frames:
table:
- default_db
- _literal_127
- - 0:3163-3240
- - 0:3172-3258
- columns:
- !Single
name:
Expand All @@ -43,7 +43,7 @@ frames:
table:
- default_db
- _literal_122
- - 0:3243-3288
- - 0:3261-3315
- columns:
- !Single
name:
Expand Down Expand Up @@ -74,7 +74,7 @@ frames:
name:
- t
- a
target_id: 207
target_id: 213
target_name: null
inputs:
- id: 127
Expand All @@ -93,7 +93,7 @@ frames:
name:
- t
- a
target_id: 207
target_id: 213
target_name: null
inputs:
- id: 127
Expand All @@ -110,7 +110,7 @@ nodes:
- id: 122
kind: Array
span: 1:173-237
parent: 189
parent: 192
- id: 127
kind: Array
span: 1:36-55
Expand All @@ -135,105 +135,105 @@ nodes:
children:
- 127
- 155
parent: 189
parent: 192
- id: 155
kind: Literal
parent: 154
- id: 178
- id: 181
kind: Ident
ident: !Ident
- this
- t
- a
targets:
- 136
- id: 181
- id: 184
kind: Ident
ident: !Ident
- that
- b
- a
targets:
- 122
- id: 187
- id: 190
kind: RqOperator
span: 0:3192-3239
span: 0:3201-3257
targets:
- 178
- 181
parent: 189
- id: 189
- 184
parent: 192
- id: 192
kind: 'TransformCall: Join'
span: 0:3163-3240
span: 0:3172-3258
children:
- 154
- 122
- 187
parent: 205
- id: 197
- 190
parent: 211
- id: 203
kind: Ident
span: 0:5981-5989
span: 0:6033-6041
ident: !Ident
- this
- b
- a
targets:
- 122
- id: 201
- id: 207
kind: RqOperator
span: 0:3251-3287
span: 0:3269-3314
targets:
- 197
- 204
parent: 205
- id: 204
- 203
- 210
parent: 211
- id: 210
kind: Literal
span: 0:5993-5997
- id: 205
span: 0:6045-6049
- id: 211
kind: 'TransformCall: Filter'
span: 0:3243-3288
span: 0:3261-3315
children:
- 189
- 201
parent: 209
- id: 207
- 192
- 207
parent: 215
- id: 213
kind: Ident
ident: !Ident
- this
- t
- a
targets:
- 136
parent: 208
- id: 208
parent: 214
- id: 214
kind: Tuple
span: 0:3298-3301
span: 0:3325-3328
children:
- 207
parent: 209
- id: 209
- 213
parent: 215
- id: 215
kind: 'TransformCall: Select'
span: 1:165-238
children:
- 205
- 208
parent: 212
- id: 210
- 211
- 214
parent: 218
- id: 216
kind: Ident
span: 1:244-245
ident: !Ident
- this
- t
- a
targets:
- 207
parent: 212
- id: 212
- 213
parent: 218
- id: 218
kind: 'TransformCall: Sort'
span: 1:239-245
children:
- 209
- 210
- 215
- 216
ast:
name: Project
stmts:
Expand Down
48 changes: 48 additions & 0 deletions prqlc/prqlc/tests/integration/sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6230,6 +6230,54 @@ fn test_import() {
");
}

#[test]
fn test_tuple_reduce() {
assert_snapshot!(compile(
r###"
from foo
select {
with_initial = tuple_reduce initial:4 add {1, 2, 3},
with_initial_one = tuple_reduce initial:4 add {3},
with_initial_zero = tuple_reduce initial:4 add {},
no_initial = tuple_reduce add {1, 2, 3},
no_initial_one = tuple_reduce add {3},
}
"###,
)
.unwrap(), @"
SELECT
4 + 1 + 2 + 3 AS with_initial,
4 + 3 AS with_initial_one,
4 AS with_initial_zero,
1 + 2 + 3 AS no_initial,
3 AS no_initial_one
FROM
foo
");
}

#[test]
fn test_tuple_reduce_err() {
assert_snapshot!(compile(
r###"
from foo
select {
no_initial_err = tuple_reduce add {}
}
"###,
).unwrap_err(), @r###"
Error:
╭─[ :4:37 ]
4 │ no_initial_err = tuple_reduce add {}
│ ─┬
│ ╰── tuple expected to have at least one entry when initial value is not provided, but found empty tuple
│ Help: try adding an initial:<value> parameter
───╯
"###);
}

#[test]
fn unstable_ordering() {
// https://github.com/PRQL/prql/issues/5053
Expand Down
Loading