git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/object/search.go (about) 1 package object 2 3 import ( 4 "encoding/json" 5 "strconv" 6 7 v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" 8 cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" 9 oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" 10 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" 11 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version" 12 ) 13 14 // SearchMatchType indicates match operation on specified header. 15 type SearchMatchType uint32 16 17 const ( 18 MatchUnknown SearchMatchType = iota 19 MatchStringEqual 20 MatchStringNotEqual 21 MatchNotPresent 22 MatchCommonPrefix 23 ) 24 25 func (m SearchMatchType) ToV2() v2object.MatchType { 26 switch m { 27 case MatchStringEqual: 28 return v2object.MatchStringEqual 29 case MatchStringNotEqual: 30 return v2object.MatchStringNotEqual 31 case MatchNotPresent: 32 return v2object.MatchNotPresent 33 case MatchCommonPrefix: 34 return v2object.MatchCommonPrefix 35 default: 36 return v2object.MatchUnknown 37 } 38 } 39 40 func SearchMatchFromV2(t v2object.MatchType) (m SearchMatchType) { 41 switch t { 42 case v2object.MatchStringEqual: 43 m = MatchStringEqual 44 case v2object.MatchStringNotEqual: 45 m = MatchStringNotEqual 46 case v2object.MatchNotPresent: 47 m = MatchNotPresent 48 case v2object.MatchCommonPrefix: 49 m = MatchCommonPrefix 50 default: 51 m = MatchUnknown 52 } 53 54 return m 55 } 56 57 // String returns string representation of SearchMatchType. 58 // 59 // String mapping: 60 // - MatchStringEqual: STRING_EQUAL; 61 // - MatchStringNotEqual: STRING_NOT_EQUAL; 62 // - MatchNotPresent: NOT_PRESENT; 63 // - MatchCommonPrefix: COMMON_PREFIX; 64 // - MatchUnknown, default: MATCH_TYPE_UNSPECIFIED. 65 func (m SearchMatchType) String() string { 66 return m.ToV2().String() 67 } 68 69 // FromString parses SearchMatchType from a string representation. 70 // It is a reverse action to String(). 71 // 72 // Returns true if s was parsed successfully. 73 func (m *SearchMatchType) FromString(s string) bool { 74 var g v2object.MatchType 75 76 ok := g.FromString(s) 77 78 if ok { 79 *m = SearchMatchFromV2(g) 80 } 81 82 return ok 83 } 84 85 type stringEncoder interface { 86 EncodeToString() string 87 } 88 89 type SearchFilter struct { 90 header filterKey 91 value stringEncoder 92 op SearchMatchType 93 } 94 95 type staticStringer string 96 97 type filterKey struct { 98 typ filterKeyType 99 100 str string 101 } 102 103 // enumeration of reserved filter keys. 104 type filterKeyType int 105 106 type SearchFilters []SearchFilter 107 108 const ( 109 _ filterKeyType = iota 110 fKeyVersion 111 fKeyObjectID 112 fKeyContainerID 113 fKeyOwnerID 114 fKeyCreationEpoch 115 fKeyPayloadLength 116 fKeyPayloadHash 117 fKeyType 118 fKeyHomomorphicHash 119 fKeyParent 120 fKeySplitID 121 fKeyPropRoot 122 fKeyPropPhy 123 fKeyECParent 124 ) 125 126 func (k filterKey) String() string { 127 switch k.typ { 128 default: 129 return k.str 130 case fKeyVersion: 131 return v2object.FilterHeaderVersion 132 case fKeyObjectID: 133 return v2object.FilterHeaderObjectID 134 case fKeyContainerID: 135 return v2object.FilterHeaderContainerID 136 case fKeyOwnerID: 137 return v2object.FilterHeaderOwnerID 138 case fKeyCreationEpoch: 139 return v2object.FilterHeaderCreationEpoch 140 case fKeyPayloadLength: 141 return v2object.FilterHeaderPayloadLength 142 case fKeyPayloadHash: 143 return v2object.FilterHeaderPayloadHash 144 case fKeyType: 145 return v2object.FilterHeaderObjectType 146 case fKeyHomomorphicHash: 147 return v2object.FilterHeaderHomomorphicHash 148 case fKeyParent: 149 return v2object.FilterHeaderParent 150 case fKeySplitID: 151 return v2object.FilterHeaderSplitID 152 case fKeyPropRoot: 153 return v2object.FilterPropertyRoot 154 case fKeyPropPhy: 155 return v2object.FilterPropertyPhy 156 case fKeyECParent: 157 return v2object.FilterHeaderECParent 158 } 159 } 160 161 func (s staticStringer) EncodeToString() string { 162 return string(s) 163 } 164 165 func (f *SearchFilter) Header() string { 166 return f.header.String() 167 } 168 169 func (f *SearchFilter) Value() string { 170 return f.value.EncodeToString() 171 } 172 173 func (f *SearchFilter) Operation() SearchMatchType { 174 return f.op 175 } 176 177 func NewSearchFilters() SearchFilters { 178 return SearchFilters{} 179 } 180 181 func NewSearchFiltersFromV2(v2 []v2object.SearchFilter) SearchFilters { 182 filters := make(SearchFilters, 0, len(v2)) 183 184 for i := range v2 { 185 filters.AddFilter( 186 v2[i].GetKey(), 187 v2[i].GetValue(), 188 SearchMatchFromV2(v2[i].GetMatchType()), 189 ) 190 } 191 192 return filters 193 } 194 195 func (f *SearchFilters) addFilter(op SearchMatchType, keyTyp filterKeyType, key string, val stringEncoder) { 196 if *f == nil { 197 *f = make(SearchFilters, 0, 1) 198 } 199 200 *f = append(*f, SearchFilter{ 201 header: filterKey{ 202 typ: keyTyp, 203 str: key, 204 }, 205 value: val, 206 op: op, 207 }) 208 } 209 210 func (f *SearchFilters) AddFilter(header, value string, op SearchMatchType) { 211 f.addFilter(op, 0, header, staticStringer(value)) 212 } 213 214 func (f *SearchFilters) addReservedFilter(op SearchMatchType, keyTyp filterKeyType, val stringEncoder) { 215 f.addFilter(op, keyTyp, "", val) 216 } 217 218 // addFlagFilters adds filters that works like flags: they don't need to have 219 // specific match type or value. They processed by FrostFS nodes by the fact 220 // of presence in search query. E.g.: PHY, ROOT. 221 func (f *SearchFilters) addFlagFilter(keyTyp filterKeyType) { 222 f.addFilter(MatchUnknown, keyTyp, "", staticStringer("")) 223 } 224 225 func (f *SearchFilters) AddObjectVersionFilter(op SearchMatchType, v version.Version) { 226 f.addReservedFilter(op, fKeyVersion, staticStringer(version.EncodeToString(v))) 227 } 228 229 func (f *SearchFilters) AddObjectContainerIDFilter(m SearchMatchType, id cid.ID) { 230 f.addReservedFilter(m, fKeyContainerID, id) 231 } 232 233 func (f *SearchFilters) AddObjectOwnerIDFilter(m SearchMatchType, id user.ID) { 234 f.addReservedFilter(m, fKeyOwnerID, id) 235 } 236 237 func (f *SearchFilters) AddNotificationEpochFilter(epoch uint64) { 238 f.addFilter(MatchStringEqual, 0, v2object.SysAttributeTickEpoch, staticStringer(strconv.FormatUint(epoch, 10))) 239 } 240 241 func (f SearchFilters) ToV2() []v2object.SearchFilter { 242 result := make([]v2object.SearchFilter, len(f)) 243 244 for i := range f { 245 result[i].SetKey(f[i].header.String()) 246 result[i].SetValue(f[i].value.EncodeToString()) 247 result[i].SetMatchType(f[i].op.ToV2()) 248 } 249 250 return result 251 } 252 253 func (f *SearchFilters) addRootFilter() { 254 f.addFlagFilter(fKeyPropRoot) 255 } 256 257 func (f *SearchFilters) AddRootFilter() { 258 f.addRootFilter() 259 } 260 261 func (f *SearchFilters) addPhyFilter() { 262 f.addFlagFilter(fKeyPropPhy) 263 } 264 265 func (f *SearchFilters) AddPhyFilter() { 266 f.addPhyFilter() 267 } 268 269 // AddParentIDFilter adds filter by parent identifier. 270 func (f *SearchFilters) AddParentIDFilter(m SearchMatchType, id oid.ID) { 271 f.addReservedFilter(m, fKeyParent, id) 272 } 273 274 // AddObjectIDFilter adds filter by object identifier. 275 func (f *SearchFilters) AddObjectIDFilter(m SearchMatchType, id oid.ID) { 276 f.addReservedFilter(m, fKeyObjectID, id) 277 } 278 279 func (f *SearchFilters) AddSplitIDFilter(m SearchMatchType, id *SplitID) { 280 f.addReservedFilter(m, fKeySplitID, staticStringer(id.String())) 281 } 282 283 func (f *SearchFilters) AddECParentFilter(m SearchMatchType, parentID oid.ID) { 284 f.addReservedFilter(m, fKeyECParent, staticStringer(parentID.String())) 285 } 286 287 // AddTypeFilter adds filter by object type. 288 func (f *SearchFilters) AddTypeFilter(m SearchMatchType, typ Type) { 289 f.addReservedFilter(m, fKeyType, staticStringer(typ.String())) 290 } 291 292 // MarshalJSON encodes SearchFilters to protobuf JSON format. 293 func (f *SearchFilters) MarshalJSON() ([]byte, error) { 294 return json.Marshal(f.ToV2()) 295 } 296 297 // UnmarshalJSON decodes SearchFilters from protobuf JSON format. 298 func (f *SearchFilters) UnmarshalJSON(data []byte) error { 299 var fsV2 []v2object.SearchFilter 300 301 if err := json.Unmarshal(data, &fsV2); err != nil { 302 return err 303 } 304 305 *f = NewSearchFiltersFromV2(fsV2) 306 307 return nil 308 }