Skip to content

Commit

Permalink
Apply generic
Browse files Browse the repository at this point in the history
  • Loading branch information
minhduc140583 committed Jul 7, 2024
1 parent 3b47940 commit 28dbdb7
Show file tree
Hide file tree
Showing 15 changed files with 291 additions and 354 deletions.
25 changes: 16 additions & 9 deletions cassandra/query/query_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,44 @@ package query

import (
"fmt"
s "github.com/core-go/search"
"reflect"
"strings"
"time"

s "github.com/core-go/search"
)

const (
desc = "desc"
asc = "asc"
)

type Builder struct {
type Builder[T any, F any] struct {
TableName string
ModelType reflect.Type
BuildParam func(int) string
}

func UseQuery(tableName string, modelType reflect.Type, options ...func(int) string) func(interface{}) (string, []interface{}) {
b := NewBuilder(tableName, modelType, options...)
func UseQuery[T any, F any](tableName string, options ...func(int) string) func(F) (string, []interface{}) {
b := NewBuilder[T, F](tableName, options...)
return b.BuildQuery
}
func NewBuilder(tableName string, modelType reflect.Type, options ...func(int) string) *Builder {
func NewBuilder[T any, F any](tableName string, options ...func(int) string) *Builder[T, F] {
var build func(int) string
if len(options) > 0 {
build = options[0]
} else {
build = BuildParam
}
return &Builder{TableName: tableName, ModelType: modelType, BuildParam: build}
var t T
resultModelType := reflect.TypeOf(t)
if resultModelType.Kind() == reflect.Ptr {
resultModelType = resultModelType.Elem()
}
return &Builder[T, F]{TableName: tableName, ModelType: resultModelType, BuildParam: build}
}
func (b *Builder[T, F]) BuildQuery(filter F) (string, []interface{}) {
return Build(filter, b.TableName, b.ModelType, b.BuildParam)
}

const (
Expand Down Expand Up @@ -61,9 +70,7 @@ func getJoinFromSqlBuilderTag(typeOfField reflect.StructField) *string {
func getColumnNameFromSqlBuilderTag(typeOfField reflect.StructField) *string {
return getStringFromTag(typeOfField, "sql_builder", "column:")
}
func (b *Builder) BuildQuery(filter interface{}) (string, []interface{}) {
return Build(filter, b.TableName, b.ModelType, b.BuildParam)
}

func Build(fm interface{}, tableName string, modelType reflect.Type, buildParam func(int) string) (string, []interface{}) {
if buildParam == nil {
buildParam = BuildParam
Expand Down
45 changes: 30 additions & 15 deletions cassandra/search_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,51 @@ const (
asc = "asc"
)

type SearchBuilder struct {
DB *gocql.ClusterConfig
BuildQuery func(sm interface{}) (string, []interface{})
ModelType reflect.Type
fieldsIndex map[string]int
type SearchBuilder[T any, K any, F any] struct {
DB *gocql.ClusterConfig
Table string
BuildQuery func(F) (string, []interface{})
Mp func(*T)
Map map[string]int
}

func NewSearchQuery(db *gocql.ClusterConfig, modelType reflect.Type, buildQuery func(interface{}) (string, []interface{})) (*SearchBuilder, error) {
return NewSearchBuilder(db, modelType, buildQuery)
}
func NewSearchBuilder(db *gocql.ClusterConfig, modelType reflect.Type, buildQuery func(interface{}) (string, []interface{})) (*SearchBuilder, error) {
func NewSearchBuilder[T any, K any, F any](db *gocql.ClusterConfig, table string, buildQuery func(F) (string, []interface{}), opts ...func(*T)) (*SearchBuilder[T, K, F], error) {
var mp func(*T)
if len(opts) >= 1 {
mp = opts[0]
}
var t T
modelType := reflect.TypeOf(t)
if modelType.Kind() == reflect.Ptr {
modelType = modelType.Elem()
}
fieldsIndex, err := GetColumnIndexes(modelType)
if err != nil {
return nil, err
}
builder := &SearchBuilder{DB: db, fieldsIndex: fieldsIndex, BuildQuery: buildQuery, ModelType: modelType}
builder := &SearchBuilder[T, K, F]{DB: db, Table: table, Map: fieldsIndex, BuildQuery: buildQuery, Mp: mp}
return builder, nil
}

func (b *SearchBuilder) Search(ctx context.Context, m interface{}, results interface{}, limit int64, refId string) (string, error) {
sql, params := b.BuildQuery(m)
func (b *SearchBuilder[T, K, F]) Search(ctx context.Context, filter F, limit int64, next string) ([]T, string, error) {
var objs []T
sql, params := b.BuildQuery(filter)
ses, err := b.DB.CreateSession()
defer ses.Close()

if err != nil {
return "", err
return objs, "", err
}
nextPageToken, er2 := QueryWithMap(ses, b.fieldsIndex, results, sql, params, limit, refId)
return nextPageToken, er2
nextPageToken, er2 := QueryWithMap(ses, b.Map, &objs, sql, params, limit, next)
if b.Mp != nil {
l := len(objs)
for i := 0; i < l; i++ {
b.Mp(&objs[i])
}
}
return objs, nextPageToken, er2
}

func QueryWithMap(ses *gocql.Session, fieldsIndex map[string]int, results interface{}, sql string, values []interface{}, max int64, refId string) (string, error) {
next, er0 := hex.DecodeString(refId)
if er0 != nil {
Expand Down
25 changes: 15 additions & 10 deletions elasticsearch/query/query_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,33 @@ import (
"github.com/core-go/search"
)

func UseQuery(resultModelType reflect.Type) func(interface{}) map[string]interface{} {
b := NewBuilder(resultModelType)
func UseQuery[T any, F any]() func(F) map[string]interface{} {
b := NewBuilder[T, F]()
return b.BuildQuery
}

type Builder struct {
type Builder[T any, F any] struct {
ModelType reflect.Type
}

func NewBuilder(resultModelType reflect.Type) *Builder {
return &Builder{ModelType: resultModelType}
func NewBuilder[T any, F any]() *Builder[T, F] {
var t T
modelType := reflect.TypeOf(t)
if modelType.Kind() == reflect.Ptr {
modelType = modelType.Elem()
}
return &Builder[T, F]{ModelType: modelType}
}
func (b *Builder) BuildQuery(sm interface{}) map[string]interface{} {
return Build(sm, b.ModelType)
func (b *Builder[T, F]) BuildQuery(filter F) map[string]interface{} {
return Build(filter, b.ModelType)
}

func Build(sm interface{}, resultModelType reflect.Type) map[string]interface{} {
func Build(filter interface{}, resultModelType reflect.Type) map[string]interface{} {
query := map[string]interface{}{}
if _, ok := sm.(*search.Filter); ok {
if _, ok := filter.(*search.Filter); ok {
return query
}
value := reflect.Indirect(reflect.ValueOf(sm))
value := reflect.Indirect(reflect.ValueOf(filter))
numField := value.NumField()
for i := 0; i < numField; i++ {
fieldValue := value.Field(i).Interface()
Expand Down
37 changes: 27 additions & 10 deletions elasticsearch/search_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,47 @@ import (
"github.com/elastic/go-elasticsearch/v8"
)

type SearchBuilder struct {
type SearchBuilder[T any, F any] struct {
Client *elasticsearch.Client
Index []string
BuildQuery func(searchModel interface{}) map[string]interface{}
GetSort func(m interface{}) string
BuildQuery func(F) map[string]interface{}
GetSort func(interface{}) string
ModelType reflect.Type
idJson string
versionJson string
Map func(*T)
}

func NewSearchBuilder(client *elasticsearch.Client, index []string, modelType reflect.Type, buildQuery func(interface{}) map[string]interface{}, getSort func(m interface{}) string) *SearchBuilder {
return NewSearchBuilderWithVersion(client, index, modelType, buildQuery, getSort, "")
func NewSearchBuilder[T any, F any](client *elasticsearch.Client, index []string, buildQuery func(F) map[string]interface{}, getSort func(m interface{}) string, opts ...func(*T)) *SearchBuilder[T, F] {
return NewSearchBuilderWithVersion[T, F](client, index, buildQuery, getSort, "", opts...)
}
func NewSearchBuilderWithVersion(client *elasticsearch.Client, index []string, modelType reflect.Type, buildQuery func(interface{}) map[string]interface{}, getSort func(m interface{}) string, versionJson string) *SearchBuilder {
func NewSearchBuilderWithVersion[T any, F any](client *elasticsearch.Client, index []string, buildQuery func(F) map[string]interface{}, getSort func(m interface{}) string, versionJson string, opts ...func(*T)) *SearchBuilder[T, F] {
var t T
modelType := reflect.TypeOf(t)
if modelType.Kind() != reflect.Struct {
panic("T must be a struct")
}
idIndex, _, idJson := FindIdField(modelType)
if idIndex < 0 {
panic(fmt.Sprintf("%s struct requires id field which bson name is '_id'", modelType.Name()))
}
return &SearchBuilder{Client: client, Index: index, BuildQuery: buildQuery, GetSort: getSort, ModelType: modelType, idJson: idJson, versionJson: versionJson}
var mp func(*T)
if len(opts) > 0 && opts[0] != nil {
mp = opts[0]
}
return &SearchBuilder[T, F]{Client: client, Index: index, BuildQuery: buildQuery, GetSort: getSort, ModelType: modelType, idJson: idJson, versionJson: versionJson, Map: mp}
}
func (b *SearchBuilder) Search(ctx context.Context, filter interface{}, results interface{}, limit int64, offset int64) (int64, error) {
func (b *SearchBuilder[T, F]) Search(ctx context.Context, filter F, limit int64, offset int64) ([]T, int64, error) {
query := b.BuildQuery(filter)
s := b.GetSort(filter)
sort := BuildSort(s, b.ModelType)
total, err := BuildSearchResult(ctx, b.Client, b.Index, results, b.idJson, query, sort, limit, offset, b.versionJson)
return total, err
var objs []T
total, err := BuildSearchResult(ctx, b.Client, b.Index, objs, b.idJson, query, sort, limit, offset, b.versionJson)
if b.Map != nil {
l := len(objs)
for i := 0; i < l; i++ {
b.Map(&objs[i])
}
}
return objs, total, err
}
31 changes: 18 additions & 13 deletions firestore/query/query_builder.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,44 @@
package query

import (
"github.com/core-go/search"
f "github.com/core-go/search/firestore"
"log"
"reflect"
"strings"

"github.com/core-go/search"
f "github.com/core-go/search/firestore"
)

type Builder struct {
type Builder[T any, F any] struct {
ModelType reflect.Type
}

func UseQuery(resultModelType reflect.Type) func(interface{}) ([]f.Query, []string) {
bu := NewBuilder(resultModelType)
func UseQuery[T any, F any]() func(F) ([]f.Query, []string) {
bu := NewBuilder[T, F]()
return bu.BuildQuery
}

func NewBuilder(resultModelType reflect.Type) *Builder {
return &Builder{ModelType: resultModelType}
func NewBuilder[T any, F any]() *Builder[T, F] {
var t T
resultModelType := reflect.TypeOf(t)
if resultModelType.Kind() == reflect.Ptr {
resultModelType = resultModelType.Elem()
}
return &Builder[T, F]{ModelType: resultModelType}
}

func (b *Builder) BuildQuery(sm interface{}) ([]f.Query, []string) {
return BuildQueryByType(sm, b.ModelType)
func (b *Builder[T, F]) BuildQuery(filter F) ([]f.Query, []string) {
return BuildQueryByType(filter, b.ModelType)
}

func BuildQueryByType(sm interface{}, resultModelType reflect.Type) ([]f.Query, []string) {
func BuildQueryByType(filter interface{}, resultModelType reflect.Type) ([]f.Query, []string) {
var query = make([]f.Query, 0)
fields := make([]string, 0)

if _, ok := sm.(*search.Filter); ok {
if _, ok := filter.(*search.Filter); ok {
return query, fields
}

value := reflect.Indirect(reflect.ValueOf(sm))
value := reflect.Indirect(reflect.ValueOf(filter))
numField := value.NumField()
var keyword string
keywordFormat := map[string]string{
Expand Down
53 changes: 39 additions & 14 deletions firestore/search_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,36 @@ import (
"strings"
)

type SearchBuilder struct {
type SearchBuilder[T any, F any] struct {
Collection *firestore.CollectionRef
ModelType reflect.Type
BuildQuery func(searchModel interface{}) ([]Query, []string)
BuildQuery func(F) ([]Query, []string)
BuildSort func(s string, modelType reflect.Type) map[string]firestore.Direction
GetSort func(m interface{}) string
GetSort func(interface{}) string
Map func(*T)
idIndex int
createdTimeIndex int
updatedTimeIndex int
}

func NewSearchBuilderWithQuery(client *firestore.Client, collectionName string, modelType reflect.Type, buildQuery func(interface{}) ([]Query, []string), getSort func(interface{}) string, buildSort func(s string, modelType reflect.Type) map[string]firestore.Direction, createdTimeFieldName string, updatedTimeFieldName string, options ...string) *SearchBuilder {
func NewSearchBuilderWithSort[T any, F any](client *firestore.Client, collectionName string, buildQuery func(F) ([]Query, []string), getSort func(interface{}) string, buildSort func(s string, modelType reflect.Type) map[string]firestore.Direction, mp func(*T), opts ...string) *SearchBuilder[T, F] {
idx := -1
var idFieldName string
if len(options) > 0 && len(options[0]) > 0 {
idFieldName = options[0]
var createdTimeFieldName string
var updatedTimeFieldName string
if len(opts) > 0 && len(opts[0]) > 0 {
createdTimeFieldName = opts[0]
}
if len(opts) > 1 && len(opts[1]) > 0 {
updatedTimeFieldName = opts[1]
}
if len(opts) > 2 && len(opts[2]) > 0 {
idFieldName = opts[2]
}
var t T
modelType := reflect.TypeOf(t)
if modelType.Kind() != reflect.Struct {
panic("T must be a struct")
}
if len(idFieldName) == 0 {
idx, _, _ = FindIdField(modelType)
Expand All @@ -47,18 +61,29 @@ func NewSearchBuilderWithQuery(client *firestore.Client, collectionName string,
utIdx, _, _ = FindFieldByName(modelType, updatedTimeFieldName)
}
collection := client.Collection(collectionName)
return &SearchBuilder{Collection: collection, ModelType: modelType, BuildQuery: buildQuery, BuildSort: buildSort, GetSort: getSort, idIndex: idx, createdTimeIndex: ctIdx, updatedTimeIndex: utIdx}
return &SearchBuilder[T, F]{Collection: collection, ModelType: modelType, BuildQuery: buildQuery, BuildSort: buildSort, GetSort: getSort, Map: mp, idIndex: idx, createdTimeIndex: ctIdx, updatedTimeIndex: utIdx}
}
func NewSearchBuilderWithMap[T any, F any](client *firestore.Client, collectionName string, buildQuery func(F) ([]Query, []string), getSort func(interface{}) string, mp func(*T), opts ...string) *SearchBuilder[T, F] {
return NewSearchBuilderWithSort[T, F](client, collectionName, buildQuery, getSort, BuildSort, mp, opts...)
}
func NewSearchBuilder(client *firestore.Client, collectionName string, modelType reflect.Type, buildQuery func(interface{}) ([]Query, []string), getSort func(interface{}) string, createdTimeFieldName string, updatedTimeFieldName string, options ...string) *SearchBuilder {
return NewSearchBuilderWithQuery(client, collectionName, modelType, buildQuery, getSort, BuildSort, createdTimeFieldName, updatedTimeFieldName, options...)
func NewSearchBuilder[T any, F any](client *firestore.Client, collectionName string, buildQuery func(F) ([]Query, []string), getSort func(interface{}) string, opts ...string) *SearchBuilder[T, F] {
return NewSearchBuilderWithSort[T, F](client, collectionName, buildQuery, getSort, BuildSort, nil, opts...)
}
func (b *SearchBuilder) Search(ctx context.Context, m interface{}, results interface{}, limit int64, nextPageToken string) (string, error) {
query, fields := b.BuildQuery(m)

s := b.GetSort(m)
func (b *SearchBuilder[T, F]) Search(ctx context.Context, filter F, limit int64, nextPageToken string) ([]T, string, error) {
query, fields := b.BuildQuery(filter)

s := b.GetSort(filter)
sort := b.BuildSort(s, b.ModelType)
refId, err := BuildSearchResult(ctx, b.Collection, results, query, fields, sort, limit, nextPageToken, b.idIndex, b.createdTimeIndex, b.updatedTimeIndex)
return refId, err
var objs []T
refId, err := BuildSearchResult(ctx, b.Collection, &objs, query, fields, sort, limit, nextPageToken, b.idIndex, b.createdTimeIndex, b.updatedTimeIndex)
if b.Map != nil {
l := len(objs)
for i := 0; i < l; i++ {
b.Map(&objs[i])
}
}
return objs, refId, err
}

func BuildSearchResult(ctx context.Context, collection *firestore.CollectionRef, results interface{}, query []Query, fields []string, sort map[string]firestore.Direction, limit int64, refId string, idIndex int, createdTimeIndex int, updatedTimeIndex int) (string, error) {
Expand Down
Loading

0 comments on commit 28dbdb7

Please sign in to comment.