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  }