This repository has been archived by the owner on Jan 18, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathcommands.go
218 lines (187 loc) · 5.36 KB
/
commands.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
package orient
import (
"bytes"
"io"
"reflect"
"gopkg.in/istreamdata/orientgo.v2/obinary/rw"
)
var (
_ Serializable = (*textReqCommand)(nil)
_ OCommandRequestText = SQLQuery{}
_ OCommandRequestText = SQLCommand{}
_ OCommandRequestText = ScriptCommand{}
_ OCommandRequestText = FunctionCommand{}
)
// OCommandRequestText is an interface for text-based database commands,
// which can be executed using database.Command function.
type OCommandRequestText interface {
CustomSerializable
GetText() string
}
func arrayToParamsMap(params []interface{}) interface{} {
if len(params) == 1 && reflect.TypeOf(params[0]).Kind() == reflect.Map {
return params[0]
}
mp := make(map[int32]interface{}, len(params))
for i, p := range params {
if ide, ok := p.(OIdentifiable); ok {
p = ide.GetIdentity() // use RID only
}
mp[int32(i)] = p
}
return mp
}
func newTextReqCommand(text string, params []interface{}) textReqCommand {
return textReqCommand{text: text, params: params}
}
// textReqCommand is a generic text-based command.
//
// OCommandTextAbstract in Java world.
type textReqCommand struct {
//OCommandReq
text string
params []interface{}
}
func (rq textReqCommand) GetText() string {
return rq.text
}
func (rq textReqCommand) ToStream(w io.Writer) error {
params := arrayToParamsMap(rq.params)
buf := bytes.NewBuffer(nil)
doc := NewEmptyDocument()
doc.SetField("parameters", params)
if err := GetDefaultRecordSerializer().ToStream(buf, doc); err != nil {
return err
}
bw := rw.NewWriter(w)
bw.WriteString(rq.text)
if params == nil || reflect.ValueOf(params).Len() == 0 {
bw.WriteBool(false) // simple params are absent
bw.WriteBool(false) // composite keys are absent
return bw.Err()
}
bw.WriteBool(true) // simple params
bw.WriteBytes(buf.Bytes())
// TODO: check for composite keys
bw.WriteBool(false) // composite keys
return bw.Err()
}
// FunctionCommand is a command to call server-side function.
//
// OCommandFunction in Java world.
type FunctionCommand struct {
textReqCommand
}
// NewFunctionCommand creates a new call request to server-side function with given name and arguments.
func NewFunctionCommand(name string, params ...interface{}) FunctionCommand {
return FunctionCommand{
textReqCommand: newTextReqCommand(name, params),
}
}
// GetClassName returns Java class name
func (rq FunctionCommand) GetClassName() string {
return "com.orientechnologies.orient.core.command.script.OCommandFunction"
}
// ScriptCommand is a way to execute batch-like commands.
//
// OCommandScript in Java world.
type ScriptCommand struct {
lang string
textReqCommand
}
// NewScriptCommand creates a new script request written in a given language (SQL/JS/Groovy/...),
// with specified body code and params.
//
// Example:
//
// NewScriptCommand(LangJS, `var out = db.command("SELECT FROM V"); out`)
//
func NewScriptCommand(lang ScriptLang, body string, params ...interface{}) ScriptCommand {
return ScriptCommand{
lang: string(lang),
textReqCommand: newTextReqCommand(body, params),
}
}
// GetClassName returns Java class name
func (rq ScriptCommand) GetClassName() string { return "s" }
// ToStream serializes command to specified Writer
func (rq ScriptCommand) ToStream(w io.Writer) error {
if err := rw.NewWriter(w).WriteString(rq.lang); err != nil {
return err
}
return rq.textReqCommand.ToStream(w)
}
// SQLCommand is a non-SELECT sql command (EXEC/INSERT/DELETE).
//
// OCommandSQL in Java world.
type SQLCommand struct {
textReqCommand
}
// NewSQLCommand creates a new SQL command request with given params.
//
// Example:
//
// NewSQLCommand("INSERT INTO People (id, name) VALUES (?, ?)", id, name)
//
func NewSQLCommand(sql string, params ...interface{}) SQLCommand {
return SQLCommand{newTextReqCommand(sql, params)}
}
// GetClassName returns Java class name
func (rq SQLCommand) GetClassName() string { return "c" }
// SQLQuery is a SELECT-like SQL command.
//
// OSQLQuery in Java world.
type SQLQuery struct {
text string
limit int
plan string
params []interface{}
}
// NewSQLQuery creates a new SQL query with given params.
//
// Example:
//
// NewSQLQuery("SELECT FROM V WHERE id = ?", id)
//
func NewSQLQuery(sql string, params ...interface{}) SQLQuery {
return SQLQuery{text: sql, params: params, limit: -1}
}
// GetText returns query text
func (rq SQLQuery) GetText() string { return rq.text }
// GetClassName returns Java class name
func (rq SQLQuery) GetClassName() string { return "q" }
// Limit sets a query record limit
func (rq SQLQuery) Limit(n int) SQLQuery {
rq.limit = n
return rq
}
// FetchPlan sets a query fetch plan
func (rq SQLQuery) FetchPlan(plan FetchPlan) SQLQuery {
rq.plan = string(plan)
return rq
}
// ToStream serializes command to specified Writer
func (rq SQLQuery) ToStream(w io.Writer) error {
sparams, err := rq.serializeQueryParameters(rq.params)
if err != nil {
return err
}
bw := rw.NewWriter(w)
bw.WriteString(rq.text)
bw.WriteInt(int32(rq.limit))
bw.WriteString(rq.plan)
bw.WriteBytes(sparams)
return bw.Err()
}
func (rq SQLQuery) serializeQueryParameters(params []interface{}) ([]byte, error) {
if len(params) == 0 {
return nil, nil
}
doc := NewEmptyDocument()
doc.SetField("params", arrayToParamsMap(params)) // TODO: convertToRIDsIfPossible
buf := bytes.NewBuffer(nil)
if err := GetDefaultRecordSerializer().ToStream(buf, doc); err != nil {
return nil, err
}
return buf.Bytes(), nil
}