02.11.2025

This commit is contained in:
2025-11-02 19:55:58 +03:00
parent 49371e3eca
commit 9c204a9554
4 changed files with 50 additions and 28 deletions

View File

@@ -1,9 +1,9 @@
package batcher package batcher
import ( import (
"strings"
"errors" "errors"
"strconv" "strconv"
"strings"
"btchrr/models" "btchrr/models"
) )
@@ -80,25 +80,33 @@ func (b *Batcher) BuildBatchQuery(singleQuery string, batchSize int, batchedItem
switch placeholder { switch placeholder {
case "?": case "?":
for i :=0; i < numOfBatches; i++ { for i := 0; i < numOfBatches; i++ {
batchQuery, err := b.buildSqliteQuery(singleQuery, batchedItems[i]) batchQuery, err := b.buildSqliteQuery(singleQuery)
if err != nil { if err != nil {
return []models.BatchedQuery{}, err return []models.BatchedQuery{}, err
} }
batchQuery.Items = batchedItems[i]
batchedQueries = append(batchedQueries, batchQuery) batchedQueries = append(batchedQueries, batchQuery)
} }
return return
case "$": case "$":
for i :=0; i < numOfBatches; i++ { for i := 0; i < numOfBatches; i++ {
batchQuery, err := b.buildPostgresQuery(singleQuery, batchedItems[i]) batchQuery, err := b.buildPostgresQuery(singleQuery)
if err != nil { if err != nil {
return []models.BatchedQuery{}, err return []models.BatchedQuery{}, err
} }
batchQuery.Items = batchedItems[i]
batchedQueries = append(batchedQueries, batchQuery) batchedQueries = append(batchedQueries, batchQuery)
} }
return return
case ":":
batchedQueries, err = b.buildQueryWithNamedPlaceholders(singleQuery)
if err != nil {
return []models.BatchedQuery{}, err
}
return
default: default:
return b.buildQueryWithNamedPlaceholders(singleQuery, placeholder, batchedItems) return []models.BatchedQuery{}, errors.New("unknown placeholder")
} }
} }
@@ -112,11 +120,12 @@ func (b *Batcher) detectPlaceholders(query string) (string, error) {
return "", models.ErrCannotDetectPlaceholder return "", models.ErrCannotDetectPlaceholder
} }
func (b *Batcher) buildSqliteQuery(singleQuery string, batchedItems []any) (batchedQueries models.BatchedQuery, err error) { // buildSqliteQuery - builds a batch query with sqlite placeholders
func (b *Batcher) buildSqliteQuery(singleQuery string) (batchedQuery models.BatchedQuery, err error) {
// INSERT INTO users VALUES (?, ?); // INSERT INTO users VALUES (?, ?);
idx := strings.Index(strings.ToLower(singleQuery), "values") idx := strings.Index(strings.ToLower(singleQuery), "values")
if idx == -1 { if idx == -1 {
return "", errors.New("no values found in query") return models.BatchedQuery{}, errors.New("no values found in query")
} }
prefix := singleQuery[:idx+6] // +6 - values prefix := singleQuery[:idx+6] // +6 - values
@@ -124,23 +133,23 @@ func (b *Batcher) buildSqliteQuery(singleQuery string, batchedItems []any) (batc
numOfInserts := strings.Count(valuesPart, "?") numOfInserts := strings.Count(valuesPart, "?")
if numOfInserts == 0 { if numOfInserts == 0 {
return "", errors.New("no placeholders found in query") return models.BatchedQuery{}, errors.New("no placeholders found in query")
} }
singleItemValues := "(" + strings.Repeat("?, ", numOfInserts - 1) + "?)" singleItemValues := "(" + strings.Repeat("?, ", numOfInserts-1) + "?)"
//INSERT INTO users (name, age) VALUES (?, ?), (?, ?), (?, ?); //INSERT INTO users (name, age) VALUES (?, ?), (?, ?), (?, ?);
newValues := strings.Repeat(singleItemValues + ", ", b.batchSize - 1) + singleItemValues newValues := strings.Repeat(singleItemValues+", ", b.batchSize-1) + singleItemValues
newQuery := prefix + " " + newValues + ";" batchedQuery.Query = prefix + " " + newValues + ";"
return
return models.BatchedQuery(newQuery), nil
} }
func (b *Batcher) buildPostgresQuery(singleQuery string, batchedItems []any) (batchedQueries models.BatchedQuery, err error) { // buildPostgresQuery - builds a batch query with postgres placeholders
func (b *Batcher) buildPostgresQuery(singleQuery string) (batchedQuery models.BatchedQuery, err error) {
// INSERT INTO users VALUES ($1, $2); // INSERT INTO users VALUES ($1, $2);
idx := strings.Index(strings.ToLower(singleQuery), "values") idx := strings.Index(strings.ToLower(singleQuery), "values")
if idx == -1 { if idx == -1 {
return "", errors.New("no values found in query") return models.BatchedQuery{}, errors.New("no values found in query")
} }
prefix := singleQuery[:idx+6] // +6 - values prefix := singleQuery[:idx+6] // +6 - values
@@ -148,13 +157,13 @@ func (b *Batcher) buildPostgresQuery(singleQuery string, batchedItems []any) (ba
numOfInserts := strings.Count(valuesPart, "$") numOfInserts := strings.Count(valuesPart, "$")
if numOfInserts == 0 { if numOfInserts == 0 {
return "", errors.New("no placeholders found in query") return models.BatchedQuery{}, errors.New("no placeholders found in query")
} }
//INSERT INTO users VALUES ($1, $2), ($3, $4), ($5, $6); //INSERT INTO users VALUES ($1, $2), ($3, $4), ($5, $6);
placeholderNum := 1 placeholderNum := 1
query := "" query := ""
for i := 0; i < b.batchSize ; i++ { for i := 0; i < b.batchSize; i++ {
if i > 0 { if i > 0 {
query += ", " query += ", "
} }
@@ -166,11 +175,22 @@ func (b *Batcher) buildPostgresQuery(singleQuery string, batchedItems []any) (ba
query += ")" query += ")"
} }
query = prefix + " " + query + ";" batchedQuery.Query = prefix + " " + query + ";"
return models.BatchedQuery(query), nil return
} }
func (b *Batcher) buildQueryWithNamedPlaceholders(singleQuery string, placeholder string, batchedItems [][]any) (batchedQueries []models.BatchedQuery, err error) { // buildQueryWithNamedPlaceholders - builds a batch query with named placeholders
return []models.BatchedQuery{}, errors.New("not implemented") func (b *Batcher) buildQueryWithNamedPlaceholders(singleQuery string) (batchedQuery models.BatchedQuery, err error) {
// INSERT INTO users (name, age) VALUES (:name, :age);
idx := strings.Index(strings.ToLower(singleQuery), "values")
if idx == -1 {
return models.BatchedQuery{}, errors.New("no values found in query")
}
prefix := singleQuery[:idx+6] // +6 - values
valuesPart := singleQuery[idx+6:]
return
} }

View File

@@ -52,7 +52,7 @@ func NewBtchrr(batchSize int, db *sql.DB) (*Btchrr, error) {
} }
// Exec - accepts a query for single item, items and executes it in batches // Exec - accepts a query for single item, items and executes it in batches
func (b *Btchrr) Exec(ctx context.Context, query string, items []any) (sql.Result, error) { func (b *Btchrr) ExecWitchContext(ctx context.Context, query string, items []any) (sql.Result, error) {
err := b.executor.CheckQuery(query) err := b.executor.CheckQuery(query)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -16,8 +16,7 @@ func NewSQLAdapter(db *sql.DB) *DBAdapter {
} }
func (a *DBAdapter) Exec(ctx context.Context, batchedQuery models.BatchedQuery) (sql.Result, error) { func (a *DBAdapter) Exec(ctx context.Context, batchedQuery models.BatchedQuery) (sql.Result, error) {
res, err := a.db.ExecContext(ctx, string(batchedQuery)) res, err := a.db.ExecContext(ctx, batchedQuery.Query, batchedQuery.Items...)
return res, err return res, err
} }

View File

@@ -9,4 +9,7 @@ var (
) )
// BatchedQuery - single batch query // BatchedQuery - single batch query
type BatchedQuery string type BatchedQuery struct {
Query string
Items []any
}