github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/services/documents/element.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package documents 19 20 import ( 21 "fmt" 22 "reflect" 23 "sort" 24 ) 25 26 func NewElement(path string, name string, typ string, format string, title string, description string) Element { 27 return Element{ 28 Nil: false, 29 Path: path, 30 Name: name, 31 Title: title, 32 Description: description, 33 Type: typ, 34 Format: format, 35 Enums: make([]string, 0, 1), 36 Required: false, 37 Validation: Validation{}, 38 Properties: make(Properties, 0, 1), 39 Additional: false, 40 Deprecated: false, 41 } 42 } 43 44 func String() Element { 45 return NewElement("_", "string", "string", "", "String", "String") 46 } 47 48 func Password() Element { 49 return NewElement("_", "password", "string", "password", "Password", "Bcrypt hash type") 50 } 51 52 func Bytes() Element { 53 return NewElement("_", "bytes", "string", "byte", "Bytes", "Base64 string") 54 } 55 56 func Bool() Element { 57 return NewElement("_", "bool", "boolean", "", "Bool", "Bool") 58 } 59 60 func Int() Element { 61 return Int64() 62 } 63 64 func Int32() Element { 65 return NewElement("_", "int32", "integer", "int32", "Int32", "Int32") 66 } 67 68 func Int64() Element { 69 return NewElement("_", "int64", "integer", "int64", "Int64", "Int64") 70 } 71 72 func Uint() Element { 73 return Uint64() 74 } 75 76 func Uint8() Element { 77 return NewElement("_", "uint8", "integer", "int32", "Uint8", "Uint8") 78 } 79 80 func Uint32() Element { 81 return NewElement("_", "uint32", "integer", "int32", "Uint32", "Uint32") 82 } 83 84 func Uint64() Element { 85 return NewElement("_", "uint64", "integer", "int64", "Uint64", "Uint64") 86 } 87 88 func Float32() Element { 89 return NewElement("_", "float32", "number", "float", "Float", "Float") 90 } 91 92 func Float64() Element { 93 return NewElement("_", "float64", "number", "double", "Double", "Double") 94 } 95 96 func Complex64() Element { 97 return NewElement("_", "complex64", "string", "", "Complex64", "Complex64 format, such as 15+3i") 98 } 99 100 func Complex128() Element { 101 return NewElement("_", "complex128", "string", "", "Complex128", "Complex128 format, such as 15+3i") 102 } 103 104 func Date() Element { 105 return NewElement("_", "date", "string", "date", "Date", "Date") 106 } 107 108 func Time() Element { 109 return NewElement("_", "time", "string", "", "Time", "Time format, such as 15:04:05") 110 } 111 112 func Duration() Element { 113 return NewElement("_", "duration", "integer", "int64", "Duration", "Nanosecond") 114 } 115 116 func DateTime() Element { 117 return NewElement("_", "datetime", "string", "2006-01-02T15:04:05Z07:00", "Datetime", "RFC3339 format, such as 2022-01-10T19:13:07+08:00") 118 } 119 120 func Any() Element { 121 return NewElement("_", "any", "object", "", "Any", "Any kind object") 122 } 123 124 func Unknown() Element { 125 return NewElement("_", "unknown", "object", "", "Unknown", "unknown object") 126 } 127 128 func Struct(path string, name string) Element { 129 return NewElement(path, name, "object", "", "", "") 130 } 131 132 func Ident(path string, name string, target Element) Element { 133 rs := reflect.ValueOf(target) 134 rv := reflect.New(rs.Type()) 135 rv.Elem().Set(rs) 136 v := rv.Elem().Interface().(Element) 137 v.Path = path 138 v.Name = name 139 v.Title = "" 140 v.Description = "" 141 return v 142 } 143 144 func Ref(path string, name string) Element { 145 return NewElement(path, name, "ref", "", "", "") 146 } 147 148 func JsonRaw() Element { 149 v := NewElement("github.com/aacfactory/json", "RawMessage", "object", "", "JsonRawMessage", "Json Raw Message") 150 v.Additional = true 151 v = v.AddProperty("", Empty()) 152 return v 153 } 154 155 func Nil() Element { 156 return Element{ 157 Nil: true, 158 } 159 } 160 161 func Empty() Element { 162 return NewElement("github.com/aacfactory/fns/services", "Empty", "object", "", "Empty", "Empty Object") 163 } 164 165 func Array(item Element) Element { 166 v := NewElement("", "", "array", "", "", "") 167 v = v.AddProperty("", item) 168 return v 169 } 170 171 func Map(value Element) Element { 172 v := NewElement("", "", "object", "", "", "") 173 v.Additional = true 174 v = v.AddProperty("", value) 175 return v 176 } 177 178 func NewElementValidation(name string, i18ns ...string) (v *ElementValidation) { 179 v = &ElementValidation{ 180 Name: name, 181 I18n: make(map[string]string), 182 } 183 if i18ns == nil || len(i18ns) == 0 || len(i18ns)%2 != 0 { 184 return 185 } 186 for i := 0; i < len(i18ns); i++ { 187 key := i18ns[i] 188 val := i18ns[i+1] 189 v.I18n[key] = val 190 i++ 191 } 192 return 193 } 194 195 type ElementValidation struct { 196 Name string `json:"name,omitempty" avro:"name"` 197 I18n map[string]string `json:"i18n,omitempty" avro:"i18N"` 198 } 199 200 type Element struct { 201 Nil bool `json:"non" avro:"nil"` 202 Path string `json:"path,omitempty" avro:"path"` 203 Name string `json:"name,omitempty" avro:"name"` 204 Title string `json:"title,omitempty" avro:"title"` 205 Description string `json:"description,omitempty" avro:"description"` 206 Type string `json:"type,omitempty" avro:"type"` 207 Format string `json:"format,omitempty" avro:"format"` 208 Enums []string `json:"enums,omitempty" avro:"enums"` 209 Required bool `json:"required,omitempty" avro:"required"` 210 Validation Validation `json:"validation,omitempty" avro:"validation"` 211 Properties Properties `json:"properties,omitempty" avro:"properties"` 212 Additional bool `json:"additional,omitempty" avro:"additional"` 213 Deprecated bool `json:"deprecated,omitempty" avro:"deprecated"` 214 } 215 216 func (element Element) Exist() bool { 217 if element.Path == "_" && element.Name == "unknown" { 218 return false 219 } 220 return !element.Nil || element.Type != "" 221 } 222 223 func (element Element) SetPath(path string) Element { 224 element.Path = path 225 return element 226 } 227 228 func (element Element) SetName(name string) Element { 229 element.Name = name 230 return element 231 } 232 233 func (element Element) AsRequired() Element { 234 element.Required = true 235 return element 236 } 237 238 func (element Element) AsDeprecated() Element { 239 element.Deprecated = true 240 return element 241 } 242 243 func (element Element) AsPassword() Element { 244 element.Format = "password" 245 return element 246 } 247 248 func (element Element) SetValidation(validation Validation) Element { 249 element.Validation = validation 250 return element 251 } 252 253 func (element Element) SetTitle(title string) Element { 254 element.Title = title 255 return element 256 } 257 258 func (element Element) SetDescription(description string) Element { 259 element.Description = description 260 return element 261 } 262 263 func (element Element) SetFormat(format string) Element { 264 element.Format = format 265 return element 266 } 267 268 func (element Element) AddEnum(v ...string) Element { 269 element.Enums = append(element.Enums, v...) 270 return element 271 } 272 273 func (element Element) IsEmpty() (ok bool) { 274 ok = element.IsObject() && len(element.Properties) == 0 275 return 276 } 277 278 func (element Element) IsBuiltin() (ok bool) { 279 ok = element.Path == "_" 280 return 281 } 282 283 func (element Element) IsObject() (ok bool) { 284 ok = element.Type == "object" 285 return 286 } 287 288 func (element Element) IsArray() (ok bool) { 289 ok = element.Type == "array" 290 return 291 } 292 293 func (element Element) IsRef() (ok bool) { 294 ok = element.Type == "ref" 295 return 296 } 297 298 func (element Element) IsAny() (ok bool) { 299 ok = element.Name == "any" 300 return 301 } 302 303 func (element Element) IsAdditional() (ok bool) { 304 ok = element.IsObject() && element.Additional 305 return 306 } 307 308 func (element Element) AddProperty(name string, prop Element) Element { 309 if element.IsObject() || element.IsArray() || element.IsAdditional() { 310 element.Properties = element.Properties.Add(name, prop) 311 } 312 return element 313 } 314 315 func (element Element) GetItem() (v Element, has bool) { 316 p, exist := element.Properties.Get("") 317 if exist { 318 v = p.Element 319 has = true 320 return 321 } 322 return 323 } 324 325 func (element Element) Key() (v string) { 326 v = fmt.Sprintf("%s.%s", element.Path, element.Name) 327 return 328 } 329 330 type Elements []Element 331 332 func (elements Elements) Len() int { 333 return len(elements) 334 } 335 336 func (elements Elements) Less(i, j int) bool { 337 return elements[i].Key() < elements[j].Key() 338 } 339 340 func (elements Elements) Swap(i, j int) { 341 elements[i], elements[j] = elements[j], elements[i] 342 return 343 } 344 345 func (elements Elements) Add(element Element) Elements { 346 if !element.Exist() { 347 return elements 348 } 349 for _, p := range elements { 350 if p.Key() == element.Key() { 351 return elements 352 } 353 } 354 n := elements 355 n = append(elements, element) 356 sort.Sort(n) 357 return n 358 } 359 360 // unpack 361 // []{ref, unpacked_prop..., unpacked_self} 362 func unpack(element Element) (elements []Element) { 363 if element.IsBuiltin() || element.IsRef() { 364 elements = append(elements, element) 365 return 366 } 367 if element.IsObject() { 368 // map 369 if element.IsAdditional() { 370 item, hasItem := element.GetItem() 371 if hasItem { 372 unpacks := unpack(item) 373 element.Properties = make(Properties, 0, 1) 374 element = element.AddProperty("", unpacks[0]) 375 elements = append(elements, element) 376 if len(unpacks) > 1 { 377 elements = append(elements, unpacks[1:]...) 378 } 379 } 380 return 381 } 382 // object 383 // add ref 384 elements = append(elements, Ref(element.Path, element.Name)) 385 // properties 386 for i, property := range element.Properties { 387 unpacks := unpack(property.Element) 388 element.Properties[i].Element = unpacks[0] 389 if len(unpacks) > 1 { 390 elements = append(elements, unpacks[1:]...) 391 } 392 } 393 elements = append(elements, element) 394 return 395 } 396 // array 397 if element.IsArray() { 398 if element.Path != "" { 399 elements = append(elements, Ref(element.Path, element.Name)) 400 } 401 item, hasItem := element.GetItem() 402 if hasItem { 403 unpacks := unpack(item) 404 if len(unpacks) > 1 { 405 elements = append(elements, unpacks[1:]...) 406 } 407 element.Properties = make(Properties, 0, 1) 408 element = element.AddProperty("", unpacks[0]) 409 elements = append(elements, element) 410 } 411 return 412 } 413 return 414 }