-
-
Notifications
You must be signed in to change notification settings - Fork 225
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
feat: mssql and pg merge query #723
Conversation
Thanks! This looks pretty good already and is rather important given that Postgres 15 also has support for MERGE statements. Could you try to add some tests to |
I guess in future we may want to extend the API to something like this and try to make it work the same in different RDMS: db.NewMerge().
WhenUpdate("MATCHED", func(q *bun.UpdateQuery) *bun.UpdateQuery {
return q.Set("models.value = _data.value")
}).
WhenInsert("NOT MATCHED", func(q *bun.InsertQuery) *bun.InsertQuery {
return q.Column("name", "value")
}).
WhenDelete("...") @bgdnxt Have you considered that already by any chance? |
haven't look into pg15 yet, will try tomorrow. |
the merge query syntax between MSSQL and PG are very similar. so it is easy to add supported. |
The update/insert query within when clause are quit different from original. could not benefit from applying a full update/inert query statement. so i just pull out the now the merge query could be use as: db.NewMerge().
Model(&Model{}).
With("_data", DBM.NewValues(&newModels)).
Using("_data").
On("?TableAlias.name = _data.name").
WhenUpdate("MATCHED", func(q *bun.MergeQuery) *bun.MergeQuery {
return q.Set("value = _data.value")
}).
WhenInsert("NOT MATCHED", func(q *bun.MergeQuery) *bun.MergeQuery {
return q.Value("name", "_data.name").Value("value", "_data.value")
}).
Returning("$action") and i still keep the func db.NewMerge().
Model(&Model{}).
With("_data", DBM.NewValues(&newModels)).
Using("_data").
On("?TableAlias.name = _data.name").
WhenDelete("MATCHED").
WhenExpr("NOT MATCHED THEN INSERT (name, value) VALUES (_data.name, _data.value)").
Returning("$action")
|
Agreed. I would even keep the old name
Yes, but we don't have to support all options from those queries. Just use the fields you need, .e.g. The problem with current implementation is that you can't have multiple WhenInsert("NOT MATCHED AND cond1", func(q *bun.MergeQuery) *bun.MergeQuery {
return q.Value("name", "_data.name").Value("value", "_data.value")
}).
WhenInsert("NOT MATCHED AND cond2", func(q *bun.MergeQuery) *bun.MergeQuery {
return q.Value("name", "_data.name").Value("value", "_data.value")
}). Also the order of I suggest to try something like this: type MergeQuery struct {
...
when []schema.QueryAppender
}
func (q *MergeQuery) When(query string, args ...interface{}) *MergeQuery {
q.when = append(q.when, schema.SafeQuery(query, args))
return q
}
func (q *MergeQuery) WhenInsert(query string, cb func (q *InsertQuery) *InsertQuery) *MergeQuery {
q.when = append(q.when, whenInsert{query: query, cb: cb})
return q
} Then implement |
@vmihailenco thanks for the feedback, now the code it more clean. |
} | ||
|
||
// WhenUpdate for when update clause | ||
func (q *MergeQuery) WhenUpdate(expr string, fn func(q *UpdateQuery) *UpdateQuery) *MergeQuery { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we can also accept args ...interface{}
as the last argument? It is a bit awkward, but would allow something like:
q.WhenInsert("MATCHED AND foo = ?", func() {...}, 123)
@bgdnxt excellent, thank you! |
closed #428