github.com/ecodeclub/eorm@v0.0.2-0.20231001112437-dae71da914d0/internal/datasource/masterslave/master_slave_db.go (about) 1 // Copyright 2021 ecodeclub 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package masterslave 16 17 import ( 18 "context" 19 "database/sql" 20 "fmt" 21 22 "github.com/ecodeclub/eorm/internal/datasource/masterslave/slaves" 23 "go.uber.org/multierr" 24 25 "github.com/ecodeclub/eorm/internal/datasource" 26 "github.com/ecodeclub/eorm/internal/datasource/transaction" 27 ) 28 29 var _ datasource.TxBeginner = &MasterSlavesDB{} 30 var _ datasource.DataSource = &MasterSlavesDB{} 31 32 type MasterSlavesDB struct { 33 master *sql.DB 34 slaves slaves.Slaves 35 } 36 37 type key string 38 39 const ( 40 master key = "master" 41 ) 42 43 func (m *MasterSlavesDB) Query(ctx context.Context, query datasource.Query) (*sql.Rows, error) { 44 _, ok := ctx.Value(master).(bool) 45 if ok { 46 return m.master.QueryContext(ctx, query.SQL, query.Args...) 47 } 48 slave, err := m.slaves.Next(ctx) 49 if err != nil { 50 return nil, err 51 } 52 return slave.DB.QueryContext(ctx, query.SQL, query.Args...) 53 } 54 55 func (m *MasterSlavesDB) Exec(ctx context.Context, query datasource.Query) (sql.Result, error) { 56 return m.master.ExecContext(ctx, query.SQL, query.Args...) 57 } 58 59 func (m *MasterSlavesDB) BeginTx(ctx context.Context, opts *sql.TxOptions) (datasource.Tx, error) { 60 tx, err := m.master.BeginTx(ctx, opts) 61 if err != nil { 62 return nil, err 63 } 64 return transaction.NewTx(tx, m), nil 65 } 66 67 func NewMasterSlavesDB(master *sql.DB, opts ...MasterSlavesDBOption) *MasterSlavesDB { 68 db := &MasterSlavesDB{ 69 master: master, 70 } 71 for _, opt := range opts { 72 opt(db) 73 } 74 return db 75 } 76 77 func (m *MasterSlavesDB) Close() error { 78 var err error 79 if er := m.master.Close(); er != nil { 80 err = multierr.Combine( 81 err, fmt.Errorf("master error: %w", er)) 82 } 83 if m.slaves != nil { 84 if er := m.slaves.Close(); er != nil { 85 err = multierr.Combine(err, er) 86 } 87 } 88 return err 89 } 90 91 type MasterSlavesDBOption func(db *MasterSlavesDB) 92 93 func MasterSlavesWithSlaves(s slaves.Slaves) MasterSlavesDBOption { 94 return func(db *MasterSlavesDB) { 95 db.slaves = s 96 } 97 } 98 99 func UseMaster(ctx context.Context) context.Context { 100 return context.WithValue(ctx, master, true) 101 }