github.com/sacloud/iaas-api-go@v1.12.0/internal/dsl/operation.go (about) 1 // Copyright 2022-2023 The sacloud/iaas-api-go Authors 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 dsl 16 17 import ( 18 "fmt" 19 "strings" 20 ) 21 22 // Operations リソースへの操作(スライス) 23 type Operations []*Operation 24 25 // Operation リソースへの操作 26 type Operation struct { 27 ResourceName string 28 Name string // 操作名、メソッド名となる 29 Method string // HTTPリクエストメソッド GET/POST/PUT/DELETE 30 PathFormat string // パスのフォーマット、省略した場合はDefaultPathFormatが設定される 31 Arguments Arguments // 引数の定義 32 Results Results // レスポンス 33 RequestEnvelope *EnvelopeType // リクエスト時のエンベロープ 34 ResponseEnvelope *EnvelopeType // レスポンス時のエンベロープ 35 UseWrappedResult bool // trueの場合APIからの戻り値としてラッパー型(xxxResult)を返す 36 LockLevel LockLevel // APIコール時のロックレベル 37 LockKeyCustomFormat string // ロックキーのgoテンプレートフォーマット(PathFormatと同じパラメータが利用可能) 38 } 39 40 // LockKeyFormat ロックキーのフォーマット、ロックなしの場合空になる 41 func (o *Operation) LockKeyFormat() string { 42 if o.LockLevel == LockLevelNone { 43 return "" 44 } 45 if o.LockKeyCustomFormat != "" { 46 return o.LockKeyCustomFormat 47 } 48 switch o.LockLevel { 49 case LockLevelResource: 50 return o.GetPathFormat() 51 case LockLevelAPI: 52 return fmt.Sprintf("%s.%s.%s", o.ResourceName, o.Name, o.Method) 53 case LockLevelGlobal: 54 return "GlobalLock" 55 default: 56 return "" 57 } 58 } 59 60 // GetPathFormat パスのフォーマット 61 func (o *Operation) GetPathFormat() string { 62 if o.PathFormat != "" { 63 return o.PathFormat 64 } 65 return DefaultPathFormat 66 } 67 68 // ImportStatements コード生成時に利用するimport文を生成する 69 func (o *Operation) ImportStatements(additionalImports ...string) []string { 70 ss := wrapByDoubleQuote(additionalImports...) 71 72 for _, arg := range o.Arguments { 73 ss = append(ss, arg.ImportStatements()...) 74 } 75 76 for _, m := range o.Results { 77 ss = append(ss, m.ImportStatements()...) 78 } 79 80 return uniqStrings(ss) 81 } 82 83 // MethodName コード生成時に利用する、メソッド名を出力する 84 func (o *Operation) MethodName() string { 85 return o.Name 86 } 87 88 // ReturnErrorStatement コード生成時に利用する、エラーをreturnする文を生成する 89 func (o *Operation) ReturnErrorStatement() string { 90 if o.HasResults() { 91 if o.UseWrappedResult { 92 return "nil, err" 93 } 94 var ret string 95 for range o.Results { 96 ret += "nil," 97 } 98 ret += "err" 99 return ret 100 } 101 return "err" 102 } 103 104 // ReturnStatement コード生成時に利用するreturn部分を生成する 105 func (o *Operation) ReturnStatement() string { 106 if !o.HasResults() { 107 return "err" 108 } 109 if o.UseWrappedResult { 110 return "results, err" 111 } 112 var ret string 113 for _, r := range o.Results { 114 ret += fmt.Sprintf("results.%s,", r.DestField) 115 } 116 ret += "nil" 117 return ret 118 } 119 120 // ResultsStatement 戻り値定義部のソースを出力 121 func (o *Operation) ResultsStatement() string { 122 if !o.HasResults() { 123 return "error" 124 } 125 if o.UseWrappedResult { 126 return fmt.Sprintf("(%s, error)", o.resultType().GoTypeSourceCode()) 127 } 128 var ret string 129 for _, r := range o.Results { 130 ret += r.GoTypeSourceCode() + "," 131 } 132 return fmt.Sprintf("(%s error)", ret) 133 } 134 135 // ResultsTypeInfo 戻り値の型情報(error型を含まない) 136 func (o *Operation) ResultsTypeInfo() []*ResultTypeInfo { 137 var info []*ResultTypeInfo 138 if !o.HasResults() { 139 return info 140 } 141 if o.UseWrappedResult { 142 info = append(info, &ResultTypeInfo{ 143 VarName: "result", 144 FieldName: "Result", 145 Type: o.resultType().Type(), 146 }) 147 return info 148 } 149 for _, r := range o.Results { 150 info = append(info, &ResultTypeInfo{ 151 VarName: "result" + r.DestField, 152 FieldName: r.DestField, 153 Type: r.Type(), 154 }) 155 } 156 return info 157 } 158 159 // ResultsAssignStatement API戻り値を変数にアサインする場合の変数部分のソースを出力、主にtraceで利用する 160 func (o *Operation) ResultsAssignStatement() string { 161 if !o.HasResults() { 162 return "err" 163 } 164 if o.UseWrappedResult { 165 return "result, err" 166 } 167 var ret string 168 for _, r := range o.Results { 169 ret += fmt.Sprintf(",result%s", r.DestField) 170 } 171 return fmt.Sprintf("%s, err", ret) 172 } 173 174 // RequestEnvelopeStructName エンベロープのstruct名(camel-case) 175 func (o *Operation) RequestEnvelopeStructName() string { 176 return fmt.Sprintf("%s%sRequestEnvelope", firstRuneToLower(o.ResourceName), o.Name) 177 } 178 179 // ResponseEnvelopeStructName エンベロープのstruct名(camel-case) 180 func (o *Operation) ResponseEnvelopeStructName() string { 181 return fmt.Sprintf("%s%sResponseEnvelope", firstRuneToLower(o.ResourceName), o.Name) 182 } 183 184 // ResultTypeName API戻り値の型名 185 func (o *Operation) ResultTypeName() string { 186 if o.UseWrappedResult { 187 return o.resultType().GoType() 188 } 189 return firstRuneToLower(o.resultType().GoType()) 190 } 191 192 // HasResults 戻り値が定義されているかを取得 193 func (o *Operation) HasResults() bool { 194 return len(o.Results) > 0 195 } 196 197 // StubFieldDefines スタブ生成時のフィールド定義文を全フィールド分出力 198 func (o *Operation) StubFieldDefines() []string { 199 if !o.HasResults() { 200 return nil 201 } 202 if o.UseWrappedResult { 203 return []string{fmt.Sprintf("Values %s", o.resultType().GoTypeSourceCode())} 204 } 205 var rets []string 206 for _, r := range o.Results { 207 rets = append(rets, fmt.Sprintf("%s %s", r.DestField, r.GoTypeSourceCode())) 208 } 209 return rets 210 } 211 212 // StubReturnStatement スタブ生成時のreturn文 213 func (o *Operation) StubReturnStatement(receiverName string) string { 214 if !o.HasResults() { 215 return fmt.Sprintf("return %s.%sStubResult.Err", receiverName, o.MethodName()) 216 } 217 var rets []string 218 if o.UseWrappedResult { 219 rets = append(rets, fmt.Sprintf("%s.%sStubResult.Values", receiverName, o.MethodName())) 220 } else { 221 for _, r := range o.Results { 222 rets = append(rets, fmt.Sprintf("%s.%sStubResult.%s", receiverName, o.MethodName(), r.DestField)) 223 } 224 } 225 226 rets = append(rets, fmt.Sprintf("%s.%sStubResult.Err", receiverName, o.MethodName())) 227 return fmt.Sprintf("return %s", strings.Join(rets, ",")) 228 } 229 230 // Models オペレーション配下の(Nameで)ユニークなモデル一覧を取得 231 func (o *Operation) Models() Models { 232 ms := o.Results.Models() 233 for _, arg := range o.Arguments { 234 m, ok := arg.Type.(*Model) 235 if ok { 236 ms = append(ms, m) 237 ms = append(ms, m.FieldModels()...) 238 } 239 } 240 return ms.UniqByName() 241 } 242 243 // HasRequestEnvelope リクエストエンベロープが設定されているか 244 func (o *Operation) HasRequestEnvelope() bool { 245 return o.RequestEnvelope != nil 246 } 247 248 // RequestPayloads リクエストペイロードを取得 249 func (o *Operation) RequestPayloads() []*EnvelopePayloadDesc { 250 if o.HasRequestEnvelope() { 251 return o.RequestEnvelope.Payloads 252 } 253 return nil 254 } 255 256 // HasResponseEnvelope レスポンスエンベロープが設定されているか 257 func (o *Operation) HasResponseEnvelope() bool { 258 return o.ResponseEnvelope != nil 259 } 260 261 // ResponsePayloads レスポンスペイロードを取得 262 func (o *Operation) ResponsePayloads() []*EnvelopePayloadDesc { 263 if o.HasResponseEnvelope() { 264 return o.ResponseEnvelope.Payloads 265 } 266 return nil 267 } 268 269 // IsRequestSingular リクエストが単数系か 270 func (o *Operation) IsRequestSingular() bool { 271 if o.HasRequestEnvelope() { 272 return o.RequestEnvelope.IsSingular() 273 } 274 return false 275 } 276 277 // IsRequestPlural リクエストが複数形か 278 func (o *Operation) IsRequestPlural() bool { 279 if o.HasRequestEnvelope() { 280 return o.RequestEnvelope.IsPlural() 281 } 282 return false 283 } 284 285 // IsResponseSingular レスポンスが単数系か 286 func (o *Operation) IsResponseSingular() bool { 287 if o.HasResponseEnvelope() { 288 return o.ResponseEnvelope.IsSingular() 289 } 290 return false 291 } 292 293 // IsResponsePlural レスポンスが複数形か 294 func (o *Operation) IsResponsePlural() bool { 295 if o.HasResponseEnvelope() { 296 return o.ResponseEnvelope.IsPlural() 297 } 298 return false 299 } 300 301 func (o *Operation) resultType() *ResultType { 302 return &ResultType{ 303 resourceName: o.ResourceName, 304 operation: o, 305 results: o.Results, 306 } 307 }