github.com/sacloud/iaas-api-go@v1.12.0/search/filter.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 search 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "net/url" 21 "time" 22 ) 23 24 // Filter 検索系APIでの検索条件 25 // 26 // Note: libsacloudではリクエスト時に`X-Sakura-Bigint-As-Int`ヘッダを指定することで 27 // 文字列で表されているBitintをintとして取得している。 28 // このため、libsacloud側では数値型に見える項目でもさくらのクラウド側では文字列となっている場合がある。 29 // これらの項目ではOpEqual以外の演算子は利用できない。 30 // また、これらの項目でスカラ値を検索条件に与えた場合は部分一致ではなく完全一致となるため注意。 31 type Filter map[FilterKey]interface{} 32 33 // MarshalJSON 検索系APIコール時のGETパラメータを出力するためのjson.Marshaler実装 34 func (f Filter) MarshalJSON() ([]byte, error) { 35 result := make(map[string]interface{}) 36 37 for key, expression := range f { 38 if expression == nil { 39 continue 40 } 41 42 exp := expression 43 switch key.Op { 44 case OpEqual: 45 if _, ok := exp.(*EqualExpression); !ok { 46 exp = OrEqual(expression) 47 } 48 default: 49 v, err := convertToValidFilterCondition(exp) 50 if err != nil { 51 return nil, err 52 } 53 exp = v 54 } 55 56 result[key.String()] = exp 57 } 58 59 return json.Marshal(result) 60 } 61 62 func convertToValidFilterCondition(v interface{}) (string, error) { 63 switch v := v.(type) { 64 case time.Time: 65 return v.Format(time.RFC3339), nil 66 case string: 67 return escapeFilterString(v), nil 68 case int, int8, int16, int32, int64, 69 uint, uint8, uint16, uint32, uint64, 70 float32, float64: 71 return fmt.Sprintf("%v", v), nil 72 } 73 data, err := json.Marshal(v) 74 if err != nil { 75 return "", err 76 } 77 return string(data), nil 78 } 79 80 func escapeFilterString(s string) string { 81 // HACK さくらのクラウド側でqueryStringでの+エスケープに対応していないため、 82 // %20にエスケープされるurl.Pathを利用する。 83 // http://qiita.com/shibukawa/items/c0730092371c0e243f62 84 // 85 // UPDATE: https://github.com/sacloud/libsacloud/issues/657#issuecomment-733467472 86 // (&url.URL{Path:s}).String()だと、MACAddressが"./00:00:5E:00:53:00"のようになってしまう。 87 // このためurl.PathEscapeを利用する。 88 return url.PathEscape(s) 89 }