feature/init_member #1

Merged
daniel.w merged 7 commits from feature/init_member into main 2024-08-22 14:26:04 +00:00
29 changed files with 1428 additions and 47 deletions
Showing only changes of commit 5aff70ae2f - Show all commits

View File

@ -47,3 +47,21 @@ build-docker:
docker buildx build -t $(DOCKER_REPO):$(VERSION) --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/ed_25519)" . docker buildx build -t $(DOCKER_REPO):$(VERSION) --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/ed_25519)" .
rm -rf Dockerfile rm -rf Dockerfile
@echo "Generate core-api files successfully" @echo "Generate core-api files successfully"
.PHONY: gen-model
gen-model: # 建立 rpc 資料庫
goctl model mysql ddl -c no -s ./generate/database/mysql/20230529020011_account_table.up.sql --style go_zero -d ./internal/model -i ''
goctl model mysql ddl -c no -s ./generate/database/mysql/20230529020011_account_uid_table.up.sql --style go_zero -d ./internal/model -i ''
goctl model mysql ddl -c no -s ./generate/database/mysql/20230529020011_user_table.up.sql --style go_zero -d ./internal/model -i ''
goctl model mysql ddl -c no -s ./generate/database/mysql/20230719061241_machine_node.up.sql --style go_zero -d ./internal/model -i ''
@echo "Generate model files successfully"
# 只產生 Model 剩下的要自己撰寫,連欄位名稱也是
goctl model mongo -t AutoId -c --dir ./internal/model/mongo --style go_zero
#goctl model mysql ddl -s ./generate/database/mysql/20240819090248_create_role_permission_table.up.sql --style go_zero -d ./internal/model -i '' (沒cache)
#goctl model mysql ddl -c no -s ./generate/database/mysql/20240816014305_create_permission_table.up.sql --style go_zero -d ./internal/model -i '' (有cache)
#.PHONY: mock-gen
#mock-gen: # 建立 mock 資料
# mockgen -source=./order.go -destination=../../repository/mock/order.go -package=mock
# @echo "Generate model files successfully"

View File

@ -3,6 +3,11 @@ syntax = "proto3";
package member; package member;
option go_package="./member"; option go_package="./member";
// OKResp
message OKResp {}
// NoneReq
message NoneReq {}
// ================ enum ================ // ================ enum ================
enum VerifyType { enum VerifyType {
VERIFY_NONE = 0; // VERIFY_NONE = 0; //
@ -27,11 +32,6 @@ enum MemberStatus {
STATUS_GA = 6; // GA STATUS_GA = 6; // GA
} }
enum Gender {
GENDER_NONE = 0; //
GENDER_MALE = 1; //
GENDER_FEMALE = 2; //
}
// ================ enum ================ // ================ enum ================
@ -41,17 +41,6 @@ message Pager {
int64 size=2; int64 size=2;
int64 index=3; int64 index=3;
} }
message Response {
BaseResp status=1;
}
message BaseResp {
string code = 1;
string message = 2;
string error = 3;
}
// ================ common ================ // ================ common ================
@ -81,8 +70,7 @@ message CreateUserInfoReq {
} }
message GetAccountInfoResp { message GetAccountInfoResp {
BaseResp status = 1; CreateLoginUserReq data = 1;
CreateLoginUserReq data = 2;
} }
// UpdateUserInfoReq // UpdateUserInfoReq
@ -91,24 +79,18 @@ message UpdateUserInfoReq {
optional string language = 2; optional string language = 2;
optional string currency = 3; optional string currency = 3;
optional string nick_name = 4; optional string nick_name = 4;
optional uint32 gender = 5; optional VerifyType verify_type = 5;
optional int64 birthday = 6; optional AlarmType alarm_type = 6;
optional VerifyType verify_type = 7; optional MemberStatus status = 7;
optional AlarmType alarm_type = 8;
optional MemberStatus status = 9;
} }
message GetUIDByAccountReq { message GetUIDByAccountReq {
string account = 1; string account = 1;
} }
message UID {
string uid = 1;
}
message GetUidByAccountResp { message GetUidByAccountResp {
BaseResp status = 1; string uid = 1;
UID data = 2; string account =2;
} }
message UpdateTokenReq { message UpdateTokenReq {
@ -126,8 +108,7 @@ message VerifyCode {
} }
message GenerateRefreshCodeResp { message GenerateRefreshCodeResp {
BaseResp status = 1; VerifyCode data = 1;
VerifyCode data = 2;
} }
message VerifyRefreshCodeReq { message VerifyRefreshCodeReq {
@ -158,8 +139,7 @@ message UserInfo {
} }
message GetUserInfoResp { message GetUserInfoResp {
BaseResp status = 1; UserInfo data = 1;
UserInfo data = 2;
} }
message ListUserInfoReq { message ListUserInfoReq {
@ -173,29 +153,28 @@ message ListUserInfoReq {
} }
message ListUserInfoResp { message ListUserInfoResp {
BaseResp status = 1; repeated UserInfo data = 1;
repeated UserInfo data = 2; Pager page =2;
Pager page =3;
} }
service Account { service Account {
// CreateUserAccount -> // CreateUserAccount ->
rpc CreateUserAccount(CreateLoginUserReq) returns(Response); rpc CreateUserAccount(CreateLoginUserReq) returns(OKResp);
// GetUserAccountInfo // GetUserAccountInfo
rpc GetUserAccountInfo(GetUIDByAccountReq) returns(GetAccountInfoResp); rpc GetUserAccountInfo(GetUIDByAccountReq) returns(GetAccountInfoResp);
// UpdateUserToken // UpdateUserToken
rpc UpdateUserToken(UpdateTokenReq) returns(Response); rpc UpdateUserToken(UpdateTokenReq) returns(OKResp);
// GetUidByAccount UID // GetUidByAccount UID
rpc GetUidByAccount(GetUIDByAccountReq) returns(GetUidByAccountResp); rpc GetUidByAccount(GetUIDByAccountReq) returns(GetUidByAccountResp);
// BindAccount -> account bind to UID // BindAccount -> account bind to UID
rpc BindAccount(BindingUserReq) returns(Response); rpc BindAccount(BindingUserReq) returns(OKResp);
// BindUserInfo User Info // BindUserInfo User Info
rpc BindUserInfo(CreateUserInfoReq) returns(Response); rpc BindUserInfo(CreateUserInfoReq) returns(OKResp);
// UpdateUserInfo User Info // UpdateUserInfo User Info
rpc UpdateUserInfo(UpdateUserInfoReq) returns(Response); rpc UpdateUserInfo(UpdateUserInfoReq) returns(OKResp);
// UpdateStatus // UpdateStatus
rpc UpdateStatus(UpdateStatusReq) returns(Response); rpc UpdateStatus(UpdateStatusReq) returns(OKResp);
// GetUserInfo // GetUserInfo
rpc GetUserInfo(GetUserInfoReq) returns(GetUserInfoResp); rpc GetUserInfo(GetUserInfoReq) returns(GetUserInfoResp);
// ListMember // ListMember
@ -203,7 +182,7 @@ service Account {
// GenerateRefreshCode // GenerateRefreshCode
rpc GenerateRefreshCode(GenerateRefreshCodeReq) returns(GenerateRefreshCodeResp); rpc GenerateRefreshCode(GenerateRefreshCodeReq) returns(GenerateRefreshCodeResp);
// VerifyRefreshCode token // VerifyRefreshCode token
rpc VerifyRefreshCode(VerifyRefreshCodeReq) returns(Response); rpc VerifyRefreshCode(VerifyRefreshCodeReq) returns(OKResp);
} }
// ================ account ================ // ================ account ================

12
go.mod
View File

@ -3,12 +3,17 @@ module app-cloudep-member-server
go 1.22.3 go 1.22.3
require ( require (
code.30cm.net/digimon/library-go/errors v1.0.1
code.30cm.net/digimon/library-go/validator v1.0.0
github.com/bwmarrin/snowflake v0.3.0
github.com/zeromicro/go-zero v1.7.0 github.com/zeromicro/go-zero v1.7.0
go.uber.org/goleak v1.3.0
google.golang.org/grpc v1.65.0 google.golang.org/grpc v1.65.0
google.golang.org/protobuf v1.34.2 google.golang.org/protobuf v1.34.2
) )
require ( require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
@ -18,11 +23,16 @@ require (
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/fatih/color v1.17.0 // indirect github.com/fatih/color v1.17.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.4 // indirect github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.22.0 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/mock v1.6.0 // indirect github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
@ -33,6 +43,7 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
@ -65,6 +76,7 @@ require (
go.uber.org/automaxprocs v1.5.3 // indirect go.uber.org/automaxprocs v1.5.3 // indirect
go.uber.org/multierr v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/net v0.27.0 // indirect golang.org/x/net v0.27.0 // indirect
golang.org/x/oauth2 v0.20.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect
golang.org/x/sys v0.22.0 // indirect golang.org/x/sys v0.22.0 // indirect

View File

@ -1,7 +1,33 @@
package config package config
import "github.com/zeromicro/go-zero/zrpc" import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/zrpc"
)
type Config struct { type Config struct {
zrpc.RpcServerConf zrpc.RpcServerConf
// 加上 DB 結構體
DB struct {
DsnString string
}
// 快取
Cache cache.CacheConf
// 密碼加密層數
Bcrypt struct {
Cost int
}
// Redis Cluster
RedisCluster redis.RedisConf
Mongo struct {
Schema string
User string
Password string
Host string
Port string
Database string
Collection string
}
} }

18
internal/domain/const.go Normal file
View File

@ -0,0 +1,18 @@
package domain
const (
DefaultPageSize = 100
DefaultPageIndex = 1
Scope = 10
)
const InitAutoId = 1000000
const DefaultReferralCodeLen = 8
var ConvertTable = [...]string{
"O", "D", "W", "X", "Y",
"G", "B", "C", "H", "E",
"F", "A", "Q", "I", "J",
"L", "M", "N", "Z", "K",
"P", "V", "R", "S", "T",
}

View File

@ -0,0 +1,21 @@
package usecase
import (
ers "code.30cm.net/digimon/library-go/errors"
"code.30cm.net/digimon/library-go/errors/code"
)
// 12 represents Scope
// 100 represents Category
// 9 represents Detail error code
// full code 12009 只會有 系統以及錯誤碼category 是給系統判定用的
// 目前 Scope 以及分類要系統共用,係向的錯誤各自服務實作就好
const (
UIDOutOfRangeErrorCode = iota + 1
)
// UIDOutOfRangeErrorCodeError 20001 Token 簽名錯誤
func UIDOutOfRangeErrorCodeError(msg string) *ers.LibError {
return ers.NewErr(code.CloudEPMember, code.CatInput, UIDOutOfRangeErrorCode, msg)
}

View File

@ -0,0 +1,7 @@
package usecase
import "context"
type UIDGenerateUseCase interface {
Generate(ctx context.Context) (string, error)
}

View File

@ -0,0 +1,27 @@
package middleware
import (
ers "code.30cm.net/digimon/library-go/errors"
"context"
"errors"
"github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc"
"time"
)
const defaultTimeout = 30 * time.Second
func TimeoutMiddleware(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
newCtx, cancelCtx := context.WithTimeout(ctx, defaultTimeout)
defer func() {
cancelCtx()
if errors.Is(newCtx.Err(), context.DeadlineExceeded) {
err = ers.SystemTimeoutError(info.FullMethod)
logx.Errorf("Method: %s, request %v, timeout: %d", info.FullMethod, req, defaultTimeout)
}
}()
return handler(ctx, req)
}

View File

@ -0,0 +1,18 @@
package snowflake
import (
"fmt"
"time"
)
type NewNodeError struct {
machineNodeID int64
startTime time.Time
Err error
}
func (e *NewNodeError) Error() string {
return fmt.Sprintf("new node fail machineNodeID: %d, startTime: %s, err: %v",
e.machineNodeID, e.startTime, e.Err)
}

View File

@ -0,0 +1,54 @@
package snowflake
import (
"fmt"
"testing"
"time"
)
func TestNewNodeError_Error(t *testing.T) {
startTime, err := time.Parse(time.DateOnly, "2023-07-20")
if err != nil {
t.Error(err)
}
t.Parallel()
type fields struct {
machineNodeID int64
startTime time.Time
Err error
}
tests := []struct {
name string
fields fields
want string
}{
{
name: "success",
fields: fields{
machineNodeID: 1,
startTime: startTime,
Err: nil,
},
want: fmt.Sprintf("new node fail machineNodeID: %d, startTime: %s, err: %v",
1, "2023-07-20 00:00:00 +0000 UTC", nil),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
e := &NewNodeError{
machineNodeID: tt.fields.machineNodeID,
startTime: tt.fields.startTime,
Err: tt.fields.Err,
}
if got := e.Error(); got != tt.want {
t.Errorf("Error() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -0,0 +1,8 @@
###
# snowflake
```go
import "yt.com/backend/common.git/snowflake"
```
### 量級超過1024 再來做解決

View File

@ -0,0 +1,81 @@
package snowflake
import (
"fmt"
"sync"
"time"
"github.com/bwmarrin/snowflake"
)
var mu sync.Mutex
// Snowflake provides a way to NewNode for Generate UID.
type Snowflake struct {
machineNodeID int64
startTime time.Time
}
// Option is the options type to configure Snowflake.
type Option func(*Snowflake)
// New returns a new Snowflake instance with the provided options.
func New(opts ...Option) *Snowflake {
s := &Snowflake{
// default machine 1
machineNodeID: 1,
}
for _, opt := range opts {
opt(s)
}
return s
}
// WithMachineNodeID adds machineID total 10bit = 1024 machine number.
func WithMachineNodeID(machineNodeID int64) Option {
return func(snowflake *Snowflake) {
snowflake.machineNodeID = machineNodeID
}
}
// WithStartTime adds snowflake start timestamp in milliseconds.
func WithStartTime(startTime time.Time) Option {
return func(snowflake *Snowflake) {
snowflake.startTime = startTime
}
}
// GetNowDate return nowTodayDate e.g. 2023-07-20 00:00:00 +0000 UTC.
func GetNowDate() (time.Time, error) {
startTime := time.Now().UTC().Format(time.DateOnly)
st, err := time.Parse(time.DateOnly, startTime)
if err != nil {
return time.Time{}, fmt.Errorf("time.Parse failed :%w", err)
}
return st, nil
}
// NewNode return snowflake node use Generate UID.
func (s *Snowflake) NewNode() (*snowflake.Node, error) {
mu.Lock()
defer mu.Unlock()
snowflake.Epoch = s.startTime.UnixMilli()
node, err := snowflake.NewNode(s.machineNodeID)
if err != nil {
return nil, fmt.Errorf("snowflake.NewNode, failed :%w",
&NewNodeError{
machineNodeID: s.machineNodeID,
startTime: s.startTime,
Err: err,
})
}
return node, nil
}

View File

@ -0,0 +1,148 @@
package snowflake
import (
"flag"
"os"
"reflect"
"testing"
"time"
"go.uber.org/goleak"
)
func TestMain(m *testing.M) {
leak := flag.Bool("leak", false, "use leak detector")
flag.Parse()
if *leak {
goleak.VerifyTestMain(m)
return
}
os.Exit(m.Run())
}
func TestSnowflake(t *testing.T) {
st, err := GetNowDate()
if err != nil {
t.Error(err)
}
t.Parallel()
type args struct {
machineNodeID int64
startTime time.Time
}
tests := []struct {
name string
args args
want *Snowflake
wantDeepEqualErr bool
wantNewNodeErr bool
}{
{
name: "success",
args: args{
machineNodeID: 10,
startTime: st,
},
want: &Snowflake{
machineNodeID: 10,
startTime: st,
},
wantDeepEqualErr: false,
wantNewNodeErr: false,
},
{
name: "failed machine node ID negative number",
args: args{
machineNodeID: -1,
startTime: time.Time{},
},
want: &Snowflake{
machineNodeID: -1,
startTime: time.Time{},
},
wantDeepEqualErr: false,
wantNewNodeErr: true,
},
{
name: "failed snowflake struct field by machine node ID",
args: args{
machineNodeID: 10,
startTime: st,
},
want: &Snowflake{
machineNodeID: 2,
startTime: st,
},
wantDeepEqualErr: true,
wantNewNodeErr: false,
},
{
name: "failed snowflake struct field by startTime",
args: args{
machineNodeID: 2,
startTime: st,
},
want: &Snowflake{
machineNodeID: 2,
startTime: time.Time{},
},
wantDeepEqualErr: true,
wantNewNodeErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := New(
WithMachineNodeID(tt.args.machineNodeID),
WithStartTime(tt.args.startTime),
)
if !reflect.DeepEqual(got, tt.want) != tt.wantDeepEqualErr {
t.Errorf("Snowflake.New() = %v, want %v", got, tt.want)
}
node, err := got.NewNode()
if (err != nil) != tt.wantNewNodeErr {
t.Errorf("NewNode() = %v, want %v", err != nil, tt.wantNewNodeErr)
}
if err == nil {
id := node.Generate().Int64()
if id <= 0 {
t.Errorf("node.Generate().Int64() = %v, want %s", id, "id > 0")
}
}
})
}
}
func BenchmarkSnowflake(b *testing.B) {
st, err := GetNowDate()
if err != nil {
b.Error(err)
}
snowflake := New(
WithMachineNodeID(1),
WithStartTime(st),
)
node, err := snowflake.NewNode()
if err != nil {
b.Error(err)
}
for i := 0; i < b.N; i++ {
node.Generate().Int64()
}
}

27
internal/model/account_model.go Executable file
View File

@ -0,0 +1,27 @@
package model
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var _ AccountModel = (*customAccountModel)(nil)
type (
// AccountModel is an interface to be customized, add more methods here,
// and implement the added methods in customAccountModel.
AccountModel interface {
accountModel
}
customAccountModel struct {
*defaultAccountModel
}
)
// NewAccountModel returns a model for the database table.
func NewAccountModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) AccountModel {
return &customAccountModel{
defaultAccountModel: newAccountModel(conn, c, opts...),
}
}

View File

@ -0,0 +1,154 @@
// Code generated by goctl. DO NOT EDIT.
package model
import (
"context"
"database/sql"
"fmt"
"strings"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/stringx"
)
var (
accountFieldNames = builder.RawFieldNames(&Account{})
accountRows = strings.Join(accountFieldNames, ",")
accountRowsExpectAutoSet = strings.Join(stringx.Remove(accountFieldNames, "`id`"), ",")
accountRowsWithPlaceHolder = strings.Join(stringx.Remove(accountFieldNames, "`id`"), "=?,") + "=?"
cacheAccountIdPrefix = "cache:account:id:"
cacheAccountAccountPrefix = "cache:account:account:"
)
type (
accountModel interface {
Insert(ctx context.Context, data *Account) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*Account, error)
FindOneByAccount(ctx context.Context, account string) (*Account, error)
Update(ctx context.Context, data *Account) error
Delete(ctx context.Context, id int64) error
}
defaultAccountModel struct {
sqlc.CachedConn
table string
}
Account struct {
Id int64 `db:"id"`
Account string `db:"account"`
Token string `db:"token"`
Platform int64 `db:"platform"` // 平台類型 1. ark 2. google
CreateTime int64 `db:"create_time"`
UpdateTime int64 `db:"update_time"`
}
)
func newAccountModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) *defaultAccountModel {
return &defaultAccountModel{
CachedConn: sqlc.NewConn(conn, c, opts...),
table: "`account`",
}
}
func (m *defaultAccountModel) withSession(session sqlx.Session) *defaultAccountModel {
return &defaultAccountModel{
CachedConn: m.CachedConn.WithSession(session),
table: "`account`",
}
}
func (m *defaultAccountModel) Delete(ctx context.Context, id int64) error {
data, err := m.FindOne(ctx, id)
if err != nil {
return err
}
accountAccountKey := fmt.Sprintf("%s%v", cacheAccountAccountPrefix, data.Account)
accountIdKey := fmt.Sprintf("%s%v", cacheAccountIdPrefix, id)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
return conn.ExecCtx(ctx, query, id)
}, accountAccountKey, accountIdKey)
return err
}
func (m *defaultAccountModel) FindOne(ctx context.Context, id int64) (*Account, error) {
accountIdKey := fmt.Sprintf("%s%v", cacheAccountIdPrefix, id)
var resp Account
err := m.QueryRowCtx(ctx, &resp, accountIdKey, func(ctx context.Context, conn sqlx.SqlConn, v any) error {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", accountRows, m.table)
return conn.QueryRowCtx(ctx, v, query, id)
})
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAccountModel) FindOneByAccount(ctx context.Context, account string) (*Account, error) {
accountAccountKey := fmt.Sprintf("%s%v", cacheAccountAccountPrefix, account)
var resp Account
err := m.QueryRowIndexCtx(ctx, &resp, accountAccountKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) {
query := fmt.Sprintf("select %s from %s where `account` = ? limit 1", accountRows, m.table)
if err := conn.QueryRowCtx(ctx, &resp, query, account); err != nil {
return nil, err
}
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAccountModel) Insert(ctx context.Context, data *Account) (sql.Result, error) {
accountAccountKey := fmt.Sprintf("%s%v", cacheAccountAccountPrefix, data.Account)
accountIdKey := fmt.Sprintf("%s%v", cacheAccountIdPrefix, data.Id)
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?)", m.table, accountRowsExpectAutoSet)
return conn.ExecCtx(ctx, query, data.Account, data.Token, data.Platform, data.CreateTime, data.UpdateTime)
}, accountAccountKey, accountIdKey)
return ret, err
}
func (m *defaultAccountModel) Update(ctx context.Context, newData *Account) error {
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return err
}
accountAccountKey := fmt.Sprintf("%s%v", cacheAccountAccountPrefix, data.Account)
accountIdKey := fmt.Sprintf("%s%v", cacheAccountIdPrefix, data.Id)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, accountRowsWithPlaceHolder)
return conn.ExecCtx(ctx, query, newData.Account, newData.Token, newData.Platform, newData.CreateTime, newData.UpdateTime, newData.Id)
}, accountAccountKey, accountIdKey)
return err
}
func (m *defaultAccountModel) formatPrimary(primary any) string {
return fmt.Sprintf("%s%v", cacheAccountIdPrefix, primary)
}
func (m *defaultAccountModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", accountRows, m.table)
return conn.QueryRowCtx(ctx, v, query, primary)
}
func (m *defaultAccountModel) tableName() string {
return m.table
}

View File

@ -0,0 +1,27 @@
package model
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var _ AccountToUidModel = (*customAccountToUidModel)(nil)
type (
// AccountToUidModel is an interface to be customized, add more methods here,
// and implement the added methods in customAccountToUidModel.
AccountToUidModel interface {
accountToUidModel
}
customAccountToUidModel struct {
*defaultAccountToUidModel
}
)
// NewAccountToUidModel returns a model for the database table.
func NewAccountToUidModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) AccountToUidModel {
return &customAccountToUidModel{
defaultAccountToUidModel: newAccountToUidModel(conn, c, opts...),
}
}

View File

@ -0,0 +1,152 @@
// Code generated by goctl. DO NOT EDIT.
package model
import (
"context"
"database/sql"
"fmt"
"strings"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/stringx"
)
var (
accountToUidFieldNames = builder.RawFieldNames(&AccountToUid{})
accountToUidRows = strings.Join(accountToUidFieldNames, ",")
accountToUidRowsExpectAutoSet = strings.Join(stringx.Remove(accountToUidFieldNames, "`id`"), ",")
accountToUidRowsWithPlaceHolder = strings.Join(stringx.Remove(accountToUidFieldNames, "`id`"), "=?,") + "=?"
cacheAccountToUidIdPrefix = "cache:accountToUid:id:"
cacheAccountToUidAccountPrefix = "cache:accountToUid:account:"
)
type (
accountToUidModel interface {
Insert(ctx context.Context, data *AccountToUid) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*AccountToUid, error)
FindOneByAccount(ctx context.Context, account string) (*AccountToUid, error)
Update(ctx context.Context, data *AccountToUid) error
Delete(ctx context.Context, id int64) error
}
defaultAccountToUidModel struct {
sqlc.CachedConn
table string
}
AccountToUid struct {
Id int64 `db:"id"`
Account string `db:"account"`
Uid string `db:"uid"`
Type int64 `db:"type"` // 1 手機 2 信箱 3 自定義帳號
}
)
func newAccountToUidModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) *defaultAccountToUidModel {
return &defaultAccountToUidModel{
CachedConn: sqlc.NewConn(conn, c, opts...),
table: "`account_to_uid`",
}
}
func (m *defaultAccountToUidModel) withSession(session sqlx.Session) *defaultAccountToUidModel {
return &defaultAccountToUidModel{
CachedConn: m.CachedConn.WithSession(session),
table: "`account_to_uid`",
}
}
func (m *defaultAccountToUidModel) Delete(ctx context.Context, id int64) error {
data, err := m.FindOne(ctx, id)
if err != nil {
return err
}
accountToUidAccountKey := fmt.Sprintf("%s%v", cacheAccountToUidAccountPrefix, data.Account)
accountToUidIdKey := fmt.Sprintf("%s%v", cacheAccountToUidIdPrefix, id)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
return conn.ExecCtx(ctx, query, id)
}, accountToUidAccountKey, accountToUidIdKey)
return err
}
func (m *defaultAccountToUidModel) FindOne(ctx context.Context, id int64) (*AccountToUid, error) {
accountToUidIdKey := fmt.Sprintf("%s%v", cacheAccountToUidIdPrefix, id)
var resp AccountToUid
err := m.QueryRowCtx(ctx, &resp, accountToUidIdKey, func(ctx context.Context, conn sqlx.SqlConn, v any) error {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", accountToUidRows, m.table)
return conn.QueryRowCtx(ctx, v, query, id)
})
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAccountToUidModel) FindOneByAccount(ctx context.Context, account string) (*AccountToUid, error) {
accountToUidAccountKey := fmt.Sprintf("%s%v", cacheAccountToUidAccountPrefix, account)
var resp AccountToUid
err := m.QueryRowIndexCtx(ctx, &resp, accountToUidAccountKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) {
query := fmt.Sprintf("select %s from %s where `account` = ? limit 1", accountToUidRows, m.table)
if err := conn.QueryRowCtx(ctx, &resp, query, account); err != nil {
return nil, err
}
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAccountToUidModel) Insert(ctx context.Context, data *AccountToUid) (sql.Result, error) {
accountToUidAccountKey := fmt.Sprintf("%s%v", cacheAccountToUidAccountPrefix, data.Account)
accountToUidIdKey := fmt.Sprintf("%s%v", cacheAccountToUidIdPrefix, data.Id)
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?)", m.table, accountToUidRowsExpectAutoSet)
return conn.ExecCtx(ctx, query, data.Account, data.Uid, data.Type)
}, accountToUidAccountKey, accountToUidIdKey)
return ret, err
}
func (m *defaultAccountToUidModel) Update(ctx context.Context, newData *AccountToUid) error {
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return err
}
accountToUidAccountKey := fmt.Sprintf("%s%v", cacheAccountToUidAccountPrefix, data.Account)
accountToUidIdKey := fmt.Sprintf("%s%v", cacheAccountToUidIdPrefix, data.Id)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, accountToUidRowsWithPlaceHolder)
return conn.ExecCtx(ctx, query, newData.Account, newData.Uid, newData.Type, newData.Id)
}, accountToUidAccountKey, accountToUidIdKey)
return err
}
func (m *defaultAccountToUidModel) formatPrimary(primary any) string {
return fmt.Sprintf("%s%v", cacheAccountToUidIdPrefix, primary)
}
func (m *defaultAccountToUidModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", accountToUidRows, m.table)
return conn.QueryRowCtx(ctx, v, query, primary)
}
func (m *defaultAccountToUidModel) tableName() string {
return m.table
}

View File

@ -0,0 +1,27 @@
package model
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var _ MachineNodeModel = (*customMachineNodeModel)(nil)
type (
// MachineNodeModel is an interface to be customized, add more methods here,
// and implement the added methods in customMachineNodeModel.
MachineNodeModel interface {
machineNodeModel
}
customMachineNodeModel struct {
*defaultMachineNodeModel
}
)
// NewMachineNodeModel returns a model for the database table.
func NewMachineNodeModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) MachineNodeModel {
return &customMachineNodeModel{
defaultMachineNodeModel: newMachineNodeModel(conn, c, opts...),
}
}

View File

@ -0,0 +1,117 @@
// Code generated by goctl. DO NOT EDIT.
package model
import (
"context"
"database/sql"
"fmt"
"strings"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/stringx"
)
var (
machineNodeFieldNames = builder.RawFieldNames(&MachineNode{})
machineNodeRows = strings.Join(machineNodeFieldNames, ",")
machineNodeRowsExpectAutoSet = strings.Join(stringx.Remove(machineNodeFieldNames, "`id`"), ",")
machineNodeRowsWithPlaceHolder = strings.Join(stringx.Remove(machineNodeFieldNames, "`id`"), "=?,") + "=?"
cacheMachineNodeIdPrefix = "cache:machineNode:id:"
)
type (
machineNodeModel interface {
Insert(ctx context.Context, data *MachineNode) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*MachineNode, error)
Update(ctx context.Context, data *MachineNode) error
Delete(ctx context.Context, id int64) error
}
defaultMachineNodeModel struct {
sqlc.CachedConn
table string
}
MachineNode struct {
Id int64 `db:"id"` // 流水號
CreateTime int64 `db:"create_time"` // 創建時間
UpdateTime int64 `db:"update_time"` // 更新時間
HostName string `db:"host_name"` // host name
}
)
func newMachineNodeModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) *defaultMachineNodeModel {
return &defaultMachineNodeModel{
CachedConn: sqlc.NewConn(conn, c, opts...),
table: "`machine_node`",
}
}
func (m *defaultMachineNodeModel) withSession(session sqlx.Session) *defaultMachineNodeModel {
return &defaultMachineNodeModel{
CachedConn: m.CachedConn.WithSession(session),
table: "`machine_node`",
}
}
func (m *defaultMachineNodeModel) Delete(ctx context.Context, id int64) error {
machineNodeIdKey := fmt.Sprintf("%s%v", cacheMachineNodeIdPrefix, id)
_, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
return conn.ExecCtx(ctx, query, id)
}, machineNodeIdKey)
return err
}
func (m *defaultMachineNodeModel) FindOne(ctx context.Context, id int64) (*MachineNode, error) {
machineNodeIdKey := fmt.Sprintf("%s%v", cacheMachineNodeIdPrefix, id)
var resp MachineNode
err := m.QueryRowCtx(ctx, &resp, machineNodeIdKey, func(ctx context.Context, conn sqlx.SqlConn, v any) error {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", machineNodeRows, m.table)
return conn.QueryRowCtx(ctx, v, query, id)
})
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultMachineNodeModel) Insert(ctx context.Context, data *MachineNode) (sql.Result, error) {
machineNodeIdKey := fmt.Sprintf("%s%v", cacheMachineNodeIdPrefix, data.Id)
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?)", m.table, machineNodeRowsExpectAutoSet)
return conn.ExecCtx(ctx, query, data.CreateTime, data.UpdateTime, data.HostName)
}, machineNodeIdKey)
return ret, err
}
func (m *defaultMachineNodeModel) Update(ctx context.Context, data *MachineNode) error {
machineNodeIdKey := fmt.Sprintf("%s%v", cacheMachineNodeIdPrefix, data.Id)
_, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, machineNodeRowsWithPlaceHolder)
return conn.ExecCtx(ctx, query, data.CreateTime, data.UpdateTime, data.HostName, data.Id)
}, machineNodeIdKey)
return err
}
func (m *defaultMachineNodeModel) formatPrimary(primary any) string {
return fmt.Sprintf("%s%v", cacheMachineNodeIdPrefix, primary)
}
func (m *defaultMachineNodeModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", machineNodeRows, m.table)
return conn.QueryRowCtx(ctx, v, query, primary)
}
func (m *defaultMachineNodeModel) tableName() string {
return m.table
}

View File

@ -0,0 +1,46 @@
package model
import (
"context"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/monc"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
var _ AutoIdModel = (*customAutoIdModel)(nil)
type (
// AutoIdModel is an interface to be customized, add more methods here,
// and implement the added methods in customAutoIdModel.
AutoIdModel interface {
autoIdModel
Inc(ctx context.Context, data *AutoId) error
}
customAutoIdModel struct {
*defaultAutoIdModel
}
)
// NewAutoIdModel returns a model for the mongo.
func NewAutoIdModel(url, db, collection string, c cache.CacheConf) AutoIdModel {
conn := monc.MustNewModel(url, db, collection, c)
return &customAutoIdModel{
defaultAutoIdModel: newDefaultAutoIdModel(conn),
}
}
func (m *customAutoIdModel) Inc(ctx context.Context, data *AutoId) error {
filter := bson.M{"admin": "auto_id"}
update := bson.M{"$inc": bson.M{"counter": 1}}
key := prefixAutoIdCacheKey + "count"
err := m.conn.FindOneAndUpdate(ctx, key, data, filter, update,
options.FindOneAndUpdate().SetUpsert(true),
options.FindOneAndUpdate().SetReturnDocument(options.After),
)
return err
}

View File

@ -0,0 +1,77 @@
// Code generated by goctl. DO NOT EDIT.
package model
import (
"context"
"time"
"github.com/zeromicro/go-zero/core/stores/monc"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)
var prefixAutoIdCacheKey = "cache:autoId:"
type autoIdModel interface {
Insert(ctx context.Context, data *AutoId) error
FindOne(ctx context.Context, id string) (*AutoId, error)
Update(ctx context.Context, data *AutoId) (*mongo.UpdateResult, error)
Delete(ctx context.Context, id string) (int64, error)
}
type defaultAutoIdModel struct {
conn *monc.Model
}
func newDefaultAutoIdModel(conn *monc.Model) *defaultAutoIdModel {
return &defaultAutoIdModel{conn: conn}
}
func (m *defaultAutoIdModel) Insert(ctx context.Context, data *AutoId) error {
if data.ID.IsZero() {
data.ID = primitive.NewObjectID()
data.CreateAt = time.Now()
data.UpdateAt = time.Now()
}
key := prefixAutoIdCacheKey + data.ID.Hex()
_, err := m.conn.InsertOne(ctx, key, data)
return err
}
func (m *defaultAutoIdModel) FindOne(ctx context.Context, id string) (*AutoId, error) {
oid, err := primitive.ObjectIDFromHex(id)
if err != nil {
return nil, ErrInvalidObjectId
}
var data AutoId
key := prefixAutoIdCacheKey + id
err = m.conn.FindOne(ctx, key, &data, bson.M{"_id": oid})
switch err {
case nil:
return &data, nil
case monc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAutoIdModel) Update(ctx context.Context, data *AutoId) (*mongo.UpdateResult, error) {
data.UpdateAt = time.Now()
key := prefixAutoIdCacheKey + data.ID.Hex()
res, err := m.conn.UpdateOne(ctx, key, bson.M{"_id": data.ID}, bson.M{"$set": data})
return res, err
}
func (m *defaultAutoIdModel) Delete(ctx context.Context, id string) (int64, error) {
oid, err := primitive.ObjectIDFromHex(id)
if err != nil {
return 0, ErrInvalidObjectId
}
key := prefixAutoIdCacheKey + id
res, err := m.conn.DeleteOne(ctx, key, bson.M{"_id": oid})
return res, err
}

View File

@ -0,0 +1,15 @@
package model
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type AutoId struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
Name string `bson:"name,omitempty" json:"name,omitempty"`
Count uint64 `bson:"count,omitempty" json:"count,omitempty"`
UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"`
}

View File

@ -0,0 +1,12 @@
package model
import (
"errors"
"github.com/zeromicro/go-zero/core/stores/mon"
)
var (
ErrNotFound = mon.ErrNotFound
ErrInvalidObjectId = errors.New("invalid objectId")
)

View File

@ -0,0 +1,27 @@
package model
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var _ UserTableModel = (*customUserTableModel)(nil)
type (
// UserTableModel is an interface to be customized, add more methods here,
// and implement the added methods in customUserTableModel.
UserTableModel interface {
userTableModel
}
customUserTableModel struct {
*defaultUserTableModel
}
)
// NewUserTableModel returns a model for the database table.
func NewUserTableModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) UserTableModel {
return &customUserTableModel{
defaultUserTableModel: newUserTableModel(conn, c, opts...),
}
}

View File

@ -0,0 +1,159 @@
// Code generated by goctl. DO NOT EDIT.
package model
import (
"context"
"database/sql"
"fmt"
"strings"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/stringx"
)
var (
userTableFieldNames = builder.RawFieldNames(&UserTable{})
userTableRows = strings.Join(userTableFieldNames, ",")
userTableRowsExpectAutoSet = strings.Join(stringx.Remove(userTableFieldNames, "`id`"), ",")
userTableRowsWithPlaceHolder = strings.Join(stringx.Remove(userTableFieldNames, "`id`"), "=?,") + "=?"
cacheUserTableIdPrefix = "cache:userTable:id:"
cacheUserTableUidPrefix = "cache:userTable:uid:"
)
type (
userTableModel interface {
Insert(ctx context.Context, data *UserTable) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*UserTable, error)
FindOneByUid(ctx context.Context, uid string) (*UserTable, error)
Update(ctx context.Context, data *UserTable) error
Delete(ctx context.Context, id int64) error
}
defaultUserTableModel struct {
sqlc.CachedConn
table string
}
UserTable struct {
Id int64 `db:"id"`
VerifyType int64 `db:"verify_type"` // 驗證類型 0. 異常 1.信箱 2.手機 3. GA 4.不驗證
AlarmType int64 `db:"alarm_type"` // 告警狀態 0. 異常 1. 正常(未告警) 2.系統告警中
Status int64 `db:"status"` // 會員狀態 0. 異常 1. 尚未驗證 2. 啟用 3. 停權中 4. 信箱以驗證 5. 手機以驗證 6. GA 以驗證
Uid string `db:"uid"` // 唯一辨識碼
NickName string `db:"nick_name"` // 暱稱
Language string `db:"language"` // 使用語言
Currency string `db:"currency"` // 使用幣別
Avatar string `db:"avatar"` // 會員頭像
CreateTime int64 `db:"create_time"`
UpdateTime int64 `db:"update_time"`
}
)
func newUserTableModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) *defaultUserTableModel {
return &defaultUserTableModel{
CachedConn: sqlc.NewConn(conn, c, opts...),
table: "`user_table`",
}
}
func (m *defaultUserTableModel) withSession(session sqlx.Session) *defaultUserTableModel {
return &defaultUserTableModel{
CachedConn: m.CachedConn.WithSession(session),
table: "`user_table`",
}
}
func (m *defaultUserTableModel) Delete(ctx context.Context, id int64) error {
data, err := m.FindOne(ctx, id)
if err != nil {
return err
}
userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, id)
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
return conn.ExecCtx(ctx, query, id)
}, userTableIdKey, userTableUidKey)
return err
}
func (m *defaultUserTableModel) FindOne(ctx context.Context, id int64) (*UserTable, error) {
userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, id)
var resp UserTable
err := m.QueryRowCtx(ctx, &resp, userTableIdKey, func(ctx context.Context, conn sqlx.SqlConn, v any) error {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", userTableRows, m.table)
return conn.QueryRowCtx(ctx, v, query, id)
})
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultUserTableModel) FindOneByUid(ctx context.Context, uid string) (*UserTable, error) {
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, uid)
var resp UserTable
err := m.QueryRowIndexCtx(ctx, &resp, userTableUidKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) {
query := fmt.Sprintf("select %s from %s where `uid` = ? limit 1", userTableRows, m.table)
if err := conn.QueryRowCtx(ctx, &resp, query, uid); err != nil {
return nil, err
}
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultUserTableModel) Insert(ctx context.Context, data *UserTable) (sql.Result, error) {
userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, data.Id)
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid)
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, userTableRowsExpectAutoSet)
return conn.ExecCtx(ctx, query, data.VerifyType, data.AlarmType, data.Status, data.Uid, data.NickName, data.Language, data.Currency, data.Avatar, data.CreateTime, data.UpdateTime)
}, userTableIdKey, userTableUidKey)
return ret, err
}
func (m *defaultUserTableModel) Update(ctx context.Context, newData *UserTable) error {
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return err
}
userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, data.Id)
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, userTableRowsWithPlaceHolder)
return conn.ExecCtx(ctx, query, newData.VerifyType, newData.AlarmType, newData.Status, newData.Uid, newData.NickName, newData.Language, newData.Currency, newData.Avatar, newData.CreateTime, newData.UpdateTime, newData.Id)
}, userTableIdKey, userTableUidKey)
return err
}
func (m *defaultUserTableModel) formatPrimary(primary any) string {
return fmt.Sprintf("%s%v", cacheUserTableIdPrefix, primary)
}
func (m *defaultUserTableModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error {
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", userTableRows, m.table)
return conn.QueryRowCtx(ctx, v, query, primary)
}
func (m *defaultUserTableModel) tableName() string {
return m.table
}

5
internal/model/vars.go Normal file
View File

@ -0,0 +1,5 @@
package model
import "github.com/zeromicro/go-zero/core/stores/sqlx"
var ErrNotFound = sqlx.ErrNotFound

View File

@ -1,13 +1,56 @@
package svc package svc
import "app-cloudep-member-server/internal/config" import (
"app-cloudep-member-server/internal/config"
"app-cloudep-member-server/internal/domain"
domainUC "app-cloudep-member-server/internal/domain/usecase"
"app-cloudep-member-server/internal/model"
mgo "app-cloudep-member-server/internal/model/mongo"
"app-cloudep-member-server/internal/usecase"
ers "code.30cm.net/digimon/library-go/errors"
vi "code.30cm.net/digimon/library-go/validator"
"fmt"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type ServiceContext struct { type ServiceContext struct {
Config config.Config Config config.Config
Validate vi.Validate
AccountModel model.AccountModel
UserModel model.UserTableModel
AccountToUidModel model.AccountToUidModel
GenUIDUseCase domainUC.UIDGenerateUseCase
Redis redis.Redis
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
// 設置
ers.Scope = domain.Scope
sqlConn := sqlx.NewMysql(c.DB.DsnString)
newRedis, err := redis.NewRedis(c.RedisCluster, redis.Cluster())
if err != nil {
panic(err)
}
mongo := mgo.NewAutoIdModel(
fmt.Sprintf(
"%s://%s:%s@%s:%s", c.Mongo.Schema,
c.Mongo.User, c.Mongo.Password, c.Mongo.Host, c.Mongo.Port),
c.Mongo.Database,
c.Mongo.Collection,
c.Cache)
return &ServiceContext{ return &ServiceContext{
Config: c, Config: c,
Validate: vi.MustValidator(vi.WithAccount("account")),
Redis: *newRedis,
UserModel: model.NewUserTableModel(sqlConn, c.Cache),
AccountToUidModel: model.NewAccountToUidModel(sqlConn, c.Cache),
AccountModel: model.NewAccountModel(sqlConn, c.Cache),
GenUIDUseCase: usecase.MustGenerateUseCase(usecase.GenerateUseCaseParam{
GenerateUIDRepo: mongo,
}),
} }
} }

View File

@ -0,0 +1 @@
package usecase

View File

@ -0,0 +1,75 @@
package usecase
import (
"app-cloudep-member-server/internal/domain"
"app-cloudep-member-server/internal/domain/usecase"
mgo "app-cloudep-member-server/internal/model/mongo"
"context"
"math"
"strconv"
"strings"
)
type GenerateUseCaseParam struct {
GenerateUIDRepo mgo.AutoIdModel
}
type GenerateUseCase struct {
generateUIDRepo mgo.AutoIdModel
}
func MustGenerateUseCase(param GenerateUseCaseParam) usecase.UIDGenerateUseCase {
return &GenerateUseCase{
generateUIDRepo: param.GenerateUIDRepo,
}
}
// Generate 利用 mongo 創立全局唯一的 ark id
// 如果之後有效能問題,扛在同一個 mongo 資料庫,在改成雪花算法
func (g GenerateUseCase) Generate(ctx context.Context) (string, error) {
var data mgo.AutoId
err := g.generateUIDRepo.Inc(ctx, &data)
if err != nil {
return "", err
}
uid := strconv.Itoa(int(domain.InitAutoId + data.Count))
code, err := generateReferralCode(uid)
if err != nil {
return "", err
}
return code, nil
}
// generateReferralCode 從 UID 生成 referralCode
func generateReferralCode(uid string) (string, error) {
uidInt, err := strconv.ParseInt(uid, 10, 64)
if err != nil {
return "", err
}
maxReferralUIDBoundary := int64(math.Pow(float64(len(domain.ConvertTable)), float64(domain.DefaultReferralCodeLen)))
if uidInt > maxReferralUIDBoundary {
return "", usecase.UIDOutOfRangeErrorCodeError("uid encode out of range")
}
encoded := encodeToBase(uidInt, len(domain.ConvertTable), domain.DefaultReferralCodeLen)
return encoded, nil
}
func encodeToBase(num int64, base int, length int) string {
result := ""
for num > 0 {
index := num % int64(base)
result = domain.ConvertTable[index] + result
num /= int64(base)
}
// makes sure the length fo result feats the input length
if len(result) < length {
result = strings.Repeat(domain.ConvertTable[0], length-len(result)) + result
}
return result
}