github.com/blong14/gache@v0.0.0-20240124023949-89416fd8bbfa/sql/conn.go (about) 1 package sql 2 3 import ( 4 "context" 5 "database/sql" 6 "database/sql/driver" 7 "errors" 8 "fmt" 9 "io" 10 "strconv" 11 "strings" 12 "sync" 13 14 gdb "github.com/blong14/gache/internal/db" 15 glog "github.com/blong14/gache/internal/logging" 16 gproxy "github.com/blong14/gache/internal/proxy" 17 ) 18 19 type QueryResponse struct { 20 Key []byte 21 Value []byte 22 RangeValues [][][]byte 23 Stats gdb.QueryStats 24 Success bool 25 } 26 27 type rows struct { 28 next *QueryResponse 29 done bool 30 } 31 32 func (r *rows) Columns() []string { 33 return []string{"value"} 34 } 35 36 func (r *rows) Close() error { 37 return nil 38 } 39 40 func (r *rows) Next(dest []driver.Value) error { 41 dest[0] = r.next 42 r.done = true 43 return nil 44 } 45 46 func (r *rows) HasNextResultSet() bool { 47 hasNext := r.next != nil && !r.done 48 return hasNext 49 } 50 51 func (r *rows) NextResultSet() error { 52 if r.next == nil { 53 return io.EOF 54 } 55 r.next = nil 56 return nil 57 } 58 59 type conn struct { 60 proxy *gproxy.QueryProxy 61 } 62 63 func (c *conn) Commit() error { 64 return errors.New("not implemented") 65 } 66 67 func (c *conn) Rollback() error { 68 return errors.New("not implemented") 69 } 70 71 func (c *conn) Prepare(_ string) (driver.Stmt, error) { 72 return nil, errors.New("not implemented") 73 } 74 75 func (c *conn) Close() error { 76 glog.Track("closing db connection...") 77 return nil 78 } 79 80 func (c *conn) Begin() (driver.Tx, error) { 81 return nil, errors.New("not implemented") 82 } 83 84 func (c *conn) Query(query string, args []driver.NamedValue) (driver.Rows, error) { 85 return c.QueryContext(context.Background(), query, args) 86 } 87 88 func (c *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { 89 q, err := parse(strings.NewReader(query)) 90 if err != nil { 91 return nil, err 92 } 93 for _, arg := range args { 94 valueOrKey := arg.Value.([]byte) 95 switch arg.Name { 96 case "table": 97 q.Header.TableName = valueOrKey 98 case "start": 99 q.KeyRange.Start = valueOrKey 100 case "end": 101 q.KeyRange.End = valueOrKey 102 case "key": 103 q.Key = valueOrKey 104 case "value": 105 q.Value = valueOrKey 106 case "limit": 107 q.KeyRange.Limit, err = strconv.Atoi(string(valueOrKey)) 108 if err != nil { 109 return nil, fmt.Errorf("invalid limit arg: %w", err) 110 } 111 default: 112 return nil, errors.New("invalid args") 113 } 114 } 115 c.proxy.Send(ctx, q) 116 resp := q.GetResponse() 117 return &rows{ 118 next: &QueryResponse{ 119 Key: resp.Key, 120 Value: resp.Value, 121 RangeValues: resp.RangeValues, 122 Stats: resp.Stats, 123 Success: resp.Success, 124 }, 125 }, nil 126 } 127 128 func (c *conn) Ping() error { 129 result, err := c.Query( 130 "select value from tables where key = %s;", 131 []driver.NamedValue{ 132 {Name: "key", Ordinal: 1, Value: "default"}, 133 }, 134 ) 135 if err != nil { 136 return err 137 } 138 if err = result.Close(); err != nil { 139 return err 140 } 141 return nil 142 } 143 144 var queryProxy *gproxy.QueryProxy 145 146 const MEMORY = ":memory:" 147 148 type Driver struct { 149 once sync.Once 150 } 151 152 func (d *Driver) Open(dsn string) (driver.Conn, error) { 153 var err error 154 d.once.Do(func() { 155 var qp *gproxy.QueryProxy 156 qp, err = gproxy.NewQueryProxy() 157 queryProxy = qp 158 gproxy.StartProxy(context.Background(), queryProxy) 159 }) 160 return &conn{proxy: queryProxy}, err 161 } 162 163 func init() { 164 sql.Register("gache", &Driver{}) 165 } 166 167 func GetProxy() (*gproxy.QueryProxy, error) { 168 return queryProxy, nil 169 }