-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6574dd1
commit 5c4d56d
Showing
13 changed files
with
1,411 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package cassandra | ||
|
||
import ( | ||
"context" | ||
"reflect" | ||
) | ||
|
||
func MapModels(ctx context.Context, models interface{}, mp func(context.Context, interface{}) (interface{}, error)) (interface{}, error) { | ||
vo := reflect.Indirect(reflect.ValueOf(models)) | ||
if vo.Kind() == reflect.Ptr { | ||
vo = reflect.Indirect(vo) | ||
} | ||
if vo.Kind() == reflect.Slice { | ||
le := vo.Len() | ||
for i := 0; i < le; i++ { | ||
x := vo.Index(i) | ||
k := x.Kind() | ||
if k == reflect.Struct { | ||
y := x.Addr().Interface() | ||
mp(ctx, y) | ||
} else { | ||
y := x.Interface() | ||
mp(ctx, y) | ||
} | ||
|
||
} | ||
} | ||
return models, nil | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package cassandra | ||
|
||
import ( | ||
"errors" | ||
"github.com/gocql/gocql" | ||
"reflect" | ||
"strings" | ||
) | ||
|
||
func ScanIter(iter *gocql.Iter, results interface{}, options...map[string]int) error { | ||
modelType := reflect.TypeOf(results).Elem().Elem() | ||
|
||
tb, er2 := Scan(iter, modelType, options...) | ||
if er2 != nil { | ||
return er2 | ||
} | ||
for _, element := range tb { | ||
appendToArray(results, element) | ||
} | ||
return nil | ||
} | ||
func appendToArray(arr interface{}, item interface{}) interface{} { | ||
arrValue := reflect.ValueOf(arr) | ||
elemValue := reflect.Indirect(arrValue) | ||
|
||
itemValue := reflect.ValueOf(item) | ||
if itemValue.Kind() == reflect.Ptr { | ||
itemValue = reflect.Indirect(itemValue) | ||
} | ||
elemValue.Set(reflect.Append(elemValue, itemValue)) | ||
return arr | ||
} | ||
func GetColumnIndexes(modelType reflect.Type) (map[string]int, error) { | ||
ma := make(map[string]int, 0) | ||
if modelType.Kind() != reflect.Struct { | ||
return ma, errors.New("bad type") | ||
} | ||
for i := 0; i < modelType.NumField(); i++ { | ||
field := modelType.Field(i) | ||
ormTag := field.Tag.Get("gorm") | ||
column, ok := FindTag(ormTag, "column") | ||
column = strings.ToLower(column) | ||
if ok { | ||
ma[column] = i | ||
} | ||
} | ||
return ma, nil | ||
} | ||
func FindTag(tag string, key string) (string, bool) { | ||
if has := strings.Contains(tag, key); has { | ||
str1 := strings.Split(tag, ";") | ||
num := len(str1) | ||
for i := 0; i < num; i++ { | ||
str2 := strings.Split(str1[i], ":") | ||
for j := 0; j < len(str2); j++ { | ||
if str2[j] == key { | ||
return str2[j+1], true | ||
} | ||
} | ||
} | ||
} | ||
return "", false | ||
} | ||
func Scan(iter *gocql.Iter, modelType reflect.Type, options...map[string]int) (t []interface{}, err error) { | ||
var fieldsIndex map[string]int | ||
if len(options) > 0 && options[0] != nil { | ||
fieldsIndex = options[0] | ||
} else { | ||
fieldsIndex, err = GetColumnIndexes(modelType) | ||
} | ||
if err != nil { | ||
return | ||
} | ||
columns := GetColumns(iter.Columns()) | ||
for { | ||
initModel := reflect.New(modelType).Interface() | ||
r := StructScan(initModel, columns, fieldsIndex, -1) | ||
if !iter.Scan(r...) { | ||
return | ||
} else { | ||
t = append(t, initModel) | ||
} | ||
} | ||
} | ||
func StructScan(s interface{}, columns []string, fieldsIndex map[string]int, indexIgnore int) (r []interface{}) { | ||
if s != nil { | ||
modelType := reflect.TypeOf(s).Elem() | ||
maps := reflect.Indirect(reflect.ValueOf(s)) | ||
if columns == nil { | ||
for i := 0; i < maps.NumField(); i++ { | ||
r = append(r, maps.Field(i).Addr().Interface()) | ||
} | ||
return | ||
} | ||
for i, columnsName := range columns { | ||
if i == indexIgnore { | ||
continue | ||
} | ||
var index int | ||
var ok bool | ||
var valueField reflect.Value | ||
if fieldsIndex == nil { | ||
if _, ok = modelType.FieldByName(columnsName); !ok { | ||
var t interface{} | ||
r = append(r, &t) | ||
continue | ||
} | ||
valueField = maps.FieldByName(columnsName) | ||
} else { | ||
if index, ok = fieldsIndex[columnsName]; !ok { | ||
var t interface{} | ||
r = append(r, &t) | ||
continue | ||
} | ||
valueField = maps.Field(index) | ||
} | ||
x := valueField.Addr().Interface() | ||
r = append(r, x) | ||
} | ||
} | ||
return | ||
} | ||
func GetColumns(cols []gocql.ColumnInfo) []string { | ||
c2 := make([]string, 0) | ||
if cols == nil { | ||
return c2 | ||
} | ||
for _, c := range cols { | ||
s := strings.ToLower(c.Name) | ||
c2 = append(c2, s) | ||
} | ||
return c2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package cassandra | ||
|
||
import ( | ||
"context" | ||
"encoding/hex" | ||
"reflect" | ||
"strings" | ||
|
||
"github.com/gocql/gocql" | ||
) | ||
|
||
const ( | ||
desc = "desc" | ||
asc = "asc" | ||
) | ||
|
||
type SearchBuilder struct { | ||
DB *gocql.ClusterConfig | ||
BuildQuery func(sm interface{}) (string, []interface{}) | ||
ModelType reflect.Type | ||
Map func(ctx context.Context, model interface{}) (interface{}, error) | ||
fieldsIndex map[string]int | ||
} | ||
func NewSearchQuery(db *gocql.ClusterConfig, modelType reflect.Type, buildQuery func(interface{}) (string, []interface{}), options ...func(context.Context, interface{}) (interface{}, error)) (*SearchBuilder, error) { | ||
return NewSearchBuilder(db, modelType, buildQuery, options...) | ||
} | ||
func NewSearchBuilder(db *gocql.ClusterConfig, modelType reflect.Type, buildQuery func(interface{}) (string, []interface{}), options ...func(context.Context, interface{}) (interface{}, error)) (*SearchBuilder, error) { | ||
var mp func(context.Context, interface{}) (interface{}, error) | ||
if len(options) >= 1 { | ||
mp = options[0] | ||
} | ||
fieldsIndex, err := GetColumnIndexes(modelType) | ||
if err != nil { | ||
return nil, err | ||
} | ||
builder := &SearchBuilder{DB: db, fieldsIndex: fieldsIndex, BuildQuery: buildQuery, ModelType: modelType, Map: 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) | ||
ses, err := b.DB.CreateSession() | ||
defer ses.Close() | ||
|
||
if err != nil { | ||
return "", err | ||
} | ||
nextPageToken, er2 := QueryWithMap(ses, b.fieldsIndex, results, sql, params, limit, refId, b.Map) | ||
return nextPageToken, er2 | ||
} | ||
func QueryWithMap(ses *gocql.Session, fieldsIndex map[string]int, results interface{}, sql string, values []interface{}, max int64, refId string, options...func(context.Context, interface{}) (interface{}, error)) (string, error) { | ||
var mp func(context.Context, interface{}) (interface{}, error) | ||
if len(options) > 0 && options[0] != nil { | ||
mp = options[0] | ||
} | ||
next, er0 := hex.DecodeString(refId) | ||
if er0 != nil { | ||
return "", er0 | ||
} | ||
query := ses.Query(sql, values...).PageState(next).PageSize(int(max)) | ||
if query.Exec() != nil { | ||
return "", query.Exec() | ||
} | ||
err := ScanIter(query.Iter(), results, fieldsIndex) | ||
if err != nil { | ||
return "", err | ||
} | ||
nextPageToken := hex.EncodeToString(query.Iter().PageState()) | ||
if mp != nil { | ||
_, err := MapModels(context.Background(), results, mp) | ||
return nextPageToken, err | ||
} | ||
return nextPageToken, nil | ||
} | ||
func GetSort(sortString string, modelType reflect.Type) string { | ||
var sort = make([]string, 0) | ||
sorts := strings.Split(sortString, ",") | ||
for i := 0; i < len(sorts); i++ { | ||
sortField := strings.TrimSpace(sorts[i]) | ||
fieldName := sortField | ||
c := sortField[0:1] | ||
if c == "-" || c == "+" { | ||
fieldName = sortField[1:] | ||
} | ||
columnName := GetColumnNameForSearch(modelType, fieldName) | ||
if len(columnName) > 0 { | ||
sortType := GetSortType(c) | ||
sort = append(sort, columnName+" "+sortType) | ||
} | ||
} | ||
if len(sort) > 0 { | ||
return strings.Join(sort, ",") | ||
} else { | ||
return "" | ||
} | ||
} | ||
func BuildSort(sortString string, modelType reflect.Type) string { | ||
sort := GetSort(sortString, modelType) | ||
if len(sort) > 0 { | ||
return ` order by ` + sort | ||
} else { | ||
return "" | ||
} | ||
} | ||
func GetColumnNameForSearch(modelType reflect.Type, sortField string) string { | ||
sortField = strings.TrimSpace(sortField) | ||
i, _, column := GetFieldByJson(modelType, sortField) | ||
if i > -1 { | ||
return column | ||
} | ||
return "" | ||
} | ||
func GetSortType(sortType string) string { | ||
if sortType == "-" { | ||
return desc | ||
} else { | ||
return asc | ||
} | ||
} | ||
func GetFieldByJson(modelType reflect.Type, jsonName string) (int, string, string) { | ||
numField := modelType.NumField() | ||
for i := 0; i < numField; i++ { | ||
field := modelType.Field(i) | ||
tag1, ok1 := field.Tag.Lookup("json") | ||
if ok1 && strings.Split(tag1, ",")[0] == jsonName { | ||
if tag2, ok2 := field.Tag.Lookup("gorm"); ok2 { | ||
if has := strings.Contains(tag2, "column"); has { | ||
str1 := strings.Split(tag2, ";") | ||
num := len(str1) | ||
for k := 0; k < num; k++ { | ||
str2 := strings.Split(str1[k], ":") | ||
for j := 0; j < len(str2); j++ { | ||
if str2[j] == "column" { | ||
return i, field.Name, str2[j+1] | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return i, field.Name, "" | ||
} | ||
} | ||
return -1, jsonName, jsonName | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package firestore | ||
|
||
import ( | ||
"cloud.google.com/go/firestore" | ||
"context" | ||
firebase "firebase.google.com/go" | ||
"google.golang.org/api/option" | ||
"log" | ||
) | ||
|
||
func Connect(ctx context.Context, credentials []byte) (*firestore.Client, error) { | ||
app, er1 := firebase.NewApp(ctx, nil, option.WithCredentialsJSON(credentials)) | ||
if er1 != nil { | ||
log.Fatalf("Could not create admin client: %v", er1) | ||
return nil, er1 | ||
} | ||
|
||
client, er2 := app.Firestore(ctx) | ||
if er2 != nil { | ||
log.Fatalf("Could not create data operations client: %v", er2) | ||
return nil, er2 | ||
} | ||
return client, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package geo | ||
|
||
type JSON struct { | ||
Type string `json:"type,omitempty" bson:"type,omitempty"` | ||
Coordinates []float64 `json:"coordinates,omitempty" bson:"coordinates,omitempty"` | ||
} |
Oops, something went wrong.