git.zd.zone/hrpc/hrpc@v0.0.12/database/dgraph/dgraph.go (about) 1 package dgraph 2 3 import ( 4 "context" 5 "encoding/json" 6 7 "git.zd.zone/hrpc/hrpc/database" 8 "github.com/dgraph-io/dgo/v210" 9 "github.com/dgraph-io/dgo/v210/protos/api" 10 "google.golang.org/grpc" 11 "google.golang.org/grpc/credentials/insecure" 12 ) 13 14 // Proxy represents a collection of methods to operate dGraph 15 type Proxy interface { 16 // Alter can be used to set schema. 17 // For example: 18 // op := &api.Operation{ 19 // Schema: `name: string @index(exact) .`, 20 // RunInBackground: true 21 // } 22 Alter(ctx context.Context, op *api.Operation) error 23 // Transaction should be called normally to run a Mutation or Upsert(Query + Mutation). 24 // For example: 25 // (Mutation) 26 // type Person struct { 27 // Name string `json:"name,omitempty"` 28 // } 29 // p := Persion{Name: "xxx"} 30 // b, err := json.Marshal(p) 31 // mu := &api.Mutation{ 32 // SetJson: b, 33 // } 34 // req := &api.Request{CommitNow: true, Mutations: []*api.Mutation{mu}} 35 // rsp, err := Transaction(ctx, req) 36 // (Query + Mutation) WITHOUT conditions 37 // q := `query {user as var(func: eq(email, "wrong_email@example.com"))}` 38 // mu := &api.Mutation{SetNquads: []byte(`uid(user) <email> "correct_email@example.com" .`)} 39 // req := &api.Request{Query: q, Mutations: []*api.Mutation{mu}, CommitNow: true} 40 // rsp, err := Transaction(ctx, req) 41 // (Query + Mutation) WITH conditions 42 // q := `query {user as var(func: eq(email, "wrong_email@example.com"))}` 43 // mu := &api.Mutation{ 44 // Cond: `@if(eq(len(user), 1))`, 45 // SetNquads: []byte(`uid(user) <email> "correct_email@example.com" .`), 46 // } 47 // req := &api.Request{Query: q, Mutations: []*api.Mutation{mu}, CommitNow: true} 48 // rsp, err := Transaction(ctx, req) 49 Transaction(ctx context.Context, req *api.Request) ([]byte, error) 50 // Query can be used in two ways, including general query and query with variables. 51 // It is useful to increase read speed. 52 // the param of `vars` can be nil if you do not want to pass variables to the Query statements. 53 Query(ctx context.Context, q string, vars map[string]string) ([]byte, error) 54 } 55 56 var dg *dGraph 57 58 type dGraph struct { 59 client *dgo.Dgraph 60 conns []*grpc.ClientConn 61 62 option Option 63 } 64 65 func New() *dGraph { 66 if dg != nil { 67 dg.Destory() 68 } 69 dg = &dGraph{} 70 return dg 71 } 72 73 // ------------ for implemation database.Database START-------- // 74 75 func (d *dGraph) Load(src []byte) error { 76 if err := json.Unmarshal(src, &d.option); err != nil { 77 return err 78 } 79 return nil 80 } 81 func (d *dGraph) Connect() error { 82 d.Destory() 83 84 var clients []api.DgraphClient 85 for _, target := range d.option.Targets { 86 c, err := grpc.Dial(target, grpc.WithTransportCredentials(insecure.NewCredentials())) 87 if err != nil { 88 return err 89 } 90 d.conns = append(d.conns, c) 91 clients = append(clients, api.NewDgraphClient(c)) 92 } 93 d.client = dgo.NewDgraphClient(clients...) 94 if d.option.Credential.User != "" && d.option.Credential.Password != "" { 95 if d.option.Credential.Namespace == 0 { 96 d.client.Login( 97 context.Background(), 98 d.option.Credential.User, 99 d.option.Credential.Password, 100 ) 101 } else { 102 // SHOULD ONLY valid for Dgraph v21.03 or above 103 d.client.LoginIntoNamespace( 104 context.Background(), 105 d.option.Credential.User, 106 d.option.Credential.Password, 107 d.option.Credential.Namespace, 108 ) 109 } 110 } 111 return nil 112 } 113 func (d *dGraph) Name() string { 114 return "dgraph" 115 } 116 func (d *dGraph) Destory() { 117 for _, c := range d.conns { 118 c.Close() 119 } 120 } 121 122 // ------------ for implemation database.Database END-------- // 123 124 func (d *dGraph) Alter(ctx context.Context, op *api.Operation) error { 125 return dg.client.Alter(ctx, op) 126 } 127 128 func (d *dGraph) Transaction(ctx context.Context, req *api.Request) ([]byte, error) { 129 txn := dg.client.NewTxn() 130 defer txn.Discard(ctx) 131 132 rsp, err := txn.Do(ctx, req) 133 if err != nil { 134 return nil, err 135 } 136 if err := txn.Commit(ctx); err != nil { 137 return nil, err 138 } 139 return rsp.GetJson(), nil 140 } 141 142 func (d *dGraph) Query(ctx context.Context, q string, vars map[string]string) ([]byte, error) { 143 txn := dg.client.NewReadOnlyTxn() 144 defer txn.Discard(ctx) 145 146 if vars != nil { 147 rsp, err := txn.QueryWithVars(ctx, q, vars) 148 if err != nil { 149 return nil, err 150 } 151 return rsp.GetJson(), nil 152 } 153 154 rsp, err := txn.Query(ctx, q) 155 if err != nil { 156 return nil, err 157 } 158 return rsp.GetJson(), nil 159 } 160 161 // Client returns the handler to operate mysql if success 162 func Client() Proxy { 163 return dg 164 } 165 166 var _ database.Database = (*dGraph)(nil)