From 49371e3eca2165e9a34ac6bc35a823de111b4798 Mon Sep 17 00:00:00 2001 From: KentoNion Date: Mon, 13 Oct 2025 00:07:06 +0300 Subject: [PATCH] added postgreSQL placeholders support --- batcher/batcher.go | 62 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/batcher/batcher.go b/batcher/batcher.go index c76faa3..48c3dfd 100644 --- a/batcher/batcher.go +++ b/batcher/batcher.go @@ -3,6 +3,7 @@ package batcher import ( "strings" "errors" + "strconv" "btchrr/models" ) @@ -23,7 +24,7 @@ func NewBatcher(batchSize int) (*Batcher, error) { batchSize: batchSize, placeholders: make(map[string]struct{}), } - for _, ph := range []string{"?", "$", ":", ":"} { + for _, ph := range []string{"?", "$", ":"} { b.placeholders[ph] = struct{}{} } return b, nil @@ -36,7 +37,7 @@ func (b *Batcher) BuildBatches(singleQuery string, items []any) ([]models.Batche return []models.BatchedQuery{}, err } - batches, err := b.BuildBatchQuery(singleQuery, b.batchSize, batchedItems) + batches, err := b.BuildBatchQuery(singleQuery, b.batchSize, batchedItems, len(batchedItems)) if err != nil { return []models.BatchedQuery{}, err } @@ -71,7 +72,7 @@ func (b *Batcher) batchItems(items []any) ([][]any, error) { } // BuildBatchQuery - builds a batch query from a single query -func (b *Batcher) BuildBatchQuery(singleQuery string, batchSize int, batchedItems [][]any) (batchedQueries []models.BatchedQuery, err error) { +func (b *Batcher) BuildBatchQuery(singleQuery string, batchSize int, batchedItems [][]any, numOfBatches int) (batchedQueries []models.BatchedQuery, err error) { placeholder, err := b.detectPlaceholders(singleQuery) if err != nil { return []models.BatchedQuery{}, err @@ -79,9 +80,23 @@ func (b *Batcher) BuildBatchQuery(singleQuery string, batchSize int, batchedItem switch placeholder { case "?": - return b.buildSqliteQuery(singleQuery, batchedItems) + for i :=0; i < numOfBatches; i++ { + batchQuery, err := b.buildSqliteQuery(singleQuery, batchedItems[i]) + if err != nil { + return []models.BatchedQuery{}, err + } + batchedQueries = append(batchedQueries, batchQuery) + } + return case "$": - return b.buildPostgresQuery(singleQuery, batchedItems) + for i :=0; i < numOfBatches; i++ { + batchQuery, err := b.buildPostgresQuery(singleQuery, batchedItems[i]) + if err != nil { + return []models.BatchedQuery{}, err + } + batchedQueries = append(batchedQueries, batchQuery) + } + return default: return b.buildQueryWithNamedPlaceholders(singleQuery, placeholder, batchedItems) } @@ -97,7 +112,7 @@ func (b *Batcher) detectPlaceholders(query string) (string, error) { return "", models.ErrCannotDetectPlaceholder } -func (b *Batcher) buildSqliteQuery(singleQuery string, batchedItems [][]any) (batchedQueries models.BatchedQuery, err error) { +func (b *Batcher) buildSqliteQuery(singleQuery string, batchedItems []any) (batchedQueries models.BatchedQuery, err error) { // INSERT INTO users VALUES (?, ?); idx := strings.Index(strings.ToLower(singleQuery), "values") if idx == -1 { @@ -121,8 +136,39 @@ func (b *Batcher) buildSqliteQuery(singleQuery string, batchedItems [][]any) (ba return models.BatchedQuery(newQuery), nil } -func (b *Batcher) buildPostgresQuery(singleQuery string, batchedItems [][]any) (batchedQueries []models.BatchedQuery, err error) { - return []models.BatchedQuery{}, errors.New("not implemented") +func (b *Batcher) buildPostgresQuery(singleQuery string, batchedItems []any) (batchedQueries models.BatchedQuery, err error) { + // INSERT INTO users VALUES ($1, $2); + idx := strings.Index(strings.ToLower(singleQuery), "values") + if idx == -1 { + return "", errors.New("no values found in query") + } + + prefix := singleQuery[:idx+6] // +6 - values + valuesPart := singleQuery[idx+6:] + + numOfInserts := strings.Count(valuesPart, "$") + if numOfInserts == 0 { + return "", errors.New("no placeholders found in query") + } + + //INSERT INTO users VALUES ($1, $2), ($3, $4), ($5, $6); + placeholderNum := 1 + query := "" + for i := 0; i < b.batchSize ; i++ { + if i > 0 { + query += ", " + } + query += "(" + for j := 0; j < numOfInserts; j++ { + query += "$" + strconv.Itoa(placeholderNum) + ", " + placeholderNum++ + } + query += ")" + } + + query = prefix + " " + query + ";" + + return models.BatchedQuery(query), nil } func (b *Batcher) buildQueryWithNamedPlaceholders(singleQuery string, placeholder string, batchedItems [][]any) (batchedQueries []models.BatchedQuery, err error) {