Implement ON CONFLICT and RETURNING (#666)

* Implement RETURNING on INSERT/UPDATE/DELETE

* Implement INSERT ... ON CONFLICT

* Fix tests

* cargo fmt

* tests: on conflict and returning

Co-authored-by: gamife <gamife9886@gmail.com>
This commit is contained in:
main() 2022-11-11 22:15:31 +01:00 committed by GitHub
parent ae1c69034e
commit 814367a6ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 250 additions and 8 deletions

View file

@ -564,6 +564,7 @@ fn parse_update_set_from() {
Ident::new("id")
])),
}),
returning: None,
}
);
}
@ -1177,6 +1178,143 @@ fn parse_prepare() {
);
}
#[test]
fn parse_pg_on_conflict() {
let stmt = pg_and_generic().verified_stmt(
"INSERT INTO distributors (did, dname) \
VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc') \
ON CONFLICT(did) \
DO UPDATE SET dname = EXCLUDED.dname",
);
match stmt {
Statement::Insert {
on:
Some(OnInsert::OnConflict(OnConflict {
conflict_target,
action,
})),
..
} => {
assert_eq!(vec![Ident::from("did")], conflict_target);
assert_eq!(
OnConflictAction::DoUpdate(vec![Assignment {
id: vec!["dname".into()],
value: Expr::CompoundIdentifier(vec!["EXCLUDED".into(), "dname".into()])
},]),
action
);
}
_ => unreachable!(),
};
let stmt = pg_and_generic().verified_stmt(
"INSERT INTO distributors (did, dname, area) \
VALUES (5, 'Gizmo Transglobal', 'Mars'), (6, 'Associated Computing, Inc', 'Venus') \
ON CONFLICT(did, area) \
DO UPDATE SET dname = EXCLUDED.dname, area = EXCLUDED.area",
);
match stmt {
Statement::Insert {
on:
Some(OnInsert::OnConflict(OnConflict {
conflict_target,
action,
})),
..
} => {
assert_eq!(
vec![Ident::from("did"), Ident::from("area"),],
conflict_target
);
assert_eq!(
OnConflictAction::DoUpdate(vec![
Assignment {
id: vec!["dname".into()],
value: Expr::CompoundIdentifier(vec!["EXCLUDED".into(), "dname".into()])
},
Assignment {
id: vec!["area".into()],
value: Expr::CompoundIdentifier(vec!["EXCLUDED".into(), "area".into()])
},
]),
action
);
}
_ => unreachable!(),
};
let stmt = pg_and_generic().verified_stmt(
"INSERT INTO distributors (did, dname) \
VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc') \
ON CONFLICT DO NOTHING",
);
match stmt {
Statement::Insert {
on:
Some(OnInsert::OnConflict(OnConflict {
conflict_target,
action,
})),
..
} => {
assert_eq!(Vec::<Ident>::new(), conflict_target);
assert_eq!(OnConflictAction::DoNothing, action);
}
_ => unreachable!(),
};
}
#[test]
fn parse_pg_returning() {
let stmt = pg_and_generic().verified_stmt(
"INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets') RETURNING did",
);
match stmt {
Statement::Insert { returning, .. } => {
assert_eq!(
Some(vec![SelectItem::UnnamedExpr(Expr::Identifier(
"did".into()
)),]),
returning
);
}
_ => unreachable!(),
};
let stmt = pg_and_generic().verified_stmt(
"UPDATE weather SET temp_lo = temp_lo + 1, temp_hi = temp_lo + 15, prcp = DEFAULT \
WHERE city = 'San Francisco' AND date = '2003-07-03' \
RETURNING temp_lo AS lo, temp_hi AS hi, prcp",
);
match stmt {
Statement::Update { returning, .. } => {
assert_eq!(
Some(vec![
SelectItem::ExprWithAlias {
expr: Expr::Identifier("temp_lo".into()),
alias: "lo".into()
},
SelectItem::ExprWithAlias {
expr: Expr::Identifier("temp_hi".into()),
alias: "hi".into()
},
SelectItem::UnnamedExpr(Expr::Identifier("prcp".into())),
]),
returning
);
}
_ => unreachable!(),
};
let stmt =
pg_and_generic().verified_stmt("DELETE FROM tasks WHERE status = 'DONE' RETURNING *");
match stmt {
Statement::Delete { returning, .. } => {
assert_eq!(Some(vec![SelectItem::Wildcard,]), returning);
}
_ => unreachable!(),
};
}
#[test]
fn parse_pg_bitwise_binary_ops() {
let bitwise_ops = &[