models

package
v0.0.0-...-2684b26 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 2, 2024 License: MIT Imports: 10 Imported by: 0

Documentation

Index

Constants

View Source
const DefaultModelDocsTemplate = `// Default generated models package docs
// (at least one file is necessary in a models package)
package models
`
View Source
const GongAstTemplate = `// generated code - do not edit
package models

import (
	"errors"
	"go/ast"
	"go/doc/comment"
	"go/parser"
	"go/token"
	"log"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

var dummy_strconv_import strconv.NumError
var dummy_time_import time.Time

// swagger:ignore
type GONG__ExpressionType string

const (
	GONG__STRUCT_INSTANCE      GONG__ExpressionType = "STRUCT_INSTANCE"
	GONG__FIELD_OR_CONST_VALUE GONG__ExpressionType = "FIELD_OR_CONST_VALUE"
	GONG__FIELD_VALUE          GONG__ExpressionType = "FIELD_VALUE"
	GONG__ENUM_CAST_INT        GONG__ExpressionType = "ENUM_CAST_INT"
	GONG__ENUM_CAST_STRING     GONG__ExpressionType = "ENUM_CAST_STRING"
	GONG__IDENTIFIER_CONST     GONG__ExpressionType = "IDENTIFIER_CONST"
)

// ParseAstFile Parse pathToFile and stages all instances
// declared in the file
func ParseAstFile(stage *StageStruct, pathToFile string) error {

	fileOfInterest, err := filepath.Abs(pathToFile)
	if err != nil {
		return errors.New("Path does not exist %s ;" + fileOfInterest)
	}

	fset := token.NewFileSet()
	// startParser := time.Now()
	inFile, errParser := parser.ParseFile(fset, fileOfInterest, nil, parser.ParseComments)
	// log.Printf("Parser took %s", time.Since(startParser))

	if errParser != nil {
		return errors.New("Unable to parser " + errParser.Error())
	}

	return ParseAstFileFromAst(stage, inFile, fset)
}

// ParseAstFile Parse pathToFile and stages all instances
// declared in the file
func ParseAstFileFromAst(stage *StageStruct, inFile *ast.File, fset *token.FileSet) error {
	// if there is a meta package import, it is the third import
	if len(inFile.Imports) > 3 {
		log.Fatalln("Too many imports in file", inFile.Name)
	}
	if len(inFile.Imports) == 3 {
		stage.MetaPackageImportAlias = inFile.Imports[2].Name.Name
		stage.MetaPackageImportPath = inFile.Imports[2].Path.Value
	}

	// astCoordinate := "File "
	// log.Println(// astCoordinate)
	for _, decl := range inFile.Decls {
		switch decl := decl.(type) {
		case *ast.FuncDecl:
			funcDecl := decl
			// astCoordinate := // astCoordinate + "\tFunction " + funcDecl.Name.Name
			if name := funcDecl.Name; name != nil {
				isOfInterest := strings.Contains(funcDecl.Name.Name, "Injection")
				if !isOfInterest {
					continue
				}
				// log.Println(// astCoordinate)
			}
			if doc := funcDecl.Doc; doc != nil {
				// astCoordinate := // astCoordinate + "\tDoc"
				for _, comment := range doc.List {
					_ = comment
					// astCoordinate := // astCoordinate + "\tComment: " + comment.Text
					// log.Println(// astCoordinate)
				}
			}
			if body := funcDecl.Body; body != nil {
				// astCoordinate := // astCoordinate + "\tBody: "
				for _, stmt := range body.List {
					switch stmt := stmt.(type) {
					case *ast.ExprStmt:
						exprStmt := stmt
						// astCoordinate := // astCoordinate + "\tExprStmt: "
						switch expr := exprStmt.X.(type) {
						case *ast.CallExpr:
							// astCoordinate := // astCoordinate + "\tCallExpr: "
							callExpr := expr
							switch fun := callExpr.Fun.(type) {
							case *ast.Ident:
								ident := fun
								_ = ident
								// astCoordinate := // astCoordinate + "\tIdent: " + ident.Name
								// log.Println(// astCoordinate)
							}
						}
					case *ast.AssignStmt:
						// Create an ast.CommentMap from the ast.File's comments.
						// This helps keeping the association between comments
						// and AST nodes.
						cmap := ast.NewCommentMap(fset, inFile, inFile.Comments)
						astCoordinate := "\tAssignStmt: "
						// log.Println(// astCoordinate)
						assignStmt := stmt
						instance, id, gongstruct, fieldName :=
							UnmarshallGongstructStaging(
								stage, &cmap, assignStmt, astCoordinate)
						_ = instance
						_ = id
						_ = gongstruct
						_ = fieldName
					}
				}
			}
		case *ast.GenDecl:
			genDecl := decl
			// log.Println("\tAST GenDecl: ")
			if doc := genDecl.Doc; doc != nil {
				for _, comment := range doc.List {
					_ = comment
					// log.Println("\tAST Comment: ", comment.Text)
				}
			}
			for _, spec := range genDecl.Specs {
				switch spec := spec.(type) {
				case *ast.ImportSpec:
					importSpec := spec
					if path := importSpec.Path; path != nil {
						// log.Println("\t\tAST Path: ", path.Value)
					}
				case *ast.ValueSpec:
					ident := spec.Names[0]
					_ = ident
					if !strings.HasPrefix(ident.Name, "map_DocLink_Identifier") {
						continue
					}
					switch compLit := spec.Values[0].(type) {
					case *ast.CompositeLit:
						var key string
						_ = key
						var value string
						_ = value
						for _, elt := range compLit.Elts {

							// each elt is an expression for struct or for field such as
							// for struct
							//
							//         "dummy.Dummy": &(dummy.Dummy{})
							//
							// or, for field
							//
							//          "dummy.Dummy.Name": (dummy.Dummy{}).Name,
							//
							// first node in the AST is a key value expression
							var ok bool
							var kve *ast.KeyValueExpr
							if kve, ok = elt.(*ast.KeyValueExpr); !ok {
								log.Fatal("Expression should be key value expression" +
									fset.Position(kve.Pos()).String())
							}

							switch bl := kve.Key.(type) {
							case *ast.BasicLit:
								key = bl.Value // "\"dumm.Dummy\"" is the value

								// one remove the ambracing double quotes
								key = strings.TrimPrefix(key, "\"")
								key = strings.TrimSuffix(key, "\"")
							}
							var expressionType GONG__ExpressionType = GONG__STRUCT_INSTANCE
							var docLink GONG__Identifier

							var fieldName string
							var ue *ast.UnaryExpr
							if ue, ok = kve.Value.(*ast.UnaryExpr); !ok {
								expressionType = GONG__FIELD_OR_CONST_VALUE
							}

							var callExpr *ast.CallExpr
							if callExpr, ok = kve.Value.(*ast.CallExpr); ok {

								var se *ast.SelectorExpr
								if se, ok = callExpr.Fun.(*ast.SelectorExpr); !ok {
									log.Fatal("Expression should be a selector expression" +
										fset.Position(callExpr.Pos()).String())
								}

								var id *ast.Ident
								if id, ok = se.X.(*ast.Ident); !ok {
									log.Fatal("Expression should be an ident" +
										fset.Position(se.Pos()).String())
								}

								// check the arg type to select wether this is a int or a string enum
								var bl *ast.BasicLit
								if bl, ok = callExpr.Args[0].(*ast.BasicLit); ok {
									switch bl.Kind {
									case token.STRING:
										expressionType = GONG__ENUM_CAST_STRING
									case token.INT:
										expressionType = GONG__ENUM_CAST_INT
									}
								} else {
									log.Fatal("Expression should be a basic lit" +
										fset.Position(se.Pos()).String())
								}

								docLink.Ident = id.Name + "." + se.Sel.Name
								_ = callExpr
							}

							var se2 *ast.SelectorExpr
							switch expressionType {
							case GONG__FIELD_OR_CONST_VALUE:
								if se2, ok = kve.Value.(*ast.SelectorExpr); ok {

									var ident *ast.Ident
									if _, ok = se2.X.(*ast.ParenExpr); ok {
										expressionType = GONG__FIELD_VALUE
										fieldName = se2.Sel.Name
									} else if ident, ok = se2.X.(*ast.Ident); ok {
										expressionType = GONG__IDENTIFIER_CONST
										docLink.Ident = ident.Name + "." + se2.Sel.Name
									} else {
										log.Fatal("Expression should be a selector expression or an ident" +
											fset.Position(kve.Pos()).String())
									}
								} else {

								}
							}

							var pe *ast.ParenExpr
							switch expressionType {
							case GONG__STRUCT_INSTANCE:
								if pe, ok = ue.X.(*ast.ParenExpr); !ok {
									log.Fatal("Expression should be parenthese expression" +
										fset.Position(ue.Pos()).String())
								}
							case GONG__FIELD_VALUE:
								if pe, ok = se2.X.(*ast.ParenExpr); !ok {
									log.Fatal("Expression should be parenthese expression" +
										fset.Position(ue.Pos()).String())
								}
							}
							switch expressionType {
							case GONG__FIELD_VALUE, GONG__STRUCT_INSTANCE:
								// expect a Composite Litteral with no Element <type>{}
								var cl *ast.CompositeLit
								if cl, ok = pe.X.(*ast.CompositeLit); !ok {
									log.Fatal("Expression should be a composite lit" +
										fset.Position(pe.Pos()).String())
								}

								var se *ast.SelectorExpr
								if se, ok = cl.Type.(*ast.SelectorExpr); !ok {
									log.Fatal("Expression should be a selector" +
										fset.Position(cl.Pos()).String())
								}

								var id *ast.Ident
								if id, ok = se.X.(*ast.Ident); !ok {
									log.Fatal("Expression should be an ident" +
										fset.Position(se.Pos()).String())
								}
								docLink.Ident = id.Name + "." + se.Sel.Name
							}

							switch expressionType {
							case GONG__FIELD_VALUE:
								docLink.Ident += "." + fieldName
							}

							// if map_DocLink_Identifier has the same ident, this means
							// that no renaming has occured since the last processing of the
							// file. But it is neccessary to keep it in memory for the
							// marshalling
							if docLink.Ident == key {
								// continue
							}

							// otherwise, one stores the new ident (after renaming) in the
							// renaming map
							docLink.Type = expressionType
							stage.Map_DocLink_Renaming[key] = docLink
						}
					}
				}
			}
		}

	}
	return nil
}

var __gong__map_Indentifiers_gongstructName = make(map[string]string)

// insertion point for identifiers maps{{` + string(rune(ModelGongAstGenericMaps)) + `}}

// Parser needs to be configured for having the [Name1.Name2] or [pkg.Name1] ...
// to be recognized as a proper identifier.
// While this was introduced in go 1.19, it is not yet implemented in
// gopls (see [issue](https://github.com/golang/go/issues/57559)
func lookupPackage(name string) (importPath string, ok bool) {
	return name, true
}
func lookupSym(recv, name string) (ok bool) {
	if recv == "" {
		return true
	}
	return false
}

// UnmarshallGoStaging unmarshall a go assign statement
func UnmarshallGongstructStaging(stage *StageStruct, cmap *ast.CommentMap, assignStmt *ast.AssignStmt, astCoordinate_ string) (
	instance any,
	identifier string,
	gongstructName string,
	fieldName string) {

	// used for debug purposes
	astCoordinate := "\tAssignStmt: "

	//
	// First parse all comment groups in the assignement
	// if a comment "//gong:ident [DocLink]" is met and is followed by a string assignement.
	// modify the following AST assignement to assigns the DocLink text to the string value
	//

	// get the comment group of the assigStmt
	commentGroups := (*cmap)[assignStmt]
	// get the the prefix
	var hasGongIdentDirective bool
	var commentText string
	var docLinkText string
	for _, commentGroup := range commentGroups {
		for _, comment := range commentGroup.List {
			if strings.HasPrefix(comment.Text, "//gong:ident") {
				hasGongIdentDirective = true
				commentText = comment.Text
			}
		}
	}
	if hasGongIdentDirective {
		// parser configured to find doclinks
		var docLinkFinder comment.Parser
		docLinkFinder.LookupPackage = lookupPackage
		docLinkFinder.LookupSym = lookupSym
		doc := docLinkFinder.Parse(commentText)

		for _, block := range doc.Content {
			switch paragraph := block.(type) {
			case *comment.Paragraph:
				_ = paragraph
				for _, text := range paragraph.Text {
					switch docLink := text.(type) {
					case *comment.DocLink:
						if docLink.Recv == "" {
							docLinkText = docLink.ImportPath + "." + docLink.Name
						} else {
							docLinkText = docLink.ImportPath + "." + docLink.Recv + "." + docLink.Name
						}

						// we check wether the doc link has been renamed
						// to be removed after fix of [issue](https://github.com/golang/go/issues/57559)
						if renamed, ok := (stage.Map_DocLink_Renaming)[docLinkText]; ok {
							docLinkText = renamed.Ident
						}
					}
				}
			}
		}
	}

	for rank, expr := range assignStmt.Lhs {
		if rank > 0 {
			continue
		}
		switch expr := expr.(type) {
		case *ast.Ident:
			// we are on a variable declaration
			ident := expr
			// astCoordinate := astCoordinate + "\tLhs" + "." + ident.Name
			// log.Println(astCoordinate)
			identifier = ident.Name
		case *ast.SelectorExpr:
			// we are on a variable assignement
			selectorExpr := expr
			// astCoordinate := astCoordinate + "\tLhs" + "." + selectorExpr.X.(*ast.Ident).Name + "." + selectorExpr.Sel.Name
			// log.Println(astCoordinate)
			identifier = selectorExpr.X.(*ast.Ident).Name
			fieldName = selectorExpr.Sel.Name
		}
	}
	for _, expr := range assignStmt.Rhs {
		// astCoordinate := astCoordinate + "\tRhs"
		switch expr := expr.(type) {
		case *ast.CallExpr:
			callExpr := expr
			// astCoordinate := astCoordinate + "\tFun"
			switch fun := callExpr.Fun.(type) {
			// the is Fun      Expr
			// function expression xxx.Stage()
			case *ast.SelectorExpr:
				selectorExpr := fun
				// astCoordinate := astCoordinate + "\tSelectorExpr"
				switch x := selectorExpr.X.(type) {
				case *ast.ParenExpr:
					// A ParenExpr node represents a parenthesized expression.
					// the is the
					//   { Name : "A1"}
					// astCoordinate := astCoordinate + "\tX"
					parenExpr := x
					switch x := parenExpr.X.(type) {
					case *ast.UnaryExpr:
						unaryExpr := x
						// astCoordinate := astCoordinate + "\tUnaryExpr"
						switch x := unaryExpr.X.(type) {
						case *ast.CompositeLit:
							instanceName := "NoName yet"
							compositeLit := x
							// astCoordinate := astCoordinate + "\tX(CompositeLit)"
							for _, elt := range compositeLit.Elts {
								// astCoordinate := astCoordinate + "\tElt"
								switch elt := elt.(type) {
								case *ast.KeyValueExpr:
									// This is expression
									//     Name: "A1"
									keyValueExpr := elt
									// astCoordinate := astCoordinate + "\tKeyValueExpr"
									switch key := keyValueExpr.Key.(type) {
									case *ast.Ident:
										ident := key
										_ = ident
										// astCoordinate := astCoordinate + "\tKey" + "." + ident.Name
										// log.Println(astCoordinate)
									}
									switch value := keyValueExpr.Value.(type) {
									case *ast.BasicLit:
										basicLit := value
										// astCoordinate := astCoordinate + "\tBasicLit Value" + "." + basicLit.Value
										// log.Println(astCoordinate)
										instanceName = basicLit.Value

										// remove first and last char
										instanceName = instanceName[1 : len(instanceName)-1]
									}
								}
							}
							astCoordinate2 := astCoordinate + "\tType"
							_ = astCoordinate2
							switch type_ := compositeLit.Type.(type) {
							case *ast.SelectorExpr:
								slcExpr := type_
								// astCoordinate := astCoordinate2 + "\tSelectorExpr"
								switch X := slcExpr.X.(type) {
								case *ast.Ident:
									ident := X
									_ = ident
									// astCoordinate := astCoordinate + "\tX" + "." + ident.Name
									// log.Println(astCoordinate)
								}
								if Sel := slcExpr.Sel; Sel != nil {
									// astCoordinate := astCoordinate + "\tSel" + "." + Sel.Name
									// log.Println(astCoordinate)

									gongstructName = Sel.Name
									// this is the place where an instance is created
									switch gongstructName {
									// insertion point for identifiers{{` + string(rune(ModelGongAstStageProcessing)) + `}}
									}
									__gong__map_Indentifiers_gongstructName[identifier] = gongstructName
									return
								}
							}
						}
					}
				}
				if sel := selectorExpr.Sel; sel != nil {
					// astCoordinate := astCoordinate + "\tSel" + "." + sel.Name
					// log.Println(astCoordinate)
				}
				for iteration, arg := range callExpr.Args {
					// astCoordinate := astCoordinate + "\tArg"
					switch arg := arg.(type) {
					case *ast.BasicLit:
						basicLit := arg
						// astCoordinate := astCoordinate + "\tBasicLit" + "." + basicLit.Value
						// log.Println(astCoordinate)

						// first iteration should be ignored
						if iteration == 0 {
							continue
						}

						// remove first and last char
						date := basicLit.Value[1 : len(basicLit.Value)-1]
						_ = date

						var ok bool
						gongstructName, ok = __gong__map_Indentifiers_gongstructName[identifier]
						if !ok {
							log.Fatalln("gongstructName not found for identifier", identifier)
						}
						switch gongstructName {
						// insertion point for basic lit assignments{{` + string(rune(ModelGongAstDateAssignment)) + `}}
						}
					}
				}
			case *ast.Ident:
				// append function
				ident := fun
				_ = ident
				// astCoordinate := astCoordinate + "\tIdent" + "." + ident.Name
				// log.Println(astCoordinate)
			}
			for _, arg := range callExpr.Args {
				// astCoordinate := astCoordinate + "\tArg"
				switch arg := arg.(type) {
				case *ast.Ident:
					ident := arg
					_ = ident
					// astCoordinate := astCoordinate + "\tIdent" + "." + ident.Name
					// log.Println(astCoordinate)
					var ok bool
					gongstructName, ok = __gong__map_Indentifiers_gongstructName[identifier]
					if !ok {
						log.Fatalln("gongstructName not found for identifier", identifier)
					}
					switch gongstructName {
					// insertion point for slice of pointers assignments{{` + string(rune(ModelGongAstSliceOfPointersAssignment)) + `}}
					}
				case *ast.SelectorExpr:
					slcExpr := arg
					// astCoordinate := astCoordinate + "\tSelectorExpr"
					switch X := slcExpr.X.(type) {
					case *ast.Ident:
						ident := X
						_ = ident
						// astCoordinate := astCoordinate + "\tX" + "." + ident.Name
						// log.Println(astCoordinate)

					}
					if Sel := slcExpr.Sel; Sel != nil {
						// astCoordinate := astCoordinate + "\tSel" + "." + Sel.Name
						// log.Println(astCoordinate)
					}
				}
			}
		case *ast.BasicLit, *ast.UnaryExpr:

			var basicLit *ast.BasicLit
			var exprSign = 1.0
			_ = exprSign // in case this is not used

			if bl, ok := expr.(*ast.BasicLit); ok {
				// expression is  for instance ... = 18.000
				basicLit = bl
			} else if ue, ok := expr.(*ast.UnaryExpr); ok {
				// expression is  for instance ... = -18.000
				// we want to extract a *ast.BasicLit from the *ast.UnaryExpr
				basicLit = ue.X.(*ast.BasicLit)
				exprSign = -1
			}

			// astCoordinate := astCoordinate + "\tBasicLit" + "." + basicLit.Value
			// log.Println(astCoordinate)
			var ok bool
			gongstructName, ok = __gong__map_Indentifiers_gongstructName[identifier]
			if !ok {
				log.Fatalln("gongstructName not found for identifier", identifier)
			}

			// substitute the RHS part of the assignment if a //gong:ident directive is met
			if hasGongIdentDirective {
				basicLit.Value = "[" + docLinkText + "]"
			}

			switch gongstructName {
			// insertion point for basic lit assignments{{` + string(rune(ModelGongAstBasicLitAssignment)) + `}}
			}
		case *ast.Ident:
			// assignment to boolean field ?
			ident := expr
			_ = ident
			// astCoordinate := astCoordinate + "\tIdent" + "." + ident.Name
			// log.Println(astCoordinate)
			var ok bool
			gongstructName, ok = __gong__map_Indentifiers_gongstructName[identifier]
			if !ok {
				log.Fatalln("gongstructName not found for identifier", identifier)
			}
			switch gongstructName {
			// insertion point for bool & pointers assignments{{` + string(rune(ModelGongAstIdentBooleanAndPointerAssignment)) + `}}
			}
		case *ast.SelectorExpr:
			// assignment to enum field
			selectorExpr := expr
			// astCoordinate := astCoordinate + "\tSelectorExpr"
			switch X := selectorExpr.X.(type) {
			case *ast.Ident:
				ident := X
				_ = ident
				// astCoordinate := astCoordinate + "\tX" + "." + ident.Name
				// log.Println(astCoordinate)
			}
			if Sel := selectorExpr.Sel; Sel != nil {
				// astCoordinate := astCoordinate + "\tSel" + "." + Sel.Name
				// log.Println(astCoordinate)

				// enum field
				var ok bool
				gongstructName, ok = __gong__map_Indentifiers_gongstructName[identifier]
				if !ok {
					log.Fatalln("gongstructName not found for identifier", identifier)
				}

				// remove first and last char
				enumValue := Sel.Name
				_ = enumValue
				switch gongstructName {
				// insertion point for enums assignments{{` + string(rune(ModelGongAstIdentEnumAssignment)) + `}}
				}
			}
		}
	}
	return
}
`
View Source
const GongSliceTemplate = `// generated code - do not edit
package models

// EvictInOtherSlices allows for adherance between
// the gong association model and go.
//
// Says you have a Astruct struct with a slice field "anarrayofb []*Bstruct"
//
// go allows many Astruct instance to have the anarrayofb field that have the
// same pointers. go slices are MANY-MANY association.
//
// With gong it is only ZERO-ONE-MANY associations, a Bstruct can be pointed only
// once by an Astruct instance through a given field. This follows the requirement
// that gong is suited for full stack programming and therefore the association
// is encoded as a reverse pointer (not as a joint table). In gong, a named struct
// is translated in a table and each table is a named struct.
//
// EvictInOtherSlices removes the fields instances from other
// fields of other instance
//
// Note : algo is in O(N)log(N) of nb of Astruct and Bstruct instances
func EvictInOtherSlices[OwningType PointerToGongstruct, FieldType PointerToGongstruct](
	stage *StageStruct,
	owningInstance OwningType,
	sliceField []FieldType,
	fieldName string) {

	// create a map of the field elements
	setOfFieldInstances := make(map[FieldType]any, 0)
	for _, fieldInstance := range sliceField {
		setOfFieldInstances[fieldInstance] = true
	}

	switch owningInstanceInfered := any(owningInstance).(type) {
	// insertion point{{` + string(rune(GongSliceCase)) + `}}
	default:
		_ = owningInstanceInfered // to avoid "declared and not used" error if no named struct has slices
	}
}

// ComputeReverseMaps computes the reverse map, for all intances, for all slice to pointers field
// Its complexity is in O(n)O(p) where p is the number of pointers
func (stage *StageStruct) ComputeReverseMaps() {
	// insertion point per named struct{{` + string(rune(GongSliceReverseMapCompute)) + `}}
}
`
View Source
const ModelGongCallbacksFileTemplate = `// generated code - do not edit
package models

// AfterCreateFromFront is called after a create from front
func AfterCreateFromFront[Type Gongstruct](stage *StageStruct, instance *Type) {

	switch target := any(instance).(type) {
	// insertion point{{` + string(rune(ModelGongCallbacksCreate)) + `}}
	default:
		_ = target
	}
}

// AfterUpdateFromFront is called after a update from front
func AfterUpdateFromFront[Type Gongstruct](stage *StageStruct, old, new *Type) {

	switch oldTarget := any(old).(type) {
	// insertion point{{` + string(rune(ModelGongCallbacksUpdate)) + `}}
	default:
		_ = oldTarget
	}
}

// AfterDeleteFromFront is called after a delete from front
func AfterDeleteFromFront[Type Gongstruct](stage *StageStruct, staged, front *Type) {

	switch front := any(front).(type) {
	// insertion point{{` + string(rune(ModelGongCallbacksDelete)) + `}}
	default:
		_ = front
	}
}

// AfterReadFromFront is called after a Read from front
func AfterReadFromFront[Type Gongstruct](stage *StageStruct, instance *Type) {

	switch target := any(instance).(type) {
	// insertion point{{` + string(rune(ModelGongCallbacksRead)) + `}}
	default:
		_ = target
	}
}

// SetCallbackAfterUpdateFromFront is a function to set up callback that is robust to refactoring
func SetCallbackAfterUpdateFromFront[Type Gongstruct](stage *StageStruct, callback OnAfterUpdateInterface[Type]) {

	var instance Type
	switch any(instance).(type) {
		// insertion point{{` + string(rune(ModelGongCallbacksSetFuncUpdate)) + `}}
	}
}
func SetCallbackAfterCreateFromFront[Type Gongstruct](stage *StageStruct, callback OnAfterCreateInterface[Type]) {

	var instance Type
	switch any(instance).(type) {
		// insertion point{{` + string(rune(ModelGongCallbacksSetFuncCreate)) + `}}
	}
}
func SetCallbackAfterDeleteFromFront[Type Gongstruct](stage *StageStruct, callback OnAfterDeleteInterface[Type]) {

	var instance Type
	switch any(instance).(type) {
		// insertion point{{` + string(rune(ModelGongCallbacksSetFuncDelete)) + `}}
	}
}
func SetCallbackAfterReadFromFront[Type Gongstruct](stage *StageStruct, callback OnAfterReadInterface[Type]) {

	var instance Type
	switch any(instance).(type) {
		// insertion point{{` + string(rune(ModelGongCallbacksSetFuncRead)) + `}}
	}
}
`
View Source
const ModelGongCoderFileTemplate = `// generated code - do not edit
package models

import "time"

// GongfieldCoder return an instance of Type where each field 
// encodes the index of the field
//
// This allows for refactorable field names
// 
func GongfieldCoder[Type Gongstruct]() Type {
	var t Type

	switch any(t).(type) {
	// insertion point for cases{{` + string(rune(ModelGongCoderGenericGongstructCoder)) + `}}
	default:
		return t
	}
}

type Gongfield interface {
	string | bool | int | float64 | time.Time | time.Duration{{` + string(rune(ModelGongCoderGenericGongstructTypes)) + `}}
}

// GongfieldName provides the name of the field by passing the instance of the coder to
// the fonction.
//
// This allows for refactorable field name
//
// fieldCoder := models.GongfieldCoder[models.Astruct]()
// log.Println( models.GongfieldName[*models.Astruct](fieldCoder.Name))
// log.Println( models.GongfieldName[*models.Astruct](fieldCoder.Booleanfield))
// log.Println( models.GongfieldName[*models.Astruct](fieldCoder.Intfield))
// log.Println( models.GongfieldName[*models.Astruct](fieldCoder.Floatfield))
// 
// limitations:
// 1. cannot encode boolean fields
// 2. for associations (pointer to gongstruct or slice of pointer to gongstruct, uses GetAssociationName)
func GongfieldName[Type PointerToGongstruct, FieldType Gongfield](field FieldType) string {
	var t Type

	switch any(t).(type) {
	// insertion point for cases{{` + string(rune(ModelGongCoderGenericGongstructNamerString)) + `}}
	default:
		return ""
	}
	_ = field
	return ""
}
`
View Source
const ModelGongEnumFileTemplate = `// generated code - do not edit
package models

// insertion point of enum utility functions{{` + string(rune(ModelGongEnumUtilityFunctions)) + `}}
// end of insertion point for enum utility functions

type GongstructEnumStringField interface {
	string{{` + string(rune(ModelGongStructInsertionGenericEnumStringTypes)) + `}}
	Codes() []string
	CodeValues() []string
}

type PointerToGongstructEnumStringField interface {
	{{` + string(rune(ModelGongStructInsertionGenericPointerToEnumStringTypes)) + `}}
	FromCodeString(input string) (err error)
}

type GongstructEnumIntField interface {
	int{{` + string(rune(ModelGongStructInsertionGenericEnumIntTypes)) + `}}
	Codes() []string
	CodeValues() []int
}

type PointerToGongstructEnumIntField interface {
	{{` + string(rune(ModelGongStructInsertionGenericPointerToEnumIntTypes)) + `}}
	FromCodeString(input string) (err error)
}

// Last line of the template
`
View Source
const ModelGongFileTemplate = `// generated code - do not edit
package models

import (
	"cmp"
	"errors"
	"fmt"
	"math"
	"slices"
	"time"

	"golang.org/x/exp/maps"
)

func __Gong__Abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

// errUnkownEnum is returns when a value cannot match enum values
var errUnkownEnum = errors.New("unkown enum")

// needed to avoid when fmt package is not needed by generated code
var __dummy__fmt_variable fmt.Scanner

// idem for math package when not need by generated code
var __dummy_math_variable = math.E

// swagger:ignore
type __void any

// needed for creating set of instances in the stage
var __member __void

// GongStructInterface is the interface met by GongStructs
// It allows runtime reflexion of instances (without the hassle of the "reflect" package)
type GongStructInterface interface {
	GetName() (res string)
	// GetID() (res int)
	// GetFields() (res []string)
	// GetFieldStringValue(fieldName string) (res string)
}

// StageStruct enables storage of staged instances
// swagger:ignore
type StageStruct struct {
	path string

	// insertion point for definition of arrays registering instances{{` + string(rune(ModelGongStructInsertionArrayDefintion)) + `}}
	AllModelsStructCreateCallback AllModelsStructCreateInterface

	AllModelsStructDeleteCallback AllModelsStructDeleteInterface

	BackRepo BackRepoInterface

	// if set will be called before each commit to the back repo
	OnInitCommitCallback          OnInitCommitInterface
	OnInitCommitFromFrontCallback OnInitCommitInterface
	OnInitCommitFromBackCallback  OnInitCommitInterface

	// store the number of instance per gongstruct
	Map_GongStructName_InstancesNb map[string]int

	// store meta package import
	MetaPackageImportPath  string
	MetaPackageImportAlias string

	// to be removed after fix of [issue](https://github.com/golang/go/issues/57559)
	// map to enable docLink renaming when an identifier is renamed
	Map_DocLink_Renaming map[string]GONG__Identifier
	// the to be removed stops here
}

func (stage *StageStruct) GetType() string {
	return "{{PkgPathRoot}}/models"
}

type GONG__Identifier struct {
	Ident string
	Type  GONG__ExpressionType
}

type OnInitCommitInterface interface {
	BeforeCommit(stage *StageStruct)
}

// OnAfterCreateInterface callback when an instance is updated from the front
type OnAfterCreateInterface[Type Gongstruct] interface {
	OnAfterCreate(stage *StageStruct,
		instance *Type)
}

// OnAfterReadInterface callback when an instance is updated from the front
type OnAfterReadInterface[Type Gongstruct] interface {
	OnAfterRead(stage *StageStruct,
		instance *Type)
}

// OnAfterUpdateInterface callback when an instance is updated from the front
type OnAfterUpdateInterface[Type Gongstruct] interface {
	OnAfterUpdate(stage *StageStruct, old, new *Type)
}

// OnAfterDeleteInterface callback when an instance is updated from the front
type OnAfterDeleteInterface[Type Gongstruct] interface {
	OnAfterDelete(stage *StageStruct,
		staged, front *Type)
}

type BackRepoInterface interface {
	Commit(stage *StageStruct)
	Checkout(stage *StageStruct)
	Backup(stage *StageStruct, dirPath string)
	Restore(stage *StageStruct, dirPath string)
	BackupXL(stage *StageStruct, dirPath string)
	RestoreXL(stage *StageStruct, dirPath string)
	// insertion point for Commit and Checkout signatures{{` + string(rune(ModelGongStructInsertionCommitCheckout)) + `}}
	GetLastCommitFromBackNb() uint
	GetLastPushFromFrontNb() uint
}

func NewStage(path string) (stage *StageStruct) {

	stage = &StageStruct{ // insertion point for array initiatialisation{{` + string(rune(ModelGongStructInsertionArrayInitialisation)) + `}}
		// end of insertion point
		Map_GongStructName_InstancesNb: make(map[string]int),

		path: path,

		// to be removed after fix of [issue](https://github.com/golang/go/issues/57559)
		Map_DocLink_Renaming: make(map[string]GONG__Identifier),
		// the to be removed stops here
	}

	return
}

func (stage *StageStruct) GetPath() string {
	return stage.path
}

func (stage *StageStruct) CommitWithSuspendedCallbacks() {

	tmp := stage.OnInitCommitFromBackCallback
	stage.OnInitCommitFromBackCallback = nil
	stage.Commit()
	stage.OnInitCommitFromBackCallback = tmp
}

func (stage *StageStruct) Commit() {
	stage.ComputeReverseMaps()

	if stage.BackRepo != nil {
		stage.BackRepo.Commit(stage)
	}

	// insertion point for computing the map of number of instances per gongstruct{{` + string(rune(ModelGongStructInsertionComputeNbInstances)) + `}}

}

func (stage *StageStruct) Checkout() {
	if stage.BackRepo != nil {
		stage.BackRepo.Checkout(stage)
	}

	stage.ComputeReverseMaps()
	// insertion point for computing the map of number of instances per gongstruct{{` + string(rune(ModelGongStructInsertionComputeNbInstances)) + `}}

}

// backup generates backup files in the dirPath
func (stage *StageStruct) Backup(dirPath string) {
	if stage.BackRepo != nil {
		stage.BackRepo.Backup(stage, dirPath)
	}
}

// Restore resets Stage & BackRepo and restores their content from the restore files in dirPath
func (stage *StageStruct) Restore(dirPath string) {
	if stage.BackRepo != nil {
		stage.BackRepo.Restore(stage, dirPath)
	}
}

// backup generates backup files in the dirPath
func (stage *StageStruct) BackupXL(dirPath string) {
	if stage.BackRepo != nil {
		stage.BackRepo.BackupXL(stage, dirPath)
	}
}

// Restore resets Stage & BackRepo and restores their content from the restore files in dirPath
func (stage *StageStruct) RestoreXL(dirPath string) {
	if stage.BackRepo != nil {
		stage.BackRepo.RestoreXL(stage, dirPath)
	}
}

// insertion point for cumulative sub template with model space calls{{` + string(rune(ModelGongStructInsertionStageFunctions)) + `}}
// swagger:ignore
type AllModelsStructCreateInterface interface { // insertion point for Callbacks on creation{{` + string(rune(ModelGongStructInsertionCreateCallback)) + `}}
}

type AllModelsStructDeleteInterface interface { // insertion point for Callbacks on deletion{{` + string(rune(ModelGongStructInsertionDeleteCallback)) + `}}
}

func (stage *StageStruct) Reset() { // insertion point for array reset{{` + string(rune(ModelGongStructInsertionArrayReset)) + `}}
}

func (stage *StageStruct) Nil() { // insertion point for array nil{{` + string(rune(ModelGongStructInsertionArrayNil)) + `}}
}

func (stage *StageStruct) Unstage() { // insertion point for array nil{{` + string(rune(ModelGongStructInsertionArrayUnstage)) + `}}
}

// Gongstruct is the type parameter for generated generic function that allows
// - access to staged instances
// - navigation between staged instances by going backward association links between gongstruct
// - full refactoring of Gongstruct identifiers / fields
type Gongstruct interface {
	// insertion point for generic types
	{{` + string(rune(ModelGongStructInsertionGenericGongstructTypes)) + `}}
}

type GongtructBasicField interface {
	int | float64 | bool | string | time.Time | time.Duration
}

// Gongstruct is the type parameter for generated generic function that allows
// - access to staged instances
// - navigation between staged instances by going backward association links between gongstruct
// - full refactoring of Gongstruct identifiers / fields
type PointerToGongstruct interface {
	// insertion point for generic types
	{{` + string(rune(ModelGongStructInsertionGenericPointerToGongstructTypes)) + `}}
	GetName() string
	CommitVoid(*StageStruct)
	UnstageVoid(stage *StageStruct)
}

func CompareGongstructByName[T PointerToGongstruct](a, b T) int {
	return cmp.Compare(a.GetName(), b.GetName())
}

func SortGongstructSetByName[T PointerToGongstruct](set map[T]any) (sortedSlice []T) {

	sortedSlice = maps.Keys(set)
	slices.SortFunc(sortedSlice, CompareGongstructByName)

	return
}

func GetGongstrucsSorted[T PointerToGongstruct](stage *StageStruct) (sortedSlice []T) {

	set := GetGongstructInstancesSetFromPointerType[T](stage)
	sortedSlice = SortGongstructSetByName(*set)

	return
}

type GongstructSet interface {
	map[any]any |
		// insertion point for generic types{{` + string(rune(ModelGongStructInsertionGenericGongSetTypes)) + `}}
		map[*any]any // because go does not support an extra "|" at the end of type specifications
}

type GongstructMapString interface {
	map[any]any |
		// insertion point for generic types{{` + string(rune(ModelGongStructInsertionGenericGongMapTypes)) + `}}
		map[*any]any // because go does not support an extra "|" at the end of type specifications
}

// GongGetSet returns the set staged GongstructType instances
// it is usefull because it allows refactoring of gong struct identifier
func GongGetSet[Type GongstructSet](stage *StageStruct) *Type {
	var ret Type

	switch any(ret).(type) {
	// insertion point for generic get functions{{` + string(rune(ModelGongStructInsertionGenericGetSetFunctions)) + `}}
	default:
		return nil
	}
}

// GongGetMap returns the map of staged GongstructType instances
// it is usefull because it allows refactoring of gong struct identifier
func GongGetMap[Type GongstructMapString](stage *StageStruct) *Type {
	var ret Type

	switch any(ret).(type) {
	// insertion point for generic get functions{{` + string(rune(ModelGongStructInsertionGenericGetMapFunctions)) + `}}
	default:
		return nil
	}
}

// GetGongstructInstancesSet returns the set staged GongstructType instances
// it is usefull because it allows refactoring of gongstruct identifier
func GetGongstructInstancesSet[Type Gongstruct](stage *StageStruct) *map[*Type]any {
	var ret Type

	switch any(ret).(type) {
	// insertion point for generic get functions{{` + string(rune(ModelGongStructInsertionGenericInstancesSetFunctions)) + `}}
	default:
		return nil
	}
}

// GetGongstructInstancesSetFromPointerType returns the set staged GongstructType instances
// it is usefull because it allows refactoring of gongstruct identifier
func GetGongstructInstancesSetFromPointerType[Type PointerToGongstruct](stage *StageStruct) {{mapReturnType}} {
	var ret Type

	switch any(ret).(type) {
	// insertion point for generic get functions{{` + string(rune(ModelGongStructInsertionGenericInstancesSetFromPointerTypeFunctions)) + `}}
	default:
		return nil
	}
}

// GetGongstructInstancesMap returns the map of staged GongstructType instances
// it is usefull because it allows refactoring of gong struct identifier
func GetGongstructInstancesMap[Type Gongstruct](stage *StageStruct) *map[string]*Type {
	var ret Type

	switch any(ret).(type) {
	// insertion point for generic get functions{{` + string(rune(ModelGongStructInsertionGenericInstancesMapFunctions)) + `}}
	default:
		return nil
	}
}

// GetAssociationName is a generic function that returns an instance of Type
// where each association is filled with an instance whose name is the name of the association
//
// This function can be handy for generating navigation function that are refactorable
func GetAssociationName[Type Gongstruct]() *Type {
	var ret Type

	switch any(ret).(type) {
	// insertion point for instance with special fields{{` + string(rune(ModelGongStructInsertionGenericGetAssociationNameFunctions)) + `}}
	default:
		return nil
	}
}

// GetPointerReverseMap allows backtrack navigation of any Start.Fieldname
// associations (0..1) that is a pointer from one staged Gongstruct (type Start)
// instances to another (type End)
//
// The function provides a map with keys as instances of End and values to arrays of *Start
// the map is construed by iterating over all Start instances and populationg keys with End instances
// and values with slice of Start instances
func GetPointerReverseMap[Start, End Gongstruct](fieldname string, stage *StageStruct) map[*End][]*Start {

	var ret Start

	switch any(ret).(type) {
	// insertion point of functions that provide maps for reverse associations{{` + string(rune(ModelGongStructInsertionGenericReversePointerAssociationsMaps)) + `}}
	}
	return nil
}

// GetSliceOfPointersReverseMap allows backtrack navigation of any Start.Fieldname
// associations (0..N) between one staged Gongstruct instances and many others
//
// The function provides a map with keys as instances of End and values to *Start instances
// the map is construed by iterating over all Start instances and populating keys with End instances
// and values with the Start instances
func GetSliceOfPointersReverseMap[Start, End Gongstruct](fieldname string, stage *StageStruct) map[*End]*Start {

	var ret Start

	switch any(ret).(type) {
	// insertion point of functions that provide maps for reverse associations{{` +
	string(rune(ModelGongStructInsertionGenericReverseSliceOfPointersAssociationsMaps)) + `}}
	}
	return nil
}

// GetGongstructName returns the name of the Gongstruct
// this can be usefull if one want program robust to refactoring
func GetGongstructName[Type Gongstruct]() (res string) {

	var ret Type

	switch any(ret).(type) {
	// insertion point for generic get gongstruct name{{` + string(rune(ModelGongStructInsertionGenericGongstructName)) + `}}
	}
	return res
}

// GetPointerToGongstructName returns the name of the Gongstruct
// this can be usefull if one want program robust to refactoring
func GetPointerToGongstructName[Type PointerToGongstruct]() (res string) {

	var ret Type

	switch any(ret).(type) {
	// insertion point for generic get gongstruct name{{` + string(rune(ModelGongStructInsertionGenericPointerToGongstructName)) + `}}
	}
	return res
}

// GetFields return the array of the fields
func GetFields[Type Gongstruct]() (res []string) {

	var ret Type

	switch any(ret).(type) {
	// insertion point for generic get gongstruct name{{` + string(rune(ModelGongStructInsertionGenericGetFields)) + `}}
	}
	return
}

type ReverseField struct {
	GongstructName string
	Fieldname      string
}

func GetReverseFields[Type Gongstruct]() (res []ReverseField) {

	res = make([]ReverseField, 0)

	var ret Type

	switch any(ret).(type) {

	// insertion point for generic get gongstruct name{{` + string(rune(ModelGongStructInsertionGenericGetReverseFields)) + `}}
	}
	return
}

// GetFieldsFromPointer return the array of the fields
func GetFieldsFromPointer[Type PointerToGongstruct]() (res []string) {

	var ret Type

	switch any(ret).(type) {
	// insertion point for generic get gongstruct name{{` + string(rune(ModelGongStructInsertionGenericGetFieldsFromPointer)) + `}}
	}
	return
}

func GetFieldStringValueFromPointer[Type PointerToGongstruct](instance Type, fieldName string) (res string) {

	switch inferedInstance := any(instance).(type) {
	// insertion point for generic get gongstruct field value{{` + string(rune(ModelGongStructInsertionGenericGetFieldValuesFromPointer)) + `}}
	default:
		_ = inferedInstance
	}
	return
}

func GetFieldStringValue[Type Gongstruct](instance Type, fieldName string) (res string) {

	switch inferedInstance := any(instance).(type) {
	// insertion point for generic get gongstruct field value{{` + string(rune(ModelGongStructInsertionGenericGetFieldValues)) + `}}
	default:
		_ = inferedInstance
	}
	return
}

// Last line of the template
`
View Source
const ModelGongGraphFileTemplate = `// generated code - do not edit
package models

func IsStaged[Type Gongstruct](stage *StageStruct, instance *Type) (ok bool) {

	switch target := any(instance).(type) {
	// insertion point for stage{{` + string(rune(ModelGongGraphStructInsertionIsStaged)) + `}}
	default:
		_ = target
	}
	return
}

// insertion point for stage per struct{{` + string(rune(ModelGongGraphStructInsertionIsStagedPerStruct)) + `}}

// StageBranch stages instance and apply StageBranch on all gongstruct instances that are
// referenced by pointers or slices of pointers of the instance
//
// the algorithm stops along the course of graph if a vertex is already staged
func StageBranch[Type Gongstruct](stage *StageStruct, instance *Type) {

	switch target := any(instance).(type) {
	// insertion point for stage branch{{` + string(rune(ModelGongGraphStructInsertionStageBranch)) + `}}
	default:
		_ = target
	}
}

// insertion point for stage branch per struct{{` + string(rune(ModelGongGraphStructInsertionStageBranchPerStruct)) + `}}

// CopyBranch stages instance and apply CopyBranch on all gongstruct instances that are
// referenced by pointers or slices of pointers of the instance
//
// the algorithm stops along the course of graph if a vertex is already staged
func CopyBranch[Type Gongstruct](from *Type) (to *Type) {

	mapOrigCopy := make(map[any]any)
	_ = mapOrigCopy

	switch fromT := any(from).(type) {
	// insertion point for stage branch{{` + string(rune(ModelGongGraphStructInsertionCopyBranch)) + `}}
	default:
		_ = fromT // to espace compilation issue when model is empty
	}
	return
}

// insertion point for stage branch per struct{{` + string(rune(ModelGongGraphStructInsertionCopyBranchPerStruct)) + `}}

// UnstageBranch stages instance and apply UnstageBranch on all gongstruct instances that are
// referenced by pointers or slices of pointers of the insance
//
// the algorithm stops along the course of graph if a vertex is already staged
func UnstageBranch[Type Gongstruct](stage *StageStruct, instance *Type) {

	switch target := any(instance).(type) {
	// insertion point for unstage branch{{` + string(rune(ModelGongGraphStructInsertionUnstageBranch)) + `}}
	default:
		_ = target
	}
}

// insertion point for unstage branch per struct{{` + string(rune(ModelGongGraphStructInsertionUnstageBranchPerStruct)) + `}}
`
View Source
const ModelGongMarshallFileTemplate = `// generated code - do not edit
package models

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strings"
)

const marshallRes = ` + "`" + `package {{PackageName}}

import (
	"time"

	"{{ModelsPackageName}}"

	// injection point for ident package import declaration{{ImportPackageDeclaration}}
)

// generated in order to avoid error in the package import
// if there are no elements in the stage to marshall
var ___dummy__Stage_{{databaseName}} models.StageStruct
var ___dummy__Time_{{databaseName}} time.Time

// Injection point for meta package dummy declaration{{ImportPackageDummyDeclaration}}

// currently, DocLink renaming is not enabled in gopls
// the following map are devised to overcome this limitation
// those maps and the processing code will be eleminated when
// DocLink renaming will be enabled in gopls
// [Corresponding Issue](https://github.com/golang/go/issues/57559)
//
// When parsed, those maps will help with the renaming process
var map_DocLink_Identifier_{{databaseName}} map[string]any = map[string]any{
	// injection point for docLink to identifiers{{EntriesDocLinkStringDocLinkIdentifier}}
}

// init might be handy if one want to have the data embedded in the binary
// but it has to properly reference the Injection gateway in the main package
// func init() {
// 	_ = __Dummy_time_variable
// 	InjectionGateway["{{databaseName}}"] = {{databaseName}}Injection
// }

// {{databaseName}}Injection will stage objects of database "{{databaseName}}"
func {{databaseName}}Injection(stage *models.StageStruct) {

	// Declaration of instances to stage{{Identifiers}}

	// Setup of values{{ValueInitializers}}

	// Setup of pointers{{PointersInitializers}}
}

` + "`" + `

const IdentifiersDecls = ` + "`" + `
	{{Identifier}} := (&models.{{GeneratedStructName}}{Name: ` +
	"`" + " + \"" + "`" + `"` + ` + ` + "`" +
	`{{GeneratedFieldNameValue}}` + "`" + ` + "` + "`" + `"` + ` + ` + "`" + `}).Stage(stage)` + "`" + `

const StringInitStatement = ` + "`" + `
	{{Identifier}}.{{GeneratedFieldName}} = ` +
	"`" + " + \"" + "`" + `"` + ` + ` + "`" +
	`{{GeneratedFieldNameValue}}` + "`" + ` + "` + "`" + `"` + `

const StringEnumInitStatement = ` + "`" + `
	{{Identifier}}.{{GeneratedFieldName}} = {{GeneratedFieldNameValue}}` + "`" + `

const NumberInitStatement = ` + "`" + `
	{{Identifier}}.{{GeneratedFieldName}} = {{GeneratedFieldNameValue}}` + "`" + `

const PointerFieldInitStatement = ` + "`" + `
	{{Identifier}}.{{GeneratedFieldName}} = {{GeneratedFieldNameValue}}` + "`" + `

const SliceOfPointersFieldInitStatement = ` + "`" + `
	{{Identifier}}.{{GeneratedFieldName}} = append({{Identifier}}.{{GeneratedFieldName}}, {{GeneratedFieldNameValue}})` + "`" + `

const TimeInitStatement = ` + "`" + `
	{{Identifier}}.{{GeneratedFieldName}}, _ = time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", "{{GeneratedFieldNameValue}}")` + "`" + `

// Marshall marshall the stage content into the file as an instanciation into a stage
func (stage *StageStruct) Marshall(file *os.File, modelsPackageName, packageName string) {

	name := file.Name()

	if !strings.HasSuffix(name, ".go") {
		log.Fatalln(name + " is not a go filename")
	}

	log.Println("filename of marshall output is " + name)
	newBase := filepath.Base(file.Name())

	res := marshallRes
	res = strings.ReplaceAll(res, "{{databaseName}}", strings.ReplaceAll(newBase, ".go", ""))
	res = strings.ReplaceAll(res, "{{PackageName}}", packageName)
	res = strings.ReplaceAll(res, "{{ModelsPackageName}}", modelsPackageName)

	// map of identifiers
	// var StageMapDstructIds map[*Dstruct]string
	identifiersDecl := ""
	initializerStatements := ""
	pointersInitializesStatements := ""

	id := ""
	_ = id
	decl := ""
	_ = decl
	setValueField := ""
	_ = setValueField 

	// insertion initialization of objects to stage{{` + string(rune(ModelGongMarshallStructInsertionUnmarshallDeclarations)) + `}}
	// insertion initialization of objects to stage{{` + string(rune(ModelGongMarshallStructInsertionUnmarshallPointersInitializations)) + `}}
	res = strings.ReplaceAll(res, "{{Identifiers}}", identifiersDecl)
	res = strings.ReplaceAll(res, "{{ValueInitializers}}", initializerStatements)
	res = strings.ReplaceAll(res, "{{PointersInitializers}}", pointersInitializesStatements)

	if stage.MetaPackageImportAlias != "" {
		res = strings.ReplaceAll(res, "{{ImportPackageDeclaration}}",
			fmt.Sprintf("\n\t%s %s", stage.MetaPackageImportAlias, stage.MetaPackageImportPath))

		res = strings.ReplaceAll(res, "{{ImportPackageDummyDeclaration}}",
			fmt.Sprintf("\nvar ___dummy__%s_%s %s.StageStruct",
				stage.MetaPackageImportAlias,
				strings.ReplaceAll(filepath.Base(name), ".go", ""),
				stage.MetaPackageImportAlias))

		var entries string

		// regenerate the map of doc link renaming
		// the key and value are set to the value because
		// if it has been renamed, this is the new value that matters
		valuesOrdered := make([]GONG__Identifier, 0)
		for _, value := range stage.Map_DocLink_Renaming {
			valuesOrdered = append(valuesOrdered, value)
		}
		sort.Slice(valuesOrdered[:], func(i, j int) bool {
			return valuesOrdered[i].Ident < valuesOrdered[j].Ident
		})
		for _, value := range valuesOrdered {

			// get the number of points in the value to find if it is a field
			// or a struct

			switch value.Type {
			case GONG__ENUM_CAST_INT:
				entries += fmt.Sprintf("\n\n\t\"%s\": %s(0),", value.Ident, value.Ident)
			case GONG__ENUM_CAST_STRING:
				entries += fmt.Sprintf("\n\n\t\"%s\": %s(\"\"),", value.Ident, value.Ident)
			case GONG__FIELD_VALUE:
				// substitute the second point with "{})."
				joker := "__substitute_for_first_point__"
				valueIdentifier := strings.Replace(value.Ident, ".", joker, 1)
				valueIdentifier = strings.Replace(valueIdentifier, ".", "{}).", 1)
				valueIdentifier = strings.Replace(valueIdentifier, joker, ".", 1)
				entries += fmt.Sprintf("\n\n\t\"%s\": (%s,", value.Ident, valueIdentifier)
			case GONG__IDENTIFIER_CONST:
				entries += fmt.Sprintf("\n\n\t\"%s\": %s,", value.Ident, value.Ident)
			case GONG__STRUCT_INSTANCE:
				entries += fmt.Sprintf("\n\n\t\"%s\": &(%s{}),", value.Ident, value.Ident)
			}
		}

		res = strings.ReplaceAll(res, "{{EntriesDocLinkStringDocLinkIdentifier}}", entries)
	}

	fmt.Fprintln(file, res)
}

// unique identifier per struct
func generatesIdentifier(gongStructName string, idx int, instanceName string) (identifier string) {

	identifier = instanceName
	// Make a Regex to say we only want letters and numbers
	reg, err := regexp.Compile("[^a-zA-Z0-9]+")
	if err != nil {
		log.Fatal(err)
	}
	processedString := reg.ReplaceAllString(instanceName, "_")

	identifier = fmt.Sprintf("__%s__%06d_%s", gongStructName, idx, processedString)

	return
}
`
View Source
const ModelGongOrchestratorFileTemplate = `// generated code - do not edit
package models

// insertion point{{` + string(rune(ModelGongOrchestratorStruct)) + `}}

func SetOrchestratorOnAfterUpdate[Type Gongstruct](stage *StageStruct) {

	var ret Type

	switch any(ret).(type) {
	// insertion point{{` + string(rune(ModelGongOrchestratorSwitch)) + `}}

	}

}
`
View Source
const ModelGongSerializeFileTemplate = `// generated code - do not edit
package models

import (
	"fmt"
	"log"
	"unicode/utf8"

	"github.com/xuri/excelize/v2"
)

func SerializeStage(stage *StageStruct, filename string) {

	f := excelize.NewFile()
	{
		// insertion point{{` + string(rune(ModelGongSerializeStruct)) + `}}
	}

	var tab ExcelizeTabulator
	tab.SetExcelizeFile(f)
	{
		f.DeleteSheet("Sheet1")
		if err := f.SaveAs(filename); err != nil {
			fmt.Println("cannot write xl file : ", err)
		}
	}

}

// Tabulator is an interface for writing to a table strings
type Tabulator interface {
	AddSheet(sheetName string)
	AddRow(sheetName string) int
	AddCell(sheetName string, rowId, columnIndex int, value string)
}

func Serialize[Type Gongstruct](stage *StageStruct, tab Tabulator) {
	sheetName := GetGongstructName[Type]()

	// Create a new sheet.
	tab.AddSheet(sheetName)

	headerRowIndex := tab.AddRow(sheetName)
	for colIndex, fieldName := range GetFields[Type]() {
		tab.AddCell(sheetName, headerRowIndex, colIndex, fieldName)
		// f.SetCellStr(sheetName, fmt.Sprintf("%s%d", IntToLetters(int32(index+1)), line), fieldName)
	}

	set := *GetGongstructInstancesSet[Type](stage)
	for instance := range set {
		line := tab.AddRow(sheetName)
		for index, fieldName := range GetFields[Type]() {
			tab.AddCell(sheetName, line, index, GetFieldStringValue(
				any(*instance).(Type), fieldName))
			// f.SetCellStr(sheetName, fmt.Sprintf("%s%d", IntToLetters(int32(index+1)), line), GetFieldStringValue(
			// 	any(*instance).(Type), fieldName))
		}
	}
}

type ExcelizeTabulator struct {
	f *excelize.File
}

func (tab *ExcelizeTabulator) SetExcelizeFile(f *excelize.File) {
	tab.f = f
}

func (tab *ExcelizeTabulator) AddSheet(sheetName string) {

}

func (tab *ExcelizeTabulator) AddRow(sheetName string) (rowId int) {
	return
}

func (tab *ExcelizeTabulator) AddCell(sheetName string, rowId, columnIndex int, value string) {

}

func SerializeExcelize[Type Gongstruct](stage *StageStruct, f *excelize.File) {
	sheetName := GetGongstructName[Type]()

	// Create a new sheet.
	f.NewSheet(sheetName)

	set := *GetGongstructInstancesSet[Type](stage)
	line := 1

	for index, fieldName := range GetFields[Type]() {
		f.SetCellStr(sheetName, fmt.Sprintf("%s%d", IntToLetters(int32(index+1)), line), fieldName)
	}
	f.AutoFilter(sheetName,
		fmt.Sprintf("%s%d", IntToLetters(int32(1)), line),
		[]excelize.AutoFilterOptions{})

	for instance := range set {
		line = line + 1
		for index, fieldName := range GetFields[Type]() {
			f.SetCellStr(sheetName, fmt.Sprintf("%s%d", IntToLetters(int32(index+1)), line), GetFieldStringValue(
				any(*instance).(Type), fieldName))
		}
	}

	// Autofit all columns according to their text content
	cols, err := f.GetCols(sheetName)
	if err != nil {
		log.Panicln("SerializeExcelize")
	}
	for idx, col := range cols {
		largestWidth := 0
		for _, rowCell := range col {
			cellWidth := utf8.RuneCountInString(rowCell) + 2 // + 2 for margin
			if cellWidth > largestWidth {
				largestWidth = cellWidth
			}
		}
		name, err := excelize.ColumnNumberToName(idx + 1)
		if err != nil {
			log.Panicln("SerializeExcelize")
		}
		f.SetColWidth(sheetName, name, name, float64(largestWidth))
	}
}

func IntToLetters(number int32) (letters string) {
	number--
	if firstLetter := number / 26; firstLetter > 0 {
		letters += IntToLetters(firstLetter)
		letters += string('A' + number%26)
	} else {
		letters += string('A' + number)
	}

	return
}
`
View Source
const ModelGongWopFileTemplate = `// generated code - do not edit
package models

import "time"

// to avoid compile error if no time field is present
var __GONG_time_The_fool_doth_think_he_is_wise__ = time.Hour

// insertion point{{` + string(rune(ModelGongWopStruct)) + `}}
`

Variables

View Source
var GongFileFieldFieldSubTemplateCode map[GongFilePerStructSubTemplateId]string = map[GongFilePerStructSubTemplateId]string{

	GongFileFieldSubTmplStringFieldName: `"{{FieldName}}"`,

	GongFileFieldSubTmplReverseField: `
		rf.GongstructName = "{{AssocStructName}}"
		rf.Fieldname = "{{FieldName}}"
		res = append(res, rf)`,

	GongFileFieldSubTmplStringValueBasicFieldBool: `
		case "{{FieldName}}":
			res = fmt.Sprintf("%t", inferedInstance.{{FieldName}})`,
	GongFileFieldSubTmplStringValueBasicFieldInt: `
		case "{{FieldName}}":
			res = fmt.Sprintf("%d", inferedInstance.{{FieldName}})`,
	GongFileFieldSubTmplStringValueBasicFieldIntDuration: `
		case "{{FieldName}}":
			if math.Abs(inferedInstance.{{FieldName}}.Hours()) >= 24 {
				days := __Gong__Abs(int(int(inferedInstance.{{FieldName}}.Hours()) / 24))
				months := int(days / 31)
				days = days - months*31

				remainingHours := int(inferedInstance.{{FieldName}}.Hours()) % 24
				remainingMinutes := int(inferedInstance.{{FieldName}}.Minutes()) % 60
				remainingSeconds := int(inferedInstance.{{FieldName}}.Seconds()) % 60

				if inferedInstance.{{FieldName}}.Hours() < 0 {
					res = "- "
				}

				if months > 0 {
					if months > 1 {
						res = res + fmt.Sprintf("%d months", months)
					} else {
						res = res + fmt.Sprintf("%d month", months)
					}
				}
				if days > 0 {
					if months != 0 {
						res = res + ", "
					}
					if days > 1 {
						res = res + fmt.Sprintf("%d days", days)
					} else {
						res = res + fmt.Sprintf("%d day", days)
					}

				}
				if remainingHours != 0 || remainingMinutes != 0 || remainingSeconds != 0 {
					if days != 0 || (days == 0 && months != 0) {
						res = res + ", "
					}
					res = res + fmt.Sprintf("%d hours, %d minutes, %d seconds\n", remainingHours, remainingMinutes, remainingSeconds)
				}
			} else {
				res = fmt.Sprintf("%s\n", inferedInstance.{{FieldName}}.String())
			}`,
	GongFileFieldSubTmplStringValueBasicFieldEnumString: `
		case "{{FieldName}}":
			enum := inferedInstance.{{FieldName}}
			res = enum.ToCodeString()`,
	GongFileFieldSubTmplStringValueBasicFieldEnumInt: `
		case "{{FieldName}}":
			enum := inferedInstance.{{FieldName}}
			res = enum.ToCodeString()`,
	GongFileFieldSubTmplStringValueBasicFieldFloat64: `
		case "{{FieldName}}":
			res = fmt.Sprintf("%f", inferedInstance.{{FieldName}})`,
	GongFileFieldSubTmplStringValueBasicFieldString: `
		case "{{FieldName}}":
			res = inferedInstance.{{FieldName}}`,
	GongFileFieldSubTmplStringValueTimeField: `
		case "{{FieldName}}":
			res = inferedInstance.{{FieldName}}.String()`,
	GongFileFieldSubTmplStringValuePointerField: `
		case "{{FieldName}}":
			if inferedInstance.{{FieldName}} != nil {
				res = inferedInstance.{{FieldName}}.Name
			}`,
	GongFileFieldSubTmplStringValueSliceOfPointersField: `
		case "{{FieldName}}":
			for idx, __instance__ := range inferedInstance.{{FieldName}} {
				if idx > 0 {
					res += "\n"
				}
				res += __instance__.Name
			}`,

	GongFileFieldSubTmplAssociationNamePointerField: `
			// field is initialized with an instance of {{AssocStructName}} with the name of the field
			{{FieldName}}: &{{AssocStructName}}{Name: "{{FieldName}}"},`,

	GongFileFieldSubTmplAssociationNameSliceOfPointersField: `
			// field is initialized with an instance of {{AssocStructName}} with the name of the field
			{{FieldName}}: []*{{AssocStructName}}{{Name: "{{FieldName}}"}},`,

	GongFileFieldSubTmplAssociationNameEnclosingCompositePointerField: `
			// field is initialized with {{AssocCompositeStructName}} as it is a composite
			{{AssocCompositeStructName}}: {{AssocCompositeStructName}}{
				// per field init{{PerCompositeFieldInit}}
			},`,
	GongFileFieldSubTmplAssociationNameCompositePointerField: `
				//
				{{FieldName}}: &{{AssocStructName}}{Name: "{{FieldName}}"},`,

	GongFileFieldSubTmplPointerFieldPointerAssociationMapFunction: `
		case "{{FieldName}}":
			res := make(map[*{{AssocStructName}}][]*{{Structname}})
			for {{structname}} := range stage.{{Structname}}s {
				if {{structname}}.{{FieldName}} != nil {
					{{assocstructname}}_ := {{structname}}.{{FieldName}}
					var {{structname}}s []*{{Structname}}
					_, ok := res[{{assocstructname}}_]
					if ok {
						{{structname}}s = res[{{assocstructname}}_]
					} else {
						{{structname}}s = make([]*{{Structname}}, 0)
					}
					{{structname}}s = append({{structname}}s, {{structname}})
					res[{{assocstructname}}_] = {{structname}}s
				}
			}
			return any(res).(map[*End][]*Start)`,

	GongFileSliceOfPointersReverseMap: `
	{{Structname}}_{{FieldName}}_reverseMap map[*{{AssocStructName}}]*{{Structname}}`,

	GongFileFieldSubTmplPointerFieldSliceOfPointersAssociationMapFunction: `
		case "{{FieldName}}":
			res := make(map[*{{AssocStructName}}]*{{Structname}})
			for {{structname}} := range stage.{{Structname}}s {
				for _, {{assocstructname}}_ := range {{structname}}.{{FieldName}} {
					res[{{assocstructname}}_] = {{structname}}
				}
			}
			return any(res).(map[*End]*Start)`,
}

for each sub template code, there is the sub template code

View Source
var GongGraphFileFieldFieldSubTemplateCode map[GongGraphFilePerStructSubTemplateId]string = map[GongGraphFilePerStructSubTemplateId]string{

	GongGraphFileFieldSubTmplStagePointerField: `
	if {{structname}}.{{FieldName}} != nil {
		StageBranch(stage, {{structname}}.{{FieldName}})
	}`,
	GongGraphFileFieldSubTmplStageSliceOfPointersField: `
	for _, _{{assocstructname}} := range {{structname}}.{{FieldName}} {
		StageBranch(stage, _{{assocstructname}})
	}`,
	GongGraphFileFieldSubTmplCopyPointerField: `
	if {{structname}}From.{{FieldName}} != nil {
		{{structname}}To.{{FieldName}} = CopyBranch{{AssocStructName}}(mapOrigCopy, {{structname}}From.{{FieldName}})
	}`,
	GongGraphFileFieldSubTmplCopySliceOfPointersField: `
	for _, _{{assocstructname}} := range {{structname}}From.{{FieldName}} {
		{{structname}}To.{{FieldName}} = append( {{structname}}To.{{FieldName}}, CopyBranch{{AssocStructName}}(mapOrigCopy, _{{assocstructname}}))
	}`,
	GongGraphFileFieldSubTmplUnstagePointerField: `
	if {{structname}}.{{FieldName}} != nil {
		UnstageBranch(stage, {{structname}}.{{FieldName}})
	}`,
	GongGraphFileFieldSubTmplUnstageSliceOfPointersField: `
	for _, _{{assocstructname}} := range {{structname}}.{{FieldName}} {
		UnstageBranch(stage, _{{assocstructname}})
	}`,
}
View Source
var GongMarshallFileFieldFieldSubTemplateCode map[GongMarshallFilePerStructSubTemplateId]string = map[GongMarshallFilePerStructSubTemplateId]string{

	GongMarshallFileFieldSubTmplSetBasicFieldBool: `
		setValueField = NumberInitStatement
		setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "{{FieldName}}")
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", fmt.Sprintf("%t", {{structname}}.{{FieldName}}))
		initializerStatements += setValueField
`,
	GongMarshallFileFieldSubTmplSetTimeField: `
		setValueField = TimeInitStatement
		setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "{{FieldName}}")
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", {{structname}}.{{FieldName}}.String())
		initializerStatements += setValueField
`,
	GongMarshallFileFieldSubTmplSetBasicFieldInt: `
		setValueField = NumberInitStatement
		setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "{{FieldName}}")
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", fmt.Sprintf("%d", {{structname}}.{{FieldName}}))
		initializerStatements += setValueField
`,
	GongMarshallFileFieldSubTmplSetBasicFieldEnumString: `
		if {{structname}}.{{FieldName}} != "" {
			setValueField = StringEnumInitStatement
			setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
			setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "{{FieldName}}")
			setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", "models."+{{structname}}.{{FieldName}}.ToCodeString())
			initializerStatements += setValueField
		}
`,
	GongMarshallFileFieldSubTmplSetBasicFieldEnumInt: `
		setValueField = NumberInitStatement
		setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "{{FieldName}}")
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", "models."+{{structname}}.{{FieldName}}.ToCodeString())
		initializerStatements += setValueField
`,
	GongMarshallFileFieldSubTmplSetBasicFieldFloat64: `
		setValueField = NumberInitStatement
		setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "{{FieldName}}")
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", fmt.Sprintf("%f", {{structname}}.{{FieldName}}))
		initializerStatements += setValueField
`,
	GongMarshallFileFieldSubTmplSetBasicFieldString: `
		setValueField = StringInitStatement
		setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "{{FieldName}}")
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", string({{structname}}.{{FieldName}}))
		initializerStatements += setValueField
`,
	GongMarshallFileFieldSubTmplSetBasicFieldStringDocLink: `
		setValueField = StringInitStatement
		setValueField = strings.ReplaceAll(setValueField, "\n\t{{Identifier}}",
			fmt.Sprintf("\n\n\t// comment added to overcome the problem with the comment map association\n\n\t//gong:ident [%s]\n\t{{Identifier}}",
				string({{structname}}.{{FieldName}})))
		setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "{{FieldName}}")
		setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", string({{structname}}.{{FieldName}}))
		initializerStatements += setValueField
`,
	GongMarshallFileFieldSubTmplSetPointerField: `
		if {{structname}}.{{FieldName}} != nil {
			setPointerField = PointerFieldInitStatement
			setPointerField = strings.ReplaceAll(setPointerField, "{{Identifier}}", id)
			setPointerField = strings.ReplaceAll(setPointerField, "{{GeneratedFieldName}}", "{{FieldName}}")
			setPointerField = strings.ReplaceAll(setPointerField, "{{GeneratedFieldNameValue}}", map_{{AssocStructName}}_Identifiers[{{structname}}.{{FieldName}}])
			pointersInitializesStatements += setPointerField
		}
`,
	GongMarshallFileFieldSubTmplSetSliceOfPointersField: `
		for _, _{{assocstructname}} := range {{structname}}.{{FieldName}} {
			setPointerField = SliceOfPointersFieldInitStatement
			setPointerField = strings.ReplaceAll(setPointerField, "{{Identifier}}", id)
			setPointerField = strings.ReplaceAll(setPointerField, "{{GeneratedFieldName}}", "{{FieldName}}")
			setPointerField = strings.ReplaceAll(setPointerField, "{{GeneratedFieldNameValue}}", map_{{AssocStructName}}_Identifiers[_{{assocstructname}}])
			pointersInitializesStatements += setPointerField
		}
`,
}
View Source
var GongModelEnumValueSubTemplateCode map[GongModelEnumValueSubTemplateId]string = map[GongModelEnumValueSubTemplateId]string{

	GongModelEnumValueFromString: `
	case {{GongEnumValue}}:
		*{{enumName}} = {{GongEnumCode}}`,
	GongModelEnumValueFromCodeString: `
	case "{{GongEnumCode}}":
		*{{enumName}} = {{GongEnumCode}}`,
	GongModelEnumValueToString: `
	case {{GongEnumCode}}:
		res = {{GongEnumValue}}`,
	GongModelEnumValueToCodeString: `
	case {{GongEnumCode}}:
		res = "{{GongEnumCode}}"`,
	GongModelEnumCodes: `
	res = append(res, "{{GongEnumCode}}")`,
	GongModelEnumCodeValues: `
	res = append(res, {{GongEnumValue}})`,
}
View Source
var GongSliceFileFieldFieldSubTemplateCode map[GongSliceSubTemplateId]string = map[GongSliceSubTemplateId]string{

	GongSliceSubTmplSliceOfPointersToStruct: `
		if fieldName == "{{FieldName}}" {

			// walk all instances of the owning type
			for _instance := range *GetGongstructInstancesSetFromPointerType[OwningType](stage) {
				if any(_instance).(*{{Structname}}) != owningInstanceInfered {
					_inferedTypeInstance := any(_instance).(*{{Structname}})
					reference := make([]FieldType, 0)
					targetFieldSlice := any(_inferedTypeInstance.{{FieldName}}).([]FieldType)
					copy(targetFieldSlice, reference)
					_inferedTypeInstance.{{FieldName}} = _inferedTypeInstance.{{FieldName}}[0:]
					for _, fieldInstance := range reference {
						if _, ok := setOfFieldInstances[any(fieldInstance).(FieldType)]; !ok {
							_inferedTypeInstance.{{FieldName}} =
								append(_inferedTypeInstance.{{FieldName}}, any(fieldInstance).(*{{AssociationStructName}}))
						}
					}
				}
			}
		}`,
	GongSliceSubTmplSliceOfPointersReverseMapComputation: `
	clear(stage.{{Structname}}_{{FieldName}}_reverseMap)
	stage.{{Structname}}_{{FieldName}}_reverseMap = make(map[*{{AssociationStructName}}]*{{Structname}})
	for {{structname}} := range stage.{{Structname}}s {
		_ = {{structname}}
		for _, _{{associationStructName}} := range {{structname}}.{{FieldName}} {
			stage.{{Structname}}_{{FieldName}}_reverseMap[_{{associationStructName}}] = {{structname}}
		}
	}`,
}
View Source
var GongSliceGongstructSubTemplateCode map[GongSliceGongstructInsertionId]string = map[GongSliceGongstructInsertionId]string{
	GongSliceCase: `
	case *{{Structname}}:
		// insertion point per field{{perFieldCode}}
`,
	GongSliceReverseMapCompute: `
	// Compute reverse map for named struct {{Structname}}
	// insertion point per field{{sliceOfPointerFieldReverseMapComputationCode}}
`,
}
View Source
var GongWopSubSubTemplate map[GongWopSubSubTemplateInsertionsId]string = map[GongWopSubSubTemplateInsertionsId]string{

	GongWopBasicFieldDecl: `
	{{FieldName}} {{BasicKindName}}`,

	GongWopEnumFieldDecl: `
	{{FieldName}} {{EnumType}}`,

	GongWopTimeFieldDecl: `
	{{FieldName}} time.Time`,

	GongWopDurationFieldDecl: `
	{{FieldName}} time.Duration`,

	GongWopBasicFieldCopy: `
	to.{{FieldName}} = from.{{FieldName}}`,
}
View Source
var ModelGongAstFieldSubTemplateCode map[ModelGongAstFieldInsertionId]string = map[ModelGongAstFieldInsertionId]string{
	ModelGongAstFieldAssignString: `
				case "{{FieldName}}":
					// remove first and last char
					fielValue := basicLit.Value[1 : len(basicLit.Value)-1]
					__gong__map_{{Structname}}[identifier].{{FieldName}} = fielValue`,
	ModelGongAstFieldAssignInt: `
				case "{{FieldName}}":
					// convert string to int
					fielValue, err := strconv.ParseInt(basicLit.Value, 10, 64)
					if err != nil {
						log.Fatalln(err)
					}
					__gong__map_{{Structname}}[identifier].{{FieldName}} = int(exprSign) * int(fielValue)`,
	ModelGongAstFieldAssignDuration: `
				case "{{FieldName}}":
					// convert string to duration
					fielValue, err := strconv.ParseInt(basicLit.Value, 10, 64)
					if err != nil {
						log.Fatalln(err)
					}
					__gong__map_{{Structname}}[identifier].{{FieldName}} = time.Duration(int(exprSign) * int(fielValue))`,
	ModelGongAstFieldAssignFloat64: `
				case "{{FieldName}}":
					// convert string to float64
					fielValue, err := strconv.ParseFloat(basicLit.Value, 64)
					if err != nil {
						log.Fatalln(err)
					}
					__gong__map_{{Structname}}[identifier].{{FieldName}} = exprSign * fielValue`,
	ModelGongAstFieldAssignBoolean: `
				case "{{FieldName}}":
					// convert string to boolean
					fielValue, err := strconv.ParseBool(ident.Name)
					if err != nil {
						log.Fatalln(err)
					}
					__gong__map_{{Structname}}[identifier].{{FieldName}} = fielValue`,
	ModelGongAstFieldAssignPointer: `
				case "{{FieldName}}":
					targetIdentifier := ident.Name
					__gong__map_{{Structname}}[identifier].{{FieldName}} = __gong__map_{{AssociationStructName}}[targetIdentifier]`,
	ModelGongAstFieldAssignEnum: `
					case "{{FieldName}}":
						var val {{EnumType}}
						err := (&val).FromCodeString(enumValue)
						if err != nil {
							log.Fatalln(err)
						}
						__gong__map_{{Structname}}[identifier].{{FieldName}} = {{EnumType}}(val)`,
	ModelGongAstFieldAssignDate: `
							case "{{FieldName}}":
								__gong__map_{{Structname}}[identifier].{{FieldName}}, _ = time.Parse(
									"2006-01-02 15:04:05.999999999 -0700 MST",
									date)`,
	ModelGongAstFieldAssignSliceOfPointers: `
						case "{{FieldName}}":
							// remove first and last char
							targetIdentifier := ident.Name
							target := __gong__map_{{AssociationStructName}}[targetIdentifier]
							__gong__map_{{Structname}}[identifier].{{FieldName}} =
								append(__gong__map_{{Structname}}[identifier].{{FieldName}}, target)`,
}
View Source
var ModelGongAstStructSubTemplateCode map[ModelGongAstStructInsertionId]string = map[ModelGongAstStructInsertionId]string{
	ModelGongAstGenericMaps: `
var __gong__map_{{Structname}} = make(map[string]*{{Structname}})`,
	ModelGongAstStageProcessing: `
									case "{{Structname}}":
										instance{{Structname}} := (&{{Structname}}{Name: instanceName}).Stage(stage)
										instance = any(instance{{Structname}})
										__gong__map_{{Structname}}[identifier] = instance{{Structname}}`,
	ModelGongAstBasicLitAssignment: `
			case "{{Structname}}":
				switch fieldName {
				// insertion point for field dependant code{{basicLitAssignCode}}
				}`,
	ModelGongAstIdentBooleanAndPointerAssignment: `
			case "{{Structname}}":
				switch fieldName {
				// insertion point for field dependant code{{boolAndPointerAssignCode}}
				}`,
	ModelGongAstIdentEnumAssignment: `
				case "{{Structname}}":
					switch fieldName {
					// insertion point for enum assign code{{enumAssignCode}}
					}`,
	ModelGongAstDateAssignment: `
						case "{{Structname}}":
							switch fieldName {
							// insertion point for date assign code{{dateAssignCode}}
							}`,
	ModelGongAstSliceOfPointersAssignment: `
					case "{{Structname}}":
						switch fieldName {
						// insertion point for slice of pointers assign code{{sliceOfPointersAssignCode}}
						}`,
}
View Source
var ModelGongCallbacksStructSubTemplateCode map[string]string = map[string]string{
	string(rune(ModelGongCallbacksCreate)): `
	case *{{Structname}}:
		if stage.OnAfter{{Structname}}CreateCallback != nil {
			stage.OnAfter{{Structname}}CreateCallback.OnAfterCreate(stage, target)
		}`,
	string(rune(ModelGongCallbacksUpdate)): `
	case *{{Structname}}:
		newTarget := any(new).(*{{Structname}})
		if stage.OnAfter{{Structname}}UpdateCallback != nil {
			stage.OnAfter{{Structname}}UpdateCallback.OnAfterUpdate(stage, oldTarget, newTarget)
		}`,
	string(rune(ModelGongCallbacksRead)): `
	case *{{Structname}}:
		if stage.OnAfter{{Structname}}ReadCallback != nil {
			stage.OnAfter{{Structname}}ReadCallback.OnAfterRead(stage, target)
		}`,
	string(rune(ModelGongCallbacksDelete)): `
	case *{{Structname}}:
		if stage.OnAfter{{Structname}}DeleteCallback != nil {
			staged := any(staged).(*{{Structname}})
			stage.OnAfter{{Structname}}DeleteCallback.OnAfterDelete(stage, staged, front)
		}`,
	string(rune(ModelGongCallbacksSetFuncCreate)): `
	case *{{Structname}}:
		stage.OnAfter{{Structname}}CreateCallback = any(callback).(OnAfterCreateInterface[{{Structname}}])
	`,
	string(rune(ModelGongCallbacksSetFuncUpdate)): `
	case *{{Structname}}:
		stage.OnAfter{{Structname}}UpdateCallback = any(callback).(OnAfterUpdateInterface[{{Structname}}])
	`,
	string(rune(ModelGongCallbacksSetFuncRead)): `
	case *{{Structname}}:
		stage.OnAfter{{Structname}}ReadCallback = any(callback).(OnAfterReadInterface[{{Structname}}])
	`,
	string(rune(ModelGongCallbacksSetFuncDelete)): `
	case *{{Structname}}:
		stage.OnAfter{{Structname}}DeleteCallback = any(callback).(OnAfterDeleteInterface[{{Structname}}])
	`,
}
View Source
var ModelGongCoderFieldSubTemplateCode map[ModelGongCoderFieldInsertionId]string = map[ModelGongCoderFieldInsertionId]string{
	ModelGongCoderFieldCodeString: `
		fieldCoder.{{FieldName}} = "{{Value}}"`,
	ModelGongCoderFieldCodeInt: `
		fieldCoder.{{FieldName}} = {{Value}}`,
	ModelGongCoderFieldCodeFloat64: `
		fieldCoder.{{FieldName}} = {{Value}}`,
	ModelGongCoderFieldCodeDate: `
		fieldCoder.{{FieldName}} = time.Date({{Value}}, time.January, 0, 0, 0, 0, 0, time.UTC)`,
	ModelGongCoderFieldCodeBoolean: `
		fieldCoder.{{FieldName}} = {{Value}}`,
	ModelGongCoderFieldNameString: `
			if field == "{{Value}}" {
				return "{{FieldName}}"
			}`,
	ModelGongCoderFieldNameInt: `
			if field == {{Value}} {
				return "{{FieldName}}"
			}`,
	ModelGongCoderFieldNameFloat64: `
			if field == {{Value}} {
				return "{{FieldName}}"
			}`,
	ModelGongCoderFieldNameDate: `
			if field == time.Date({{Value}}, time.January, 0, 0, 0, 0, 0, time.UTC) {
				return "{{FieldName}}"
			}`,
	ModelGongCoderFieldNameBoolean: `
			if field == {{Value}} {
				return "{{FieldName}}"
			}`,
}
View Source
var ModelGongCoderStructSubTemplateCode map[ModelGongCoderStructInsertionId]string = map[ModelGongCoderStructInsertionId]string{
	ModelGongCoderGenericGongstructTypes: ` | *{{Structname}} | []*{{Structname}}`,
	ModelGongCoderGenericGongstructCoder: `
	case {{Structname}}:
		fieldCoder := {{Structname}}{}
		// insertion point for field dependant code{{FieldCode}}
		return (any)(fieldCoder).(Type)`,
	ModelGongCoderGenericGongstructNamerString: `
	case *{{Structname}}:
		switch field := any(field).(type) {
		case string:
			// insertion point for field dependant name{{FieldNameString}}
		case int, int64:
			// insertion point for field dependant name{{FieldNameInt}}
		case float64:
			// insertion point for field dependant name{{FieldNameFloat64}}
		case time.Time:
			// insertion point for field dependant name{{FieldNameDate}}
		case bool:
			// insertion point for field dependant name{{FieldNameBoolean}}
		}`,
}
View Source
var ModelGongEnumSubTemplateCode map[ModelGongEnumInsertionId]string = map[ModelGongEnumInsertionId]string{
	ModelGongEnumUtilityFunctions: `
// Utility function for {{EnumName}}
// if enum values are string, it is stored with the value
// if enum values are int, they are stored with the code of the value
func ({{enumName}} {{EnumName}}) To{{Type}}() (res {{type}}) {

	// migration of former implementation of enum
	switch {{enumName}} {
	// insertion code per enum code{{ToStringPerCodeCode}}
	}
	return
}

func ({{enumName}} *{{EnumName}}) From{{Type}}(input {{type}}) (err error) {

	switch input {
	// insertion code per enum code{{FromStringPerCodeCode}}
	default:
		return errUnkownEnum
	}
	return
}

func ({{enumName}} *{{EnumName}}) FromCodeString(input string) (err error) {

	switch input {
	// insertion code per enum code{{FromCodeStringPerCodeCode}}
	default:
		return errUnkownEnum
	}
	return
}

func ({{enumName}} *{{EnumName}}) ToCodeString() (res string) {

	switch *{{enumName}} {
	// insertion code per enum code{{ToCodeStringPerCodeCode}}
	}
	return
}

func ({{enumName}} {{EnumName}}) Codes() (res []string) {

	res = make([]string, 0)

	// insertion code per enum code{{codes}}

	return
}

func ({{enumName}} {{EnumName}}) CodeValues() (res []{{type}}) {

	res = make([]{{type}}, 0)

	// insertion code per enum code{{codeValues}}

	return
}
`,
	ModelGongStructInsertionGenericEnumStringTypes:          ` | {{EnumName}}`,
	ModelGongStructInsertionGenericPointerToEnumStringTypes: ` | *{{EnumName}}`,
	ModelGongStructInsertionGenericEnumIntTypes:             ` | {{EnumName}}`,
	ModelGongStructInsertionGenericPointerToEnumIntTypes:    ` | *{{EnumName}}`,
}
View Source
var ModelGongGraphStructSubTemplateCode map[ModelGongGraphStructInsertionId]string = map[ModelGongGraphStructInsertionId]string{

	ModelGongGraphStructInsertionIsStaged: `
	case *{{Structname}}:
		ok = stage.IsStaged{{Structname}}(target)
`,
	ModelGongGraphStructInsertionIsStagedPerStruct: `
func (stage *StageStruct) IsStaged{{Structname}}({{structname}} *{{Structname}}) (ok bool) {

	_, ok = stage.{{Structname}}s[{{structname}}]

	return
}
`,
	ModelGongGraphStructInsertionStageBranch: `
	case *{{Structname}}:
		stage.StageBranch{{Structname}}(target)
`,
	ModelGongGraphStructInsertionStageBranchPerStruct: `
func (stage *StageStruct) StageBranch{{Structname}}({{structname}} *{{Structname}}) {

	// check if instance is already staged
	if IsStaged(stage, {{structname}}) {
		return
	}

	{{structname}}.Stage(stage)

	//insertion point for the staging of instances referenced by pointers{{StagingPointers}}

	//insertion point for the staging of instances referenced by slice of pointers{{StagingSliceOfPointers}}

}
`,
	ModelGongGraphStructInsertionCopyBranch: `
	case *{{Structname}}:
		toT := CopyBranch{{Structname}}(mapOrigCopy, fromT)
		return any(toT).(*Type)
`,
	ModelGongGraphStructInsertionCopyBranchPerStruct: `
func CopyBranch{{Structname}}(mapOrigCopy map[any]any, {{structname}}From *{{Structname}}) ({{structname}}To  *{{Structname}}){

	// {{structname}}From has already been copied
	if _{{structname}}To, ok := mapOrigCopy[{{structname}}From]; ok {
		{{structname}}To = _{{structname}}To.(*{{Structname}})
		return
	}

	{{structname}}To = new({{Structname}})
	mapOrigCopy[{{structname}}From] = {{structname}}To
	{{structname}}From.CopyBasicFields({{structname}}To)

	//insertion point for the staging of instances referenced by pointers{{CopyingPointers}}

	//insertion point for the staging of instances referenced by slice of pointers{{CopyingSliceOfPointers}}

	return
}
`,
	ModelGongGraphStructInsertionUnstageBranch: `
	case *{{Structname}}:
		stage.UnstageBranch{{Structname}}(target)
`,
	ModelGongGraphStructInsertionUnstageBranchPerStruct: `
func (stage *StageStruct) UnstageBranch{{Structname}}({{structname}} *{{Structname}}) {

	// check if instance is already staged
	if ! IsStaged(stage, {{structname}}) {
		return
	}

	{{structname}}.Unstage(stage)

	//insertion point for the staging of instances referenced by pointers{{UnstagingPointers}}

	//insertion point for the staging of instances referenced by slice of pointers{{UnstagingSliceOfPointers}}

}
`,
}
View Source
var ModelGongMarshallStructSubTemplateCode map[ModelGongMarshallStructInsertionId]string = map[ModelGongMarshallStructInsertionId]string{

	ModelGongMarshallStructInsertionUnmarshallDeclarations: `
	map_{{Structname}}_Identifiers := make(map[*{{Structname}}]string)
	_ = map_{{Structname}}_Identifiers

	{{structname}}Ordered := []*{{Structname}}{}
	for {{structname}} := range stage.{{Structname}}s {
		{{structname}}Ordered = append({{structname}}Ordered, {{structname}})
	}
	sort.Slice({{structname}}Ordered[:], func(i, j int) bool {
		return {{structname}}Ordered[i].Name < {{structname}}Ordered[j].Name
	})
	identifiersDecl += "\n\n	// Declarations of staged instances of {{Structname}}"
	for idx, {{structname}} := range {{structname}}Ordered {

		id = generatesIdentifier("{{Structname}}", idx, {{structname}}.Name)
		map_{{Structname}}_Identifiers[{{structname}}] = id

		decl = IdentifiersDecls
		decl = strings.ReplaceAll(decl, "{{Identifier}}", id)
		decl = strings.ReplaceAll(decl, "{{GeneratedStructName}}", "{{Structname}}")
		decl = strings.ReplaceAll(decl, "{{GeneratedFieldNameValue}}", {{structname}}.Name)
		identifiersDecl += decl

		initializerStatements += "\n\n	// {{Structname}} values setup"
		// Initialisation of values{{ValuesInitialization}}
	}
`,

	ModelGongMarshallStructInsertionUnmarshallPointersInitializations: `
	for idx, {{structname}} := range {{structname}}Ordered {
		var setPointerField string
		_ = setPointerField

		id = generatesIdentifier("{{Structname}}", idx, {{structname}}.Name)
		map_{{Structname}}_Identifiers[{{structname}}] = id

		// Initialisation of values{{PointersInitialization}}
	}
`,
}
View Source
var ModelGongOrchestratorStructSubTemplateCode map[string]string = map[string]string{
	string(rune(ModelGongOrchestratorStruct)): `
// {{Structname}}Orchestrator
type {{Structname}}Orchestrator struct {
}

func (orchestrator *{{Structname}}Orchestrator) OnAfterUpdate(
	gongsvgStage *StageStruct,
	staged{{Structname}}, backRepo{{Structname}} *{{Structname}}) {

	staged{{Structname}}.OnAfterUpdate(gongsvgStage, staged{{Structname}}, backRepo{{Structname}})
}`,
	string(rune(ModelGongOrchestratorSwitch)): `
	case {{Structname}}:
		stage.OnAfter{{Structname}}UpdateCallback = new({{Structname}}Orchestrator)`,
}
View Source
var ModelGongSerializeStructSubTemplateCode map[string]string = map[string]string{
	string(rune(ModelGongSerializeStruct)): `
		SerializeExcelize[{{Structname}}](stage, f)`,
}
View Source
var ModelGongStructSubTemplateCode map[ModelGongStructInsertionId]string = map[ModelGongStructInsertionId]string{
	ModelGongStructInsertionCommitCheckout: `
	Commit{{Structname}}({{structname}} *{{Structname}})
	Checkout{{Structname}}({{structname}} *{{Structname}})`,

	ModelGongStructInsertionGenericGetFields: `
	case {{Structname}}:{{ListOfFieldsName}}`,

	ModelGongStructInsertionGenericGetReverseFields: `
	case {{Structname}}:{{ListOfReverseFields}}`,

	ModelGongStructInsertionGenericGetFieldsFromPointer: `
	case *{{Structname}}:{{ListOfFieldsName}}`,

	ModelGongStructInsertionGenericGetFieldValues: `
	case {{Structname}}:
		switch fieldName {
		// string value of fields{{StringValueOfFields}}
		}`,

	ModelGongStructInsertionGenericGetFieldValuesFromPointer: `
	case *{{Structname}}:
		switch fieldName {
		// string value of fields{{StringValueOfFields}}
		}`,

	ModelGongStructInsertionStageFunctions: `
// Stage puts {{structname}} to the model stage
func ({{structname}} *{{Structname}}) Stage(stage *StageStruct) *{{Structname}} {
	stage.{{Structname}}s[{{structname}}] = __member
	stage.{{Structname}}s_mapString[{{structname}}.Name] = {{structname}}

	return {{structname}}
}

// Unstage removes {{structname}} off the model stage
func ({{structname}} *{{Structname}}) Unstage(stage *StageStruct) *{{Structname}} {
	delete(stage.{{Structname}}s, {{structname}})
	delete(stage.{{Structname}}s_mapString, {{structname}}.Name)
	return {{structname}}
}

// UnstageVoid removes {{structname}} off the model stage
func ({{structname}} *{{Structname}}) UnstageVoid(stage *StageStruct) {
	delete(stage.{{Structname}}s, {{structname}})
	delete(stage.{{Structname}}s_mapString, {{structname}}.Name)
}

// commit {{structname}} to the back repo (if it is already staged)
func ({{structname}} *{{Structname}}) Commit(stage *StageStruct) *{{Structname}} {
	if _, ok := stage.{{Structname}}s[{{structname}}]; ok {
		if stage.BackRepo != nil {
			stage.BackRepo.Commit{{Structname}}({{structname}})
		}
	}
	return {{structname}}
}

func ({{structname}} *{{Structname}}) CommitVoid(stage *StageStruct) {
	{{structname}}.Commit(stage)
}

// Checkout {{structname}} to the back repo (if it is already staged)
func ({{structname}} *{{Structname}}) Checkout(stage *StageStruct) *{{Structname}} {
	if _, ok := stage.{{Structname}}s[{{structname}}]; ok {
		if stage.BackRepo != nil {
			stage.BackRepo.Checkout{{Structname}}({{structname}})
		}
	}
	return {{structname}}
}

// for satisfaction of GongStruct interface
func ({{structname}} *{{Structname}}) GetName() (res string) {
	return {{structname}}.Name
}
`,

	ModelGongStructInsertionCreateCallback: `
	CreateORM{{Structname}}({{Structname}} *{{Structname}})`,

	ModelGongStructInsertionDeleteCallback: `
	DeleteORM{{Structname}}({{Structname}} *{{Structname}})`,

	ModelGongStructInsertionArrayDefintion: `
	{{Structname}}s           map[*{{Structname}}]any
	{{Structname}}s_mapString map[string]*{{Structname}}

	// insertion point for slice of pointers maps{{SliceOfPointersReverseMaps}}

	OnAfter{{Structname}}CreateCallback OnAfterCreateInterface[{{Structname}}]
	OnAfter{{Structname}}UpdateCallback OnAfterUpdateInterface[{{Structname}}]
	OnAfter{{Structname}}DeleteCallback OnAfterDeleteInterface[{{Structname}}]
	OnAfter{{Structname}}ReadCallback   OnAfterReadInterface[{{Structname}}]
`,

	ModelGongStructInsertionArrayInitialisation: `
		{{Structname}}s:           make(map[*{{Structname}}]any),
		{{Structname}}s_mapString: make(map[string]*{{Structname}}),
`,

	ModelGongStructInsertionArrayReset: `
	stage.{{Structname}}s = make(map[*{{Structname}}]any)
	stage.{{Structname}}s_mapString = make(map[string]*{{Structname}})
`,

	ModelGongStructInsertionArrayNil: `
	stage.{{Structname}}s = nil
	stage.{{Structname}}s_mapString = nil
`,
	ModelGongStructInsertionArrayUnstage: `
	for {{structname}} := range stage.{{Structname}}s {
		{{structname}}.Unstage(stage)
	}
`,
	ModelGongStructInsertionUnmarshallDeclarations: `
	map_{{Structname}}_Identifiers := make(map[*{{Structname}}]string)
	_ = map_{{Structname}}_Identifiers

	{{structname}}Ordered := []*{{Structname}}{}
	for {{structname}} := range stage.{{Structname}}s {
		{{structname}}Ordered = append({{structname}}Ordered, {{structname}})
	}
	sort.Slice({{structname}}Ordered[:], func(i, j int) bool {
		return {{structname}}Ordered[i].Name < {{structname}}Ordered[j].Name
	})
	identifiersDecl += "\n\n	// Declarations of staged instances of {{Structname}}"
	for idx, {{structname}} := range {{structname}}Ordered {

		id = generatesIdentifier("{{Structname}}", idx, {{structname}}.Name)
		map_{{Structname}}_Identifiers[{{structname}}] = id

		decl = IdentifiersDecls
		decl = strings.ReplaceAll(decl, "{{Identifier}}", id)
		decl = strings.ReplaceAll(decl, "{{GeneratedStructName}}", "{{Structname}}")
		decl = strings.ReplaceAll(decl, "{{GeneratedFieldNameValue}}", {{structname}}.Name)
		identifiersDecl += decl

		initializerStatements += "\n\n	// {{Structname}} values setup"
		// Initialisation of values{{ValuesInitialization}}
	}
`,

	ModelGongStructInsertionUnmarshallPointersInitializations: `
	for idx, {{structname}} := range {{structname}}Ordered {
		var setPointerField string
		_ = setPointerField

		id = generatesIdentifier("{{Structname}}", idx, {{structname}}.Name)
		map_{{Structname}}_Identifiers[{{structname}}] = id

		// Initialisation of values{{PointersInitialization}}
	}
`,

	ModelGongStructInsertionComputeNbInstances: `
	stage.Map_GongStructName_InstancesNb["{{Structname}}"] = len(stage.{{Structname}}s)`,

	ModelGongStructInsertionGenericReversePointerAssociationsMaps: `
	// reverse maps of direct associations of {{Structname}}
	case {{Structname}}:
		switch fieldname {
		// insertion point for per direct association field{{fieldReversePointerAssociationMapCode}}
		}`,

	ModelGongStructInsertionGenericReverseSliceOfPointersAssociationsMaps: `
	// reverse maps of direct associations of {{Structname}}
	case {{Structname}}:
		switch fieldname {
		// insertion point for per direct association field{{fieldReverseSliceOfPointersAssociationMapCode}}
		}`,

	ModelGongStructInsertionGenericGongstructTypes: ` | {{Structname}}`,

	ModelGongStructInsertionGenericPointerToGongstructTypes: ` | *{{Structname}}`,

	ModelGongStructInsertionGenericGongSetTypes: `
		map[*{{Structname}}]any |`,

	ModelGongStructInsertionGenericGongstructName: `
	case {{Structname}}:
		res = "{{Structname}}"`,

	ModelGongStructInsertionGenericPointerToGongstructName: `
	case *{{Structname}}:
		res = "{{Structname}}"`,

	ModelGongStructInsertionGenericGongMapTypes: `
		map[string]*{{Structname}} |`,

	ModelGongStructInsertionGenericGetSetFunctions: `
	case map[*{{Structname}}]any:
		return any(&stage.{{Structname}}s).(*Type)`,

	ModelGongStructInsertionGenericGetMapFunctions: `
	case map[string]*{{Structname}}:
		return any(&stage.{{Structname}}s_mapString).(*Type)`,

	ModelGongStructInsertionGenericInstancesSetFunctions: `
	case {{Structname}}:
		return any(&stage.{{Structname}}s).(*map[*Type]any)`,

	ModelGongStructInsertionGenericInstancesSetFromPointerTypeFunctions: `
	case *{{Structname}}:
		return any(&stage.{{Structname}}s).(*map[Type]any)`,

	ModelGongStructInsertionGenericInstancesMapFunctions: `
	case {{Structname}}:
		return any(&stage.{{Structname}}s_mapString).(*map[string]*Type)`,

	ModelGongStructInsertionGenericGetAssociationNameFunctions: `
	case {{Structname}}:
		return any(&{{Structname}}{
			// Initialisation of associations{{associationFieldInitialization}}
		}).(*Type)`,
}
View Source
var ModelGongWopStructSubTemplateCode map[ModelGongWopStructInsertionId]string = map[ModelGongWopStructInsertionId]string{
	ModelGongWopStruct: `
type {{Structname}}_WOP struct {
	// insertion point{{FieldCode}}
}

func (from *{{Structname}}) CopyBasicFields(to *{{Structname}}) {
	// insertion point{{FieldsCopyCode}}
}
`,
}

Functions

func CodeGeneratorModelGong

func CodeGeneratorModelGong(
	modelPkg *models.ModelPkg,
	pkgName string,
	pkgPath string)

func CodeGeneratorModelGongCoder

func CodeGeneratorModelGongCoder(
	modelPkg *models.ModelPkg,
	pkgName string,
	pkgPath string)

func CodeGeneratorModelGongEnum

func CodeGeneratorModelGongEnum(
	modelPkg *models.ModelPkg,
	pkgName string,
	pkgPath string)

func CodeGeneratorModelGongGraph

func CodeGeneratorModelGongGraph(
	modelPkg *models.ModelPkg,
	pkgName string,
	pkgPath string)

func CodeGeneratorModelGongMarshall

func CodeGeneratorModelGongMarshall(
	modelPkg *models.ModelPkg,
	pkgName string,
	pkgPath string)

func CodeGeneratorModelGongSlice

func CodeGeneratorModelGongSlice(
	modelPkg *models.ModelPkg,
	pkgName string,
	pkgPath string,
	pkgGoPath string)

func CodeGeneratorModelGongWop

func CodeGeneratorModelGongWop(
	modelPkg *models.ModelPkg,
	pkgName string,
	pkgPath string)

func GongAstGenerator

func GongAstGenerator(modelPkg *models.ModelPkg, pkgPath string)

Types

type GongFilePerStructSubTemplateId

type GongFilePerStructSubTemplateId int

Sub sub Templates identifiers per gong field

For each gongstruct, a code snippet will be generated from each sub template

const (
	GongFileFieldSubTmplStringFieldName GongFilePerStructSubTemplateId = iota
	GongFileFieldSubTmplReverseField

	GongFileFieldSubTmplStringValueBasicFieldBool
	GongFileFieldSubTmplStringValueBasicFieldInt
	GongFileFieldSubTmplStringValueBasicFieldIntDuration
	GongFileFieldSubTmplStringValueBasicFieldEnumString
	GongFileFieldSubTmplStringValueBasicFieldEnumInt
	GongFileFieldSubTmplStringValueBasicFieldFloat64
	GongFileFieldSubTmplStringValueBasicFieldString
	GongFileFieldSubTmplStringValueTimeField
	GongFileFieldSubTmplStringValuePointerField
	GongFileFieldSubTmplStringValueSliceOfPointersField

	GongFileFieldSubTmplAssociationNamePointerField
	GongFileFieldSubTmplAssociationNameSliceOfPointersField
	GongFileFieldSubTmplAssociationNameEnclosingCompositePointerField
	GongFileFieldSubTmplAssociationNameCompositePointerField

	GongFileFieldSubTmplPointerFieldPointerAssociationMapFunction
	GongFileFieldSubTmplPointerFieldSliceOfPointersAssociationMapFunction

	GongFileSliceOfPointersReverseMap
)

type GongGraphFilePerStructSubTemplateId

type GongGraphFilePerStructSubTemplateId int
const (
	GongGraphFileFieldSubTmplStagePointerField GongGraphFilePerStructSubTemplateId = iota
	GongGraphFileFieldSubTmplStageSliceOfPointersField
	GongGraphFileFieldSubTmplCopyPointerField
	GongGraphFileFieldSubTmplCopySliceOfPointersField
	GongGraphFileFieldSubTmplUnstagePointerField
	GongGraphFileFieldSubTmplUnstageSliceOfPointersField
)

type GongMarshallFilePerStructSubTemplateId

type GongMarshallFilePerStructSubTemplateId int
const (
	GongMarshallFileFieldSubTmplSetBasicFieldBool GongMarshallFilePerStructSubTemplateId = iota
	GongMarshallFileFieldSubTmplSetBasicFieldInt
	GongMarshallFileFieldSubTmplSetBasicFieldEnumString
	GongMarshallFileFieldSubTmplSetBasicFieldEnumInt
	GongMarshallFileFieldSubTmplSetBasicFieldFloat64
	GongMarshallFileFieldSubTmplSetBasicFieldString
	GongMarshallFileFieldSubTmplSetBasicFieldStringDocLink
	GongMarshallFileFieldSubTmplSetTimeField
	GongMarshallFileFieldSubTmplSetPointerField
	GongMarshallFileFieldSubTmplSetSliceOfPointersField
)

type GongModelEnumValueSubTemplateId

type GongModelEnumValueSubTemplateId int

gongenum value template

const (
	GongModelEnumValueFromString GongModelEnumValueSubTemplateId = iota
	GongModelEnumValueFromCodeString
	GongModelEnumValueToString
	GongModelEnumValueToCodeString
	GongModelEnumCodes
	GongModelEnumCodeValues
)

type GongSliceGongstructInsertionId

type GongSliceGongstructInsertionId int
const (
	GongSliceCase GongSliceGongstructInsertionId = iota
	GongSliceReverseMapCompute
	GongSliceGongstructInsertionNb
)

type GongSliceSubTemplateId

type GongSliceSubTemplateId int
const (
	GongSliceSubTmplSliceOfPointersToStruct GongSliceSubTemplateId = iota
	GongSliceSubTmplSliceOfPointersReverseMapComputation
)

type GongWopSubSubTemplateInsertionsId

type GongWopSubSubTemplateInsertionsId int
const (
	GongWopBasicFieldDecl GongWopSubSubTemplateInsertionsId = iota + 100
	GongWopEnumFieldDecl
	GongWopTimeFieldDecl
	GongWopDurationFieldDecl
	GongWopBasicFieldCopy
)

type ModelGongAstFieldInsertionId

type ModelGongAstFieldInsertionId int
const (
	ModelGongAstFieldAssignString ModelGongAstFieldInsertionId = iota
	ModelGongAstFieldAssignInt
	ModelGongAstFieldAssignFloat64
	ModelGongAstFieldAssignDate
	ModelGongAstFieldAssignDuration
	ModelGongAstFieldAssignBoolean
	ModelGongAstFieldAssignPointer
	ModelGongAstFieldAssignSliceOfPointers
	ModelGongAstFieldAssignEnum

	ModelGongAstFieldInsertionsNb
)

type ModelGongAstStructInsertionId

type ModelGongAstStructInsertionId int

insertion points are places where the code is generated per gong struct

const (
	ModelGongAstGenericMaps ModelGongAstStructInsertionId = iota
	ModelGongAstStageProcessing
	ModelGongAstBasicLitAssignment
	ModelGongAstIdentBooleanAndPointerAssignment
	ModelGongAstIdentEnumAssignment
	ModelGongAstDateAssignment
	ModelGongAstSliceOfPointersAssignment
	ModelGongAstStructInsertionsNb
)

type ModelGongCallbacksStructInsertionId

type ModelGongCallbacksStructInsertionId int
const (
	ModelGongCallbacksCreate ModelGongCallbacksStructInsertionId = iota
	ModelGongCallbacksUpdate
	ModelGongCallbacksRead
	ModelGongCallbacksDelete
	ModelGongCallbacksSetFuncCreate
	ModelGongCallbacksSetFuncUpdate
	ModelGongCallbacksSetFuncRead
	ModelGongCallbacksSetFuncDelete
)

type ModelGongCoderFieldInsertionId

type ModelGongCoderFieldInsertionId int
const (
	ModelGongCoderFieldCodeString ModelGongCoderFieldInsertionId = iota
	ModelGongCoderFieldCodeInt
	ModelGongCoderFieldCodeFloat64
	ModelGongCoderFieldCodeDate
	ModelGongCoderFieldCodeBoolean
	ModelGongCoderFieldNameString
	ModelGongCoderFieldNameInt
	ModelGongCoderFieldNameFloat64
	ModelGongCoderFieldNameDate
	ModelGongCoderFieldNameBoolean
	ModelGongCoderFieldInsertionsNb
)

type ModelGongCoderStructInsertionId

type ModelGongCoderStructInsertionId int

insertion points are places where the code is generated per gong struct

const (
	ModelGongCoderGenericGongstructTypes ModelGongCoderStructInsertionId = iota
	ModelGongCoderGenericGongstructCoder
	ModelGongCoderGenericGongstructNamerString
	ModelGongCoderStructInsertionsNb
)

type ModelGongEnumInsertionId

type ModelGongEnumInsertionId int

insertion code for all enums

const (
	// iota + 40 is to separate the insertion code of gongstruct from insertion code of gongenum
	ModelGongEnumUtilityFunctions ModelGongEnumInsertionId = iota + 40

	ModelGongStructInsertionGenericEnumStringTypes
	ModelGongStructInsertionGenericPointerToEnumStringTypes
	ModelGongStructInsertionGenericEnumIntTypes
	ModelGongStructInsertionGenericPointerToEnumIntTypes

	ModelGongEnumInsertionsNb
)

type ModelGongGraphStructInsertionId

type ModelGongGraphStructInsertionId int

insertion points are places where the code is generated per gong struct

const (
	ModelGongGraphStructInsertionIsStaged ModelGongGraphStructInsertionId = iota
	ModelGongGraphStructInsertionIsStagedPerStruct
	ModelGongGraphStructInsertionStageBranch
	ModelGongGraphStructInsertionStageBranchPerStruct
	ModelGongGraphStructInsertionCopyBranch
	ModelGongGraphStructInsertionCopyBranchPerStruct
	ModelGongGraphStructInsertionUnstageBranch
	ModelGongGraphStructInsertionUnstageBranchPerStruct
	ModelGongGraphStructInsertionsNb
)

type ModelGongMarshallStructInsertionId

type ModelGongMarshallStructInsertionId int

insertion points are places where the code is generated per gong struct

const (
	ModelGongMarshallStructInsertionUnmarshallDeclarations ModelGongMarshallStructInsertionId = iota
	ModelGongMarshallStructInsertionUnmarshallPointersInitializations
	ModelGongMarshallStructInsertionsNb
)

type ModelGongOrchestratorStructInsertionId

type ModelGongOrchestratorStructInsertionId int
const (
	ModelGongOrchestratorStruct ModelGongOrchestratorStructInsertionId = iota
	ModelGongOrchestratorSwitch
)

type ModelGongSerializeStructInsertionId

type ModelGongSerializeStructInsertionId int
const (
	ModelGongSerializeStruct ModelGongSerializeStructInsertionId = iota
)

type ModelGongStructInsertionId

type ModelGongStructInsertionId int

insertion points are places where the code is generated per gong struct

const (
	ModelGongStructInsertionCommitCheckout ModelGongStructInsertionId = iota
	ModelGongStructInsertionStageFunctions
	ModelGongStructInsertionCreateCallback
	ModelGongStructInsertionDeleteCallback
	ModelGongStructInsertionArrayDefintion
	ModelGongStructInsertionArrayInitialisation
	ModelGongStructInsertionArrayReset
	ModelGongStructInsertionArrayNil
	ModelGongStructInsertionArrayUnstage
	ModelGongStructInsertionUnmarshallDeclarations
	ModelGongStructInsertionUnmarshallPointersInitializations
	ModelGongStructInsertionComputeNbInstances

	ModelGongStructInsertionGenericGetFields
	ModelGongStructInsertionGenericGetReverseFields
	ModelGongStructInsertionGenericGetFieldsFromPointer
	ModelGongStructInsertionGenericGetFieldValues
	ModelGongStructInsertionGenericGetFieldValuesFromPointer

	ModelGongStructInsertionGenericReversePointerAssociationsMaps
	ModelGongStructInsertionGenericReverseSliceOfPointersAssociationsMaps

	ModelGongStructInsertionGenericGongSetTypes
	ModelGongStructInsertionGenericGongstructName
	ModelGongStructInsertionGenericPointerToGongstructName
	ModelGongStructInsertionGenericGongMapTypes
	ModelGongStructInsertionGenericGetSetFunctions
	ModelGongStructInsertionGenericGetMapFunctions
	ModelGongStructInsertionGenericInstancesSetFunctions
	ModelGongStructInsertionGenericInstancesSetFromPointerTypeFunctions
	ModelGongStructInsertionGenericInstancesSetFromPointerTypeFunctionsReturnType

	ModelGongStructInsertionGenericInstancesMapFunctions
	ModelGongStructInsertionGenericGetAssociationNameFunctions

	ModelGongStructInsertionGenericGongstructTypes
	ModelGongStructInsertionGenericPointerToGongstructTypes

	ModelGongStructInsertionsNb
)

type ModelGongWopStructInsertionId

type ModelGongWopStructInsertionId int
const (
	ModelGongWopStruct ModelGongWopStructInsertionId = iota
	ModelGongWopStructInsertionsNb
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL