mirror of
https://github.com/harness/drone.git
synced 2025-05-17 01:20:13 +08:00
fix: [AH-674]: support upstream proxies at org/acct, multiple levels (#3055)
* fix: [AH-674]: support upstream proxies at org/acct, multiple levels. change the default to false:non-recursive * fix: [AH-674]: support upstream proxies at org/acct, multiple levels. add a flag in API for recursive or non-recursive * fix: [AH-674]: support upstream proxies at org/acct, multiple levels. combine recursive and non-recursive for better maintance, optimze quries * fix: [AH-674]: support upstream proxies at org/acct, multiple levels * fix: [AH-674]: support upstream proxies at org/acct, multiple levels
This commit is contained in:
parent
f0d58cdda7
commit
facd2431a3
@ -27,7 +27,7 @@ import (
|
|||||||
"github.com/harness/gitness/registry/app/storage"
|
"github.com/harness/gitness/registry/app/storage"
|
||||||
"github.com/harness/gitness/registry/types"
|
"github.com/harness/gitness/registry/types"
|
||||||
|
|
||||||
"github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -58,6 +58,7 @@ type RegistryRequestInfo struct {
|
|||||||
searchTerm string
|
searchTerm string
|
||||||
labels []string
|
labels []string
|
||||||
registryIDs []string
|
registryIDs []string
|
||||||
|
recursive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegistryRequestParams struct {
|
type RegistryRequestParams struct {
|
||||||
@ -72,6 +73,7 @@ type RegistryRequestParams struct {
|
|||||||
sortOrder *api.SortOrder
|
sortOrder *api.SortOrder
|
||||||
sortField *api.SortField
|
sortField *api.SortField
|
||||||
registryIDsParam *api.RegistryIdentifierParam
|
registryIDsParam *api.RegistryIdentifierParam
|
||||||
|
recursive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRegistryRequestBaseInfo returns the base info for the registry request
|
// GetRegistryRequestBaseInfo returns the base info for the registry request
|
||||||
@ -186,6 +188,7 @@ func (c *APIController) GetRegistryRequestInfo(
|
|||||||
searchTerm: searchTerm,
|
searchTerm: searchTerm,
|
||||||
labels: labels,
|
labels: labels,
|
||||||
registryIDs: registryIDs,
|
registryIDs: registryIDs,
|
||||||
|
recursive: registryRequestParams.recursive,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ func (c *APIController) GetAllRegistries(
|
|||||||
sortOrder: r.Params.SortOrder,
|
sortOrder: r.Params.SortOrder,
|
||||||
sortField: r.Params.SortField,
|
sortField: r.Params.SortField,
|
||||||
registryIDsParam: nil,
|
registryIDsParam: nil,
|
||||||
|
recursive: r.Params.Recursive != nil && bool(*r.Params.Recursive), // default is false
|
||||||
}
|
}
|
||||||
regInfo, _ := c.GetRegistryRequestInfo(ctx, *registryRequestParams)
|
regInfo, _ := c.GetRegistryRequestInfo(ctx, *registryRequestParams)
|
||||||
|
|
||||||
@ -97,6 +98,7 @@ func (c *APIController) GetAllRegistries(
|
|||||||
regInfo.offset,
|
regInfo.offset,
|
||||||
regInfo.searchTerm,
|
regInfo.searchTerm,
|
||||||
repoType,
|
repoType,
|
||||||
|
regInfo.recursive,
|
||||||
)
|
)
|
||||||
count, _ = c.RegistryRepository.CountAll(
|
count, _ = c.RegistryRepository.CountAll(
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -38,6 +38,7 @@ paths:
|
|||||||
- $ref: "#/components/parameters/sortOrder"
|
- $ref: "#/components/parameters/sortOrder"
|
||||||
- $ref: "#/components/parameters/sortField"
|
- $ref: "#/components/parameters/sortField"
|
||||||
- $ref: "#/components/parameters/searchTerm"
|
- $ref: "#/components/parameters/searchTerm"
|
||||||
|
- $ref: "#/components/parameters/recursiveParam"
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: "#/components/responses/ListRegistryResponse"
|
$ref: "#/components/responses/ListRegistryResponse"
|
||||||
@ -1661,6 +1662,14 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
recursiveParam:
|
||||||
|
name: recursive
|
||||||
|
in: query
|
||||||
|
description: Whether to list registries recursively.
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
spaceRefPathParam:
|
spaceRefPathParam:
|
||||||
name: space_ref
|
name: space_ref
|
||||||
in: path
|
in: path
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Package artifact provides primitives to interact with the openapi HTTP API.
|
// Package artifact provides primitives to interact with the openapi HTTP API.
|
||||||
//
|
//
|
||||||
// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.1.0 DO NOT EDIT.
|
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT.
|
||||||
package artifact
|
package artifact
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -1435,6 +1435,14 @@ func (siw *ServerInterfaceWrapper) GetAllRegistries(w http.ResponseWriter, r *ht
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------- Optional query parameter "recursive" -------------
|
||||||
|
|
||||||
|
err = runtime.BindQueryParameter("form", true, false, "recursive", r.URL.Query(), ¶ms.Recursive)
|
||||||
|
if err != nil {
|
||||||
|
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "recursive", Err: err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
siw.Handler.GetAllRegistries(w, r, spaceRef, params)
|
siw.Handler.GetAllRegistries(w, r, spaceRef, params)
|
||||||
}))
|
}))
|
||||||
@ -4171,71 +4179,73 @@ func (sh *strictHandler) GetAllRegistries(w http.ResponseWriter, r *http.Request
|
|||||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||||
var swaggerSpec = []string{
|
var swaggerSpec = []string{
|
||||||
|
|
||||||
"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",
|
||||||
|
"2HfKFt6eAAA=",
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSwagger returns the content of the embedded swagger specification file
|
// GetSwagger returns the content of the embedded swagger specification file
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Package artifact provides primitives to interact with the openapi HTTP API.
|
// Package artifact provides primitives to interact with the openapi HTTP API.
|
||||||
//
|
//
|
||||||
// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.1.0 DO NOT EDIT.
|
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT.
|
||||||
package artifact
|
package artifact
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -494,6 +494,9 @@ type PageNumber int64
|
|||||||
// PageSize defines model for pageSize.
|
// PageSize defines model for pageSize.
|
||||||
type PageSize int64
|
type PageSize int64
|
||||||
|
|
||||||
|
// RecursiveParam defines model for recursiveParam.
|
||||||
|
type RecursiveParam bool
|
||||||
|
|
||||||
// RegistryRefPathParam defines model for registryRefPathParam.
|
// RegistryRefPathParam defines model for registryRefPathParam.
|
||||||
type RegistryRefPathParam string
|
type RegistryRefPathParam string
|
||||||
|
|
||||||
@ -855,6 +858,9 @@ type GetAllRegistriesParams struct {
|
|||||||
|
|
||||||
// SearchTerm search Term.
|
// SearchTerm search Term.
|
||||||
SearchTerm *SearchTerm `form:"search_term,omitempty" json:"search_term,omitempty"`
|
SearchTerm *SearchTerm `form:"search_term,omitempty" json:"search_term,omitempty"`
|
||||||
|
|
||||||
|
// Recursive Whether to list registries recursively.
|
||||||
|
Recursive *RecursiveParam `form:"recursive,omitempty" json:"recursive,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllRegistriesParamsType defines parameters for GetAllRegistries.
|
// GetAllRegistriesParamsType defines parameters for GetAllRegistries.
|
||||||
|
@ -366,6 +366,7 @@ type RegistryRepository interface {
|
|||||||
offset int,
|
offset int,
|
||||||
search string,
|
search string,
|
||||||
repoType string,
|
repoType string,
|
||||||
|
recursive bool,
|
||||||
) (repos *[]RegistryMetadata, err error)
|
) (repos *[]RegistryMetadata, err error)
|
||||||
|
|
||||||
CountAll(
|
CountAll(
|
||||||
|
@ -33,6 +33,7 @@ import (
|
|||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type registryDao struct {
|
type registryDao struct {
|
||||||
@ -231,66 +232,160 @@ func (r registryDao) GetAll(
|
|||||||
offset int,
|
offset int,
|
||||||
search string,
|
search string,
|
||||||
repoType string,
|
repoType string,
|
||||||
|
recursive bool,
|
||||||
) (repos *[]store.RegistryMetadata, err error) {
|
) (repos *[]store.RegistryMetadata, err error) {
|
||||||
q := databaseg.Builder.Select(
|
// Select only required fields
|
||||||
"r.registry_name as reg_identifier,"+
|
selectFields := `
|
||||||
" r.registry_description as description , "+
|
r.registry_name AS reg_identifier,
|
||||||
"r.registry_package_type as package_type, r.registry_type as type, r.registry_updated_at as last_modified,"+
|
COALESCE(r.registry_description, '') AS description,
|
||||||
" u.upstream_proxy_config_url as url, COALESCE(t2.artifact_count,0) as artifact_count, "+
|
r.registry_package_type AS package_type,
|
||||||
"COALESCE(t3.size,0) as size , r.registry_labels, COALESCE(t4.download_count,0) as download_count ",
|
r.registry_type AS type,
|
||||||
).
|
r.registry_updated_at AS last_modified,
|
||||||
|
COALESCE(u.upstream_proxy_config_url, '') AS url,
|
||||||
|
COALESCE(artifact_count.count, 0) AS artifact_count,
|
||||||
|
COALESCE(blob_sizes.total_size, 0) AS size,
|
||||||
|
r.registry_labels,
|
||||||
|
COALESCE(download_stats.download_count, 0) AS download_count
|
||||||
|
`
|
||||||
|
|
||||||
|
// Subqueries with optimizations for reduced joins and grouping
|
||||||
|
artifactCountSubquery := `
|
||||||
|
SELECT image_registry_id, COUNT(image_id) AS count
|
||||||
|
FROM images
|
||||||
|
WHERE image_enabled = TRUE
|
||||||
|
GROUP BY 1
|
||||||
|
`
|
||||||
|
|
||||||
|
blobSizesSubquery := `
|
||||||
|
SELECT rblob_registry_id AS rblob_registry_id, SUM(b.blob_size) AS total_size
|
||||||
|
FROM registry_blobs rb
|
||||||
|
JOIN blobs b ON rb.rblob_blob_id = b.blob_id
|
||||||
|
GROUP BY 1
|
||||||
|
`
|
||||||
|
|
||||||
|
downloadStatsSubquery := `
|
||||||
|
SELECT i.image_registry_id AS registry_id, COUNT(d.download_stat_id) AS download_count
|
||||||
|
FROM download_stats d
|
||||||
|
JOIN artifacts a ON d.download_stat_artifact_id = a.artifact_id
|
||||||
|
JOIN images i ON a.artifact_image_id = i.image_id
|
||||||
|
WHERE i.image_enabled = TRUE
|
||||||
|
GROUP BY 1
|
||||||
|
`
|
||||||
|
|
||||||
|
cte := `
|
||||||
|
WITH RECURSIVE registry_hierarchy AS (
|
||||||
|
-- Base case: Start with nodes having registry_parent_id = $1
|
||||||
|
SELECT
|
||||||
|
r.registry_id,
|
||||||
|
r.registry_parent_id,
|
||||||
|
r.registry_root_parent_id,
|
||||||
|
s.space_parent_id AS registry_parent_parent_id,
|
||||||
|
r.registry_name,
|
||||||
|
1::integer AS recursion_level, -- Initialize recursion level
|
||||||
|
ARRAY[r.registry_id] AS path -- Track visited nodes
|
||||||
|
FROM
|
||||||
|
registries r
|
||||||
|
LEFT JOIN
|
||||||
|
spaces s ON r.registry_parent_id = s.space_id -- Fetch registry_parent_parent_id from spaces
|
||||||
|
WHERE
|
||||||
|
r.registry_parent_id = %d
|
||||||
|
UNION
|
||||||
|
-- Recursive step: Traverse the hierarchy upward to the root
|
||||||
|
SELECT
|
||||||
|
r.registry_id,
|
||||||
|
r.registry_parent_id,
|
||||||
|
r.registry_root_parent_id,
|
||||||
|
s.space_parent_id AS registry_parent_parent_id,
|
||||||
|
r.registry_name,
|
||||||
|
rh.recursion_level + 1 AS recursion_level, -- Increment recursion level
|
||||||
|
rh.path || r.registry_id -- Append current node to the path
|
||||||
|
FROM
|
||||||
|
registries r
|
||||||
|
LEFT JOIN
|
||||||
|
spaces s ON r.registry_parent_id = s.space_id -- Fetch registry_parent_parent_id
|
||||||
|
INNER JOIN
|
||||||
|
registry_hierarchy rh ON rh.registry_parent_parent_id = r.registry_parent_id -- Match parent to child
|
||||||
|
WHERE
|
||||||
|
NOT r.registry_id = ANY(rh.path) -- Avoid revisiting nodes
|
||||||
|
AND rh.registry_parent_parent_id IS NOT NULL
|
||||||
|
AND rh.recursion_level < 10 -- Limit recursion depth
|
||||||
|
),
|
||||||
|
registry_hierarchy_u AS (
|
||||||
|
SELECT DISTINCT registry_id FROM registry_hierarchy)
|
||||||
|
`
|
||||||
|
cte = fmt.Sprintf(cte, parentID)
|
||||||
|
|
||||||
|
var query sq.SelectBuilder
|
||||||
|
if recursive {
|
||||||
|
query = databaseg.Builder.
|
||||||
|
Select(selectFields).
|
||||||
|
From("registry_hierarchy_u rh").
|
||||||
|
InnerJoin("registries r ON rh.registry_id = r.registry_id").
|
||||||
|
LeftJoin("upstream_proxy_configs u ON r.registry_id = u.upstream_proxy_config_registry_id").
|
||||||
|
LeftJoin(fmt.Sprintf("(%s) AS artifact_count ON r.registry_id = artifact_count.image_registry_id",
|
||||||
|
artifactCountSubquery)).
|
||||||
|
LeftJoin(fmt.Sprintf("(%s) AS blob_sizes ON r.registry_id = blob_sizes.rblob_registry_id", blobSizesSubquery)).
|
||||||
|
LeftJoin(fmt.Sprintf("(%s) AS download_stats ON r.registry_id = download_stats.registry_id", downloadStatsSubquery))
|
||||||
|
} else {
|
||||||
|
query = databaseg.Builder.
|
||||||
|
Select(selectFields).
|
||||||
From("registries r").
|
From("registries r").
|
||||||
LeftJoin("upstream_proxy_configs u ON r.registry_id = u.upstream_proxy_config_registry_id").
|
LeftJoin("upstream_proxy_configs u ON r.registry_id = u.upstream_proxy_config_registry_id").
|
||||||
LeftJoin(
|
LeftJoin(fmt.Sprintf("(%s) AS artifact_count ON r.registry_id = artifact_count.image_registry_id",
|
||||||
"(SELECT r.registry_id, count(a.image_id) as artifact_count FROM"+
|
artifactCountSubquery)).
|
||||||
" registries r LEFT JOIN images a ON r.registry_id = a.image_registry_id"+
|
LeftJoin(fmt.Sprintf("(%s) AS blob_sizes ON r.registry_id = blob_sizes.rblob_registry_id", blobSizesSubquery)).
|
||||||
" WHERE r.registry_parent_id = ? AND a.image_enabled = true GROUP BY r.registry_id ) as t2"+
|
LeftJoin(fmt.Sprintf("(%s) AS download_stats ON r.registry_id = download_stats.registry_id", downloadStatsSubquery)).
|
||||||
" ON r.registry_id = t2.registry_id ", parentID,
|
|
||||||
).
|
|
||||||
LeftJoin(
|
|
||||||
"(SELECT r.registry_id , COALESCE(sum(b.blob_size),0) as size FROM "+
|
|
||||||
"registries r LEFT JOIN registry_blobs rb ON r.registry_id = rblob_registry_id "+
|
|
||||||
"LEFT JOIN blobs b ON rblob_blob_id = b.blob_id WHERE r.registry_parent_id = ? "+
|
|
||||||
"GROUP BY r.registry_id) as t3 ON r.registry_id = t3.registry_id ", parentID,
|
|
||||||
).
|
|
||||||
LeftJoin(
|
|
||||||
"(SELECT i.image_registry_id, COUNT(d.download_stat_id) as download_count "+
|
|
||||||
"FROM artifacts a "+
|
|
||||||
" JOIN images i on i.image_id = a.artifact_image_id"+
|
|
||||||
" JOIN download_stats d ON d.download_stat_artifact_id = a.artifact_id"+
|
|
||||||
" WHERE i.image_enabled = true GROUP BY i.image_registry_id ) as t4 "+
|
|
||||||
" ON r.registry_id = t4.image_registry_id").
|
|
||||||
Where("r.registry_parent_id = ?", parentID)
|
Where("r.registry_parent_id = ?", parentID)
|
||||||
|
}
|
||||||
|
// Apply search filter
|
||||||
if search != "" {
|
if search != "" {
|
||||||
q = q.Where("r.registry_name LIKE ?", "%"+search+"%")
|
query = query.Where("r.registry_name LIKE ?", "%"+search+"%")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply package types filter
|
||||||
if len(packageTypes) > 0 {
|
if len(packageTypes) > 0 {
|
||||||
q = q.Where(sq.Eq{"r.registry_package_type": packageTypes})
|
query = query.Where(sq.Eq{"r.registry_package_type": packageTypes})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply repository type filter
|
||||||
if repoType != "" {
|
if repoType != "" {
|
||||||
q = q.Where("r.registry_type = ?", repoType)
|
query = query.Where("r.registry_type = ?", repoType)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sortByField == "artifact_count" || sortByField == "size" || sortByField == "download_count" {
|
// Sorting and pagination
|
||||||
q = q.OrderBy(sortByField + " " + sortByOrder).Limit(uint64(limit)).Offset(uint64(offset))
|
validSortFields := map[string]bool{
|
||||||
|
"artifact_count": true,
|
||||||
|
"size": true,
|
||||||
|
"download_count": true,
|
||||||
|
}
|
||||||
|
if validSortFields[sortByField] {
|
||||||
|
query = query.OrderBy(fmt.Sprintf("%s %s", sortByField, sortByOrder))
|
||||||
} else {
|
} else {
|
||||||
q = q.OrderBy("r.registry_" + sortByField + " " + sortByOrder).
|
query = query.OrderBy(fmt.Sprintf("r.registry_%s %s", sortByField, sortByOrder))
|
||||||
Limit(uint64(limit)).Offset(uint64(offset))
|
|
||||||
}
|
}
|
||||||
sql, args, err := q.ToSql()
|
query = query.Limit(uint64(limit)).Offset(uint64(offset))
|
||||||
|
|
||||||
|
// Convert query to SQL
|
||||||
|
sql, args, err := query.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Failed to convert query to sql")
|
return nil, errors.Wrap(err, "Failed to convert query to SQL")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sql = cte + sql // add CTE to the query
|
||||||
|
// Log the final query
|
||||||
|
finalQuery := util.ConstructQuery(sql, args)
|
||||||
|
log.Ctx(ctx).Debug().
|
||||||
|
Str("sql", finalQuery).
|
||||||
|
Msg("Executing query")
|
||||||
|
|
||||||
|
// Execute query
|
||||||
db := dbtx.GetAccessor(ctx, r.db)
|
db := dbtx.GetAccessor(ctx, r.db)
|
||||||
|
|
||||||
dst := []*RegistryMetadataDB{}
|
dst := []*RegistryMetadataDB{}
|
||||||
if err = db.SelectContext(ctx, &dst, sql, args...); err != nil {
|
if err := db.SelectContext(ctx, &dst, sql, args...); err != nil {
|
||||||
return nil, databaseg.ProcessSQLErrorf(ctx, err, "Failed executing custom list query")
|
return nil, databaseg.ProcessSQLErrorf(ctx, err, "Failed executing query")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map results to response type
|
||||||
return r.mapToRegistryMetadataList(ctx, dst)
|
return r.mapToRegistryMetadataList(ctx, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ package util
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/harness/gitness/registry/app/pkg/commons"
|
"github.com/harness/gitness/registry/app/pkg/commons"
|
||||||
)
|
)
|
||||||
@ -33,3 +35,56 @@ func GetEmptySQLInt32(i int) sql.NullInt32 {
|
|||||||
}
|
}
|
||||||
return sql.NullInt32{Int32: int32(i), Valid: true}
|
return sql.NullInt32{Int32: int32(i), Valid: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ConstructQuery(query string, args []interface{}) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
argIndex := 0
|
||||||
|
|
||||||
|
for i := 0; i < len(query); i++ {
|
||||||
|
if query[i] == '?' && argIndex < len(args) {
|
||||||
|
arg := args[argIndex]
|
||||||
|
argIndex++
|
||||||
|
|
||||||
|
// Convert the argument to a SQL-safe string
|
||||||
|
var argStr string
|
||||||
|
switch v := arg.(type) {
|
||||||
|
case string:
|
||||||
|
argStr = fmt.Sprintf("'%s'", strings.ReplaceAll(v, "'", "''")) // Escape single quotes in strings
|
||||||
|
case int, int64, float64:
|
||||||
|
argStr = fmt.Sprintf("%v", v)
|
||||||
|
case bool:
|
||||||
|
argStr = fmt.Sprintf("%t", v)
|
||||||
|
default:
|
||||||
|
argStr = fmt.Sprintf("'%v'", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(argStr)
|
||||||
|
} else {
|
||||||
|
builder.WriteByte(query[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatQuery is a helper function to interpolate parameters into the query.
|
||||||
|
func FormatQuery(query string, params []interface{}) string {
|
||||||
|
for i, param := range params {
|
||||||
|
placeholder := fmt.Sprintf("$%d", i+1)
|
||||||
|
var value string
|
||||||
|
switch v := param.(type) {
|
||||||
|
case string:
|
||||||
|
value = fmt.Sprintf("'%s'", strings.ReplaceAll(v, "'", "''"))
|
||||||
|
case []string:
|
||||||
|
quotedValues := make([]string, len(v))
|
||||||
|
for i, s := range v {
|
||||||
|
quotedValues[i] = fmt.Sprintf("'%s'", strings.ReplaceAll(s, "'", "''"))
|
||||||
|
}
|
||||||
|
value = fmt.Sprintf("ARRAY[%s]", strings.Join(quotedValues, ", "))
|
||||||
|
default:
|
||||||
|
value = fmt.Sprintf("%v", v)
|
||||||
|
}
|
||||||
|
query = strings.Replace(query, placeholder, value, 1)
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user