Skip to content

Commit 02c67a9

Browse files
committed
Add some godocs
1 parent 1a0adaa commit 02c67a9

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

dbutil/massinsert.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ import (
1212
"strings"
1313
)
1414

15+
// Array is an interface for small fixed-size arrays.
16+
// It exists because generics can't specify array sizes: https://github.com/golang/go/issues/44253
1517
type Array interface {
1618
[1]any | [2]any | [3]any | [4]any | [5]any | [6]any | [7]any | [8]any | [9]any | [10]any | [11]any | [12]any | [13]any | [14]any | [15]any | [16]any | [17]any | [18]any | [19]any | [20]any
1719
}
1820

21+
// MassInsertable represents a struct that contains dynamic values for a mass insert query.
1922
type MassInsertable[T Array] interface {
2023
GetMassInsertValues() T
2124
}
@@ -25,6 +28,48 @@ type MassInsertBuilder[Item MassInsertable[DynamicParams], StaticParams Array, D
2528
placeholderTemplate string
2629
}
2730

31+
// NewMassInsertBuilder creates a new MassInsertBuilder that can build mass insert database queries.
32+
//
33+
// Parameters in mass insert queries are split into two types: static parameters
34+
// and dynamic parameters. Static parameters are the same for all items being
35+
// inserted, while dynamic parameters are different for each item.
36+
//
37+
// The given query should be a normal INSERT query for a single row. It can also
38+
// have ON CONFLICT clauses, as long as the clause uses `excluded` instead of
39+
// positional parameters.
40+
//
41+
// The placeholder template is used to replace the `VALUES` part of the given
42+
// query. It should contain a positional placeholder ($1, $2, ...) for each
43+
// static placeholder, and a fmt directive (`$%d`) for each dynamic placeholder.
44+
//
45+
// The given query and placeholder template are validated here and the function
46+
// will panic if they're invalid (e.g. if the `VALUES` part of the insert query
47+
// can't be found, or if the placeholder template doesn't have the right things).
48+
// The idea is to use this function to populate a global variable with the mass
49+
// insert builder, so the panic will happen at startup if the query or
50+
// placeholder template are invalid (instead of returning an error when trying
51+
// to use the query later).
52+
//
53+
// Example:
54+
//
55+
// type Message struct {
56+
// ChatID int
57+
// RemoteID string
58+
// MXID id.EventID
59+
// Timestamp time.Time
60+
// }
61+
//
62+
// func (msg *Message) GetMassInsertValues() [3]any {
63+
// return [3]any{msg.RemoteID, msg.MXID, msg.Timestamp.UnixMilli()}
64+
// }
65+
//
66+
// const insertMessageQuery = `INSERT INTO message (chat_id, remote_id, mxid, timestamp) VALUES ($1, $2, $3, $4)`
67+
// var massInsertMessageBuilder = dbutil.NewMassInsertBuilder[Message, [2]any](insertMessageQuery, "($1, $%d, $%d, $%d, $%d)")
68+
//
69+
// func DoMassInsert(ctx context.Context, messages []*Message) error {
70+
// query, params := massInsertMessageBuilder.Build([1]any{messages[0].ChatID}, messages)
71+
// return db.Exec(ctx, query, params...)
72+
// }
2873
func NewMassInsertBuilder[Item MassInsertable[DynamicParams], StaticParams Array, DynamicParams Array](
2974
singleInsertQuery, placeholderTemplate string,
3075
) *MassInsertBuilder[Item, StaticParams, DynamicParams] {

0 commit comments

Comments
 (0)