From 826a8e5b94dd998c93da1c0f9bb0b2ac7c6251f6 Mon Sep 17 00:00:00 2001 From: Franco Liberali Date: Sat, 16 Dec 2023 18:22:51 -0300 Subject: [PATCH] Feature/preloading (#4) * update mockery version * fix typos in Authentication, resource and constructor * fix route for auth unit tests * remove error that is always nil * add TODO to the changes to be done in the session service * add error management to middlewareJSON * add CommandInitializer to init configuration keys * init database configuration keys * init session configuration keys * init initialization configuration keys * init server configuration keys * init logger configuration keys * remove unused r.md file in commands * move time to utils * create super user when adding the auth controller * update info controller and routes creation * change the way badaas server is created * move test e2e to test_e2e/ and docker to docker/ * do not run auto migration on test e2e execution + automigration refactor * update docs and developers utils * remove unnecesary init.sh for cockroach and add health check * move db connection to orm module and make automigration possible by fx * info and auth modules now also provide the corresponding services and middlewares * use gotestsum to run tests + create tests report + tool to install dependencies * add base models to orm * add crud services and repositories in orm module * adapt existing services and controllers to use orm module * add integration tests * update documentation * update changelog * add support for operators in conditions * add noteq * add lt * add ltoreq * add gt * add gtoreq * add isnull * add isnotnull * add is true * add is not true * add is false * add is not false * add is unknown * add is not unknown * add is distict * add is not distict * add array in * add array not in * add like * add between * add not between * add and * add or * add not * add unsafe conditions * use all coverage files in sonar * ignore all tests results * update changelog * create mocks for new types * replace inverse join generation by inverse reference in models * table class in place of strings for table name * update to conditions generation that fix embedded names * refactor: add field identifier * add possibility to do preload * support nested preloads * add a way to know if a relation was loaded or not * list and nested attributes preload * update mocks * update changelog * cli: preload --- changelog.md | 1 + cli/Makefile | 6 +- cli/changelog.md | 1 + cli/cmd/gen/conditions/codeGenerator.go | 6 + cli/cmd/gen/conditions/condition.go | 198 +++- cli/cmd/gen/conditions/conditionsGenerator.go | 118 +++ cli/cmd/gen/conditions/embeddedField.go | 34 + cli/cmd/gen/conditions/field.go | 28 +- cli/cmd/gen/conditions/file.go | 79 +- cli/cmd/gen/conditions/main.go | 57 +- cli/cmd/gen/conditions/main_test.go | 67 +- .../conditions/relationGettersGenerator.go | 224 +++++ .../tests/belongsto/badaas-orm_result.go | 8 + .../conditions/tests/goembedded/goembedded.go | 3 +- .../tests/gormembedded/gormembedded.go | 4 +- .../tests/hasmany/badaas-orm_result.go | 11 + .../gen/conditions/tests/hasmany/hasmany.go | 5 +- .../hasmanywithpointers/badaas-orm_result.go | 11 + .../hasmanywithpointers.go | 18 + .../tests/hasone/badaas-orm_result.go | 11 + cli/cmd/gen/conditions/tests/hasone/hasone.go | 1 + .../package1/badaas-orm_result.go | 11 + .../overrideforeignkey/badaas-orm_result.go | 8 + .../badaas-orm_result.go | 8 + .../overridereferences/badaas-orm_result.go | 8 + .../badaas-orm_result.go | 8 + .../conditions/tests/results/basicpointers.go | 144 ++- .../conditions/tests/results/basicslices.go | 144 ++- .../tests/results/basicslicespointer.go | 144 ++- .../conditions/tests/results/basictypes.go | 144 ++- .../tests/results/belongsto_owned.go | 37 +- .../tests/results/belongsto_owner.go | 18 +- .../tests/results/columndefinition.go | 25 +- .../conditions/tests/results/customtype.go | 25 +- .../conditions/tests/results/goembedded.go | 40 +- .../conditions/tests/results/gormembedded.go | 51 +- .../tests/results/hasmany_company.go | 27 +- .../tests/results/hasmany_seller.go | 36 +- .../results/hasmanywithpointers_company.go | 39 + .../results/hasmanywithpointers_seller.go | 55 ++ .../conditions/tests/results/hasone_city.go | 36 +- .../tests/results/hasone_country.go | 37 +- .../tests/results/multiplepackage_package1.go | 37 +- .../tests/results/multiplepackage_package2.go | 44 + .../conditions/tests/results/nullabletypes.go | 74 +- ...gnkey.go => overrideforeignkey_bicycle.go} | 37 +- .../results/overrideforeignkey_person.go | 35 + .../overrideforeignkeyinverse_credit_card.go | 44 + ...e.go => overrideforeignkeyinverse_user.go} | 37 +- .../tests/results/overridereferences_brand.go | 44 + ...erences.go => overridereferences_phone.go} | 37 +- ... => overridereferencesinverse_computer.go} | 44 +- .../overridereferencesinverse_processor.go | 44 + .../tests/results/selfreferential.go | 37 +- .../gen/conditions/tests/results/uintmodel.go | 22 +- .../gen/conditions/tests/results/uuidmodel.go | 18 +- .../selfreferential/badaas-orm_result.go | 8 + cli/cmd/gen/conditions/type.go | 37 +- cli/cmd/gen/docker_test.go | 23 +- cli/cmd/testutils/file.go | 31 + cli/cmd/utils/slice.go | 15 + cli/cmd/utils/slice_test.go | 59 ++ cli/go.mod | 4 +- cli/go.sum | 4 +- mocks/configuration/Holder.go | 38 + mocks/orm/CRUDRepository.go | 4 +- mocks/orm/CRUDService.go | 4 +- mocks/orm/Condition.go | 23 +- mocks/orm/IJoinCondition.go | 88 ++ mocks/orm/Model.go | 39 + mocks/orm/ModelID.go | 39 + mocks/orm/WhereCondition.go | 45 +- orm/ModuleFx.go | 8 +- orm/README.md | 2 +- orm/baseModels.go | 41 +- orm/condition.go | 379 ++++++-- orm/crudRepository.go | 37 +- orm/crudService.go | 6 +- orm/orm.go | 2 +- orm/preload.go | 41 + orm/uuid.go | 6 +- persistence/models/User.go | 4 +- testintegration/asserts.go | 3 +- .../conditions/bicycle_conditions.go | 44 +- .../conditions/brand_conditions.go | 29 +- .../conditions/child_conditions.go | 75 ++ testintegration/conditions/city_conditions.go | 43 +- .../conditions/company_conditions.go | 34 +- .../conditions/country_conditions.go | 44 +- .../conditions/employee_conditions.go | 44 +- .../conditions/parent1_conditions.go | 56 ++ .../conditions/parent2_conditions.go | 56 ++ .../conditions/parent_parent_conditions.go | 45 + .../conditions/person_conditions.go | 25 +- .../conditions/phone_conditions.go | 48 +- .../conditions/product_conditions.go | 101 +- testintegration/conditions/sale_conditions.go | 69 +- .../conditions/seller_conditions.go | 62 +- .../conditions/university_conditions.go | 45 + testintegration/crudServiceCommon.go | 10 + testintegration/db_models.go | 4 + testintegration/join_conditions_test.go | 12 +- testintegration/models/badaas-orm.go | 47 + testintegration/models/models.go | 69 +- testintegration/orm_test.go | 5 + testintegration/preload_conditions_test.go | 887 ++++++++++++++++++ testintegration/where_conditions_test.go | 6 +- utils/slice.go | 15 + utils/slice_test.go | 59 ++ 109 files changed, 4436 insertions(+), 978 deletions(-) create mode 100644 cli/cmd/gen/conditions/codeGenerator.go create mode 100644 cli/cmd/gen/conditions/conditionsGenerator.go create mode 100644 cli/cmd/gen/conditions/embeddedField.go create mode 100644 cli/cmd/gen/conditions/relationGettersGenerator.go create mode 100644 cli/cmd/gen/conditions/tests/belongsto/badaas-orm_result.go create mode 100644 cli/cmd/gen/conditions/tests/hasmany/badaas-orm_result.go create mode 100644 cli/cmd/gen/conditions/tests/hasmanywithpointers/badaas-orm_result.go create mode 100644 cli/cmd/gen/conditions/tests/hasmanywithpointers/hasmanywithpointers.go create mode 100644 cli/cmd/gen/conditions/tests/hasone/badaas-orm_result.go create mode 100644 cli/cmd/gen/conditions/tests/multiplepackage/package1/badaas-orm_result.go create mode 100644 cli/cmd/gen/conditions/tests/overrideforeignkey/badaas-orm_result.go create mode 100644 cli/cmd/gen/conditions/tests/overrideforeignkeyinverse/badaas-orm_result.go create mode 100644 cli/cmd/gen/conditions/tests/overridereferences/badaas-orm_result.go create mode 100644 cli/cmd/gen/conditions/tests/overridereferencesinverse/badaas-orm_result.go create mode 100644 cli/cmd/gen/conditions/tests/results/hasmanywithpointers_company.go create mode 100644 cli/cmd/gen/conditions/tests/results/hasmanywithpointers_seller.go create mode 100644 cli/cmd/gen/conditions/tests/results/multiplepackage_package2.go rename cli/cmd/gen/conditions/tests/results/{overrideforeignkey.go => overrideforeignkey_bicycle.go} (56%) create mode 100644 cli/cmd/gen/conditions/tests/results/overrideforeignkey_person.go create mode 100644 cli/cmd/gen/conditions/tests/results/overrideforeignkeyinverse_credit_card.go rename cli/cmd/gen/conditions/tests/results/{overrideforeignkeyinverse.go => overrideforeignkeyinverse_user.go} (58%) create mode 100644 cli/cmd/gen/conditions/tests/results/overridereferences_brand.go rename cli/cmd/gen/conditions/tests/results/{overridereferences.go => overridereferences_phone.go} (57%) rename cli/cmd/gen/conditions/tests/results/{overridereferencesinverse.go => overridereferencesinverse_computer.go} (58%) create mode 100644 cli/cmd/gen/conditions/tests/results/overridereferencesinverse_processor.go create mode 100644 cli/cmd/gen/conditions/tests/selfreferential/badaas-orm_result.go create mode 100644 cli/cmd/testutils/file.go create mode 100644 cli/cmd/utils/slice.go create mode 100644 cli/cmd/utils/slice_test.go create mode 100644 mocks/configuration/Holder.go create mode 100644 mocks/orm/IJoinCondition.go create mode 100644 mocks/orm/Model.go create mode 100644 mocks/orm/ModelID.go create mode 100644 orm/preload.go create mode 100644 testintegration/conditions/child_conditions.go create mode 100644 testintegration/conditions/parent1_conditions.go create mode 100644 testintegration/conditions/parent2_conditions.go create mode 100644 testintegration/conditions/parent_parent_conditions.go create mode 100644 testintegration/conditions/university_conditions.go create mode 100644 testintegration/models/badaas-orm.go create mode 100644 testintegration/preload_conditions_test.go create mode 100644 utils/slice.go create mode 100644 utils/slice_test.go diff --git a/changelog.md b/changelog.md index 24def01..6ad700f 100644 --- a/changelog.md +++ b/changelog.md @@ -33,5 +33,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Transform BadAas into a library. - Add badaas-orm with the compilable query system. - Add operators support +- Add preloading [unreleased]: https://github.com/ditrit/badaas/blob/main/changelog.md#unreleased diff --git a/cli/Makefile b/cli/Makefile index e65468f..4152766 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -1,7 +1,11 @@ lint: golangci-lint run -test_unit: +test_unit: clean_test_unit_results go test ./... -v +clean_test_unit_results: + rm -f cmd/gen/conditions/*_conditions.go + rm -f cmd/gen/conditions/tests/**/badaas-orm.go + .PHONY: test_unit \ No newline at end of file diff --git a/cli/changelog.md b/cli/changelog.md index 44c4cfd..1e4b85c 100644 --- a/cli/changelog.md +++ b/cli/changelog.md @@ -12,5 +12,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add generation of docker and configuration files - Add gen conditions to generate the conditions for the badaas' compilable query system. - Add support for operators in condition generation. +- Add preload conditions generation. [unreleased]: https://github.com/ditrit/badaas-orm/cli/blob/main/changelog.md#unreleased \ No newline at end of file diff --git a/cli/cmd/gen/conditions/codeGenerator.go b/cli/cmd/gen/conditions/codeGenerator.go new file mode 100644 index 0000000..7671dc3 --- /dev/null +++ b/cli/cmd/gen/conditions/codeGenerator.go @@ -0,0 +1,6 @@ +package conditions + +type CodeGenerator[T any] interface { + Into(file *File) error + ForEachField(file *File, fields []Field) []T +} diff --git a/cli/cmd/gen/conditions/condition.go b/cli/cmd/gen/conditions/condition.go index 176f672..b311099 100644 --- a/cli/cmd/gen/conditions/condition.go +++ b/cli/cmd/gen/conditions/condition.go @@ -11,18 +11,39 @@ import ( const ( // badaas/orm/condition.go - badaasORMCondition = "Condition" - badaasORMFieldCondition = "FieldCondition" - badaasORMWhereCondition = "WhereCondition" - badaasORMJoinCondition = "JoinCondition" + badaasORMCondition = "Condition" + badaasORMFieldCondition = "FieldCondition" + badaasORMWhereCondition = "WhereCondition" + badaasORMJoinCondition = "JoinCondition" + badaasORMIJoinCondition = "IJoinCondition" + badaasORMFieldIdentifier = "FieldIdentifier" + badaasORMNewCollectionPreload = "NewCollectionPreloadCondition" + IDFieldID = "IDFieldID" + CreatedAtFieldID = "CreatedAtFieldID" + UpdatedAtFieldID = "UpdatedAtFieldID" + DeletedAtFieldID = "DeletedAtFieldID" // badaas/orm/operator.go badaasORMOperator = "Operator" + // badaas/orm/baseModels.go + uIntID = "UIntID" + uuid = "UUID" + uuidModel = "UUIDModel" + uIntModel = "UIntModel" ) +var constantFieldIdentifiers = map[string]*jen.Statement{ + "ID": jen.Qual(badaasORMPath, IDFieldID), + "CreatedAt": jen.Qual(badaasORMPath, CreatedAtFieldID), + "UpdatedAt": jen.Qual(badaasORMPath, UpdatedAtFieldID), + "DeletedAt": jen.Qual(badaasORMPath, DeletedAtFieldID), +} + type Condition struct { - codes []jen.Code - param *JenParam - destPkg string + codes []jen.Code + param *JenParam + destPkg string + fieldIdentifier string + preloadName string } func NewCondition(destPkg string, objectType Type, field Field) *Condition { @@ -86,11 +107,8 @@ func (condition *Condition) generateForSlice(objectType Type, field Field) { // slice of named types (user defined types) _, err := field.Type.BadaasModelStruct() if err == nil { - // slice of Badaas models -> hasMany relation - condition.generateInverseJoin( - objectType, - field, - ) + // field is a Badaas Model + condition.generateCollectionPreload(objectType, field) } case *types.Pointer: // slice of pointers, generate code for a slice of the pointed type @@ -117,9 +135,10 @@ func (condition *Condition) generateForNamedType(objectType Type, field Field) { objectType, field, ) - } else if field.Type.IsGormCustomType() || field.TypeString() == "time.Time" { + } else if field.Type.IsGormCustomType() || field.TypeString() == "time.Time" || field.IsModelID() { // field is a Gorm Custom type (implements Scanner and Valuer interfaces) // or a named type supported by gorm (time.Time) + // or a badaas-orm id (uuid or uintid) condition.param.ToCustomType(condition.destPkg, field.Type) condition.generateWhere( objectType, @@ -132,24 +151,19 @@ func (condition *Condition) generateForNamedType(objectType Type, field Field) { // Generate condition between object and field when the field is a Badaas Model func (condition *Condition) generateForBadaasModel(objectType Type, field Field) { - hasFK, _ := objectType.HasFK(field) - if hasFK { - // belongsTo relation + _, err := objectType.GetFK(field) + if err == nil { + // has the fk -> belongsTo relation condition.generateJoinWithFK( objectType, field, ) } else { - // hasOne relation + // has not the fk -> hasOne relation condition.generateJoinWithoutFK( objectType, field, ) - - condition.generateInverseJoin( - objectType, - field, - ) } } @@ -176,20 +190,12 @@ func (condition *Condition) generateWhere(objectType Type, field Field) { conditionName := getConditionName(objectType, field) log.Logger.Debugf("Generated %q", conditionName) - conditionValues := jen.Dict{ - jen.Id("Operator"): jen.Id("operator"), - } - columnName := field.getColumnName() + var fieldIdentifier *jen.Statement - if columnName != "" { - conditionValues[jen.Id("Column")] = jen.Lit(columnName) + if constantFieldIdentifier, ok := constantFieldIdentifiers[field.Name]; ok { + fieldIdentifier = constantFieldIdentifier } else { - conditionValues[jen.Id("Field")] = jen.Lit(field.Name) - } - - columnPrefix := field.ColumnPrefix - if columnPrefix != "" { - conditionValues[jen.Id("ColumnPrefix")] = jen.Lit(columnPrefix) + fieldIdentifier = condition.createFieldIdentifier(field, conditionName) } condition.codes = append( @@ -202,22 +208,48 @@ func (condition *Condition) generateWhere(objectType Type, field Field) { whereCondition, ).Block( jen.Return( - fieldCondition.Clone().Values(conditionValues), + fieldCondition.Clone().Values(jen.Dict{ + jen.Id("Operator"): jen.Id("operator"), + jen.Id("FieldIdentifier"): fieldIdentifier, + }), ), ), ) } -// Generate a inverse JoinCondition, so from the field's object to the object -func (condition *Condition) generateInverseJoin(objectType Type, field Field) { - condition.generateJoinWithFK( - field.Type, - Field{ - Name: objectType.Name(), - Type: objectType, - Tags: field.Tags, - }, +// create a variable containing the definition of the field identifier +// to use it in the where condition and in the preload condition +func (condition *Condition) createFieldIdentifier(field Field, conditionName string) *jen.Statement { + fieldIdentifierValues := jen.Dict{} + columnName := field.getColumnName() + + if columnName != "" { + fieldIdentifierValues[jen.Id("Column")] = jen.Lit(columnName) + } else { + fieldIdentifierValues[jen.Id("Field")] = jen.Lit(field.Name) + } + + columnPrefix := field.ColumnPrefix + if columnPrefix != "" { + fieldIdentifierValues[jen.Id("ColumnPrefix")] = jen.Lit(columnPrefix) + } + + fieldIdentifierVar := jen.Qual( + badaasORMPath, badaasORMFieldIdentifier, + ).Values(fieldIdentifierValues) + + fieldIdentifierName := strcase.ToCamel(conditionName) + "FieldID" + + condition.codes = append( + condition.codes, + jen.Var().Id( + fieldIdentifierName, + ).Op("=").Add(fieldIdentifierVar), ) + + condition.fieldIdentifier = fieldIdentifierName + + return jen.Qual("", fieldIdentifierName) } // Generate a JoinCondition between the object and field's object @@ -258,8 +290,8 @@ func (condition *Condition) generateJoin(objectType Type, field Field, t1Field, conditionName := getConditionName(objectType, field) log.Logger.Debugf("Generated %q", conditionName) - ormT1Condition := jen.Qual( - badaasORMPath, badaasORMCondition, + ormT1IJoinCondition := jen.Qual( + badaasORMPath, badaasORMIJoinCondition, ).Types(t1) ormT2Condition := jen.Qual( badaasORMPath, badaasORMCondition, @@ -277,22 +309,86 @@ func (condition *Condition) generateJoin(objectType Type, field Field, t1Field, ).Params( jen.Id("conditions").Op("...").Add(ormT2Condition), ).Add( - ormT1Condition, + ormT1IJoinCondition, ).Block( jen.Return( ormJoinCondition.Values(jen.Dict{ - jen.Id("T1Field"): jen.Lit(t1Field), - jen.Id("T2Field"): jen.Lit(t2Field), - jen.Id("Conditions"): jen.Id("conditions"), + jen.Id("T1Field"): jen.Lit(t1Field), + jen.Id("T2Field"): jen.Lit(t2Field), + jen.Id("RelationField"): jen.Lit(field.Name), + jen.Id("Conditions"): jen.Id("conditions"), + jen.Id("T1PreloadCondition"): jen.Id(getPreloadAttributesName(objectType.Name())), }), ), ), ) + + // preload for the relation + preloadName := getPreloadRelationName(objectType, field) + condition.codes = append( + condition.codes, + jen.Var().Id( + preloadName, + ).Op("=").Add(jen.Id(conditionName)).Call( + jen.Id(getPreloadAttributesName(field.TypeName())), + ), + ) + condition.preloadName = preloadName +} + +func getPreloadRelationName(objectType Type, field Field) string { + return objectType.Name() + "Preload" + field.Name +} + +func (condition *Condition) generateCollectionPreload(objectType Type, field Field) { + t1 := jen.Qual( + getRelativePackagePath(condition.destPkg, objectType), + objectType.Name(), + ) + + t2 := jen.Qual( + getRelativePackagePath(condition.destPkg, field.Type), + field.TypeName(), + ) + + ormT1Condition := jen.Qual( + badaasORMPath, badaasORMCondition, + ).Types(t1) + ormT2IJoinCondition := jen.Qual( + badaasORMPath, badaasORMIJoinCondition, + ).Types(t2) + ormNewCollectionPreload := jen.Qual( + badaasORMPath, badaasORMNewCollectionPreload, + ).Types( + t1, t2, + ) + + preloadName := getPreloadRelationName(objectType, field) + + condition.codes = append( + condition.codes, + jen.Func().Id( + preloadName, + ).Params( + jen.Id("nestedPreloads").Op("...").Add(ormT2IJoinCondition), + ).Add( + ormT1Condition, + ).Block( + jen.Return( + ormNewCollectionPreload.Call( + jen.Lit(field.Name), + jen.Id("nestedPreloads"), + ), + ), + ), + ) + + condition.preloadName = preloadName + "()" } // Generate condition names func getConditionName(typeV Type, field Field) string { - return typeV.Name() + strcase.ToPascal(field.ColumnPrefix) + strcase.ToPascal(field.Name) + return typeV.Name() + strcase.ToPascal(field.NamePrefix) + strcase.ToPascal(field.Name) } // Avoid importing the same package as the destination one diff --git a/cli/cmd/gen/conditions/conditionsGenerator.go b/cli/cmd/gen/conditions/conditionsGenerator.go new file mode 100644 index 0000000..7bdf29c --- /dev/null +++ b/cli/cmd/gen/conditions/conditionsGenerator.go @@ -0,0 +1,118 @@ +package conditions + +import ( + "go/types" + + "github.com/dave/jennifer/jen" + + "github.com/ditrit/badaas-orm/cli/cmd/log" +) + +const badaasORMNewPreloadCondition = "NewPreloadCondition" + +type ConditionsGenerator struct { + object types.Object + objectType Type +} + +func NewConditionsGenerator(object types.Object) *ConditionsGenerator { + return &ConditionsGenerator{ + object: object, + objectType: Type{object.Type()}, + } +} + +// Add conditions for an object in the file +func (cg ConditionsGenerator) Into(file *File) error { + fields, err := getFields(cg.objectType) + if err != nil { + return err + } + + log.Logger.Infof("Generating conditions for type %q in %s", cg.object.Name(), file.name) + + // Add one condition for each field of the object + conditions := cg.ForEachField(file, fields) + + objectName := cg.object.Name() + objectQual := jen.Qual( + getRelativePackagePath(file.destPkg, cg.objectType), + cg.objectType.Name(), + ) + + preloadAttributesCondition := jen.Var().Id( + getPreloadAttributesName(objectName), + ).Op("=").Add(jen.Qual( + badaasORMPath, badaasORMNewPreloadCondition, + )).Types( + objectQual, + ) + fieldIdentifiers := []jen.Code{} + + preloadRelationsCondition := jen.Var().Id( + objectName + "PreloadRelations", + ).Op("=").Index().Add(jen.Qual( + badaasORMPath, badaasORMCondition, + )).Types( + objectQual, + ) + relationPreloads := []jen.Code{} + + for _, condition := range conditions { + file.Add(condition.codes...) + + // add all field names to the list of fields of the preload condition + if condition.fieldIdentifier != "" { + fieldIdentifiers = append( + fieldIdentifiers, + jen.Qual("", condition.fieldIdentifier), + ) + } + + // add the preload to the list of all possible preloads + if condition.preloadName != "" { + relationPreloads = append( + relationPreloads, + jen.Qual("", condition.preloadName), + ) + } + } + + file.Add(preloadAttributesCondition.Call(fieldIdentifiers...)) + + if len(relationPreloads) > 0 { + file.Add(preloadRelationsCondition.Values(relationPreloads...)) + } + + return nil +} + +func getPreloadAttributesName(objectName string) string { + return objectName + "PreloadAttributes" +} + +// Generate the conditions for each of the object's fields +func (cg ConditionsGenerator) ForEachField(file *File, fields []Field) []Condition { + conditions := []Condition{} + + for _, field := range fields { + log.Logger.Debugf("Generating condition for field %q", field.Name) + + if field.Embedded { + conditions = append( + conditions, + generateForEmbeddedField[Condition]( + file, + field, + cg, + )..., + ) + } else { + conditions = append(conditions, *NewCondition( + file.destPkg, cg.objectType, field, + )) + } + } + + return conditions +} diff --git a/cli/cmd/gen/conditions/embeddedField.go b/cli/cmd/gen/conditions/embeddedField.go new file mode 100644 index 0000000..fa507b7 --- /dev/null +++ b/cli/cmd/gen/conditions/embeddedField.go @@ -0,0 +1,34 @@ +package conditions + +import ( + "errors" + "go/types" + + "github.com/elliotchance/pie/v2" +) + +// Generate conditions for a embedded field using the "generator" +// it will generate a condition for each of the field of the embedded field's type +func generateForEmbeddedField[T any](file *File, field Field, generator CodeGenerator[T]) []T { + embeddedStructType, ok := field.Type.Underlying().(*types.Struct) + if !ok { + panic(errors.New("unreachable! embedded objects are always structs")) + } + + fields, err := getStructFields(embeddedStructType) + if err != nil { + // embedded field's type has not fields + return []T{} + } + + if !isBaseModel(field.TypeString()) { + fields = pie.Map(fields, func(embeddedField Field) Field { + embeddedField.ColumnPrefix = field.Tags.getEmbeddedPrefix() + embeddedField.NamePrefix = field.Name + + return embeddedField + }) + } + + return generator.ForEachField(file, fields) +} diff --git a/cli/cmd/gen/conditions/field.go b/cli/cmd/gen/conditions/field.go index b43069f..2ddef3a 100644 --- a/cli/cmd/gen/conditions/field.go +++ b/cli/cmd/gen/conditions/field.go @@ -3,16 +3,29 @@ package conditions import ( "errors" "go/types" + + "github.com/elliotchance/pie/v2" ) +// badaas/orm/baseModels.go +var modelIDs = []string{ + badaasORMPath + "." + uIntID, + badaasORMPath + "." + uuid, +} + type Field struct { Name string + NamePrefix string Type Type Embedded bool Tags GormTags ColumnPrefix string } +func (field Field) IsModelID() bool { + return pie.Contains(modelIDs, field.TypeString()) +} + // Get the name of the column where the data for a field will be saved func (field Field) getColumnName() string { columnTag, isPresent := field.Tags[columnTagName] @@ -85,7 +98,7 @@ func (field Field) ChangeType(newType types.Type) Field { // Get fields of a Badaas model // Returns error is objectType is not a Badaas model -func getFields(objectType Type, prefix string) ([]Field, error) { +func getFields(objectType Type) ([]Field, error) { // The underlying type has to be a struct and a Badaas Model // (ignore const, var, func, etc.) structType, err := objectType.BadaasModelStruct() @@ -93,12 +106,12 @@ func getFields(objectType Type, prefix string) ([]Field, error) { return nil, err } - return getStructFields(structType, prefix) + return getStructFields(structType) } // Get fields of a struct // Returns errors if the struct has not fields -func getStructFields(structType *types.Struct, prefix string) ([]Field, error) { +func getStructFields(structType *types.Struct) ([]Field, error) { numFields := structType.NumFields() if numFields == 0 { return nil, errors.New("struct has 0 fields") @@ -111,11 +124,10 @@ func getStructFields(structType *types.Struct, prefix string) ([]Field, error) { fieldObject := structType.Field(i) gormTags := getGormTags(structType.Tag(i)) fields = append(fields, Field{ - Name: fieldObject.Name(), - Type: Type{fieldObject.Type()}, - Embedded: fieldObject.Embedded() || gormTags.hasEmbedded(), - Tags: gormTags, - ColumnPrefix: prefix, + Name: fieldObject.Name(), + Type: Type{fieldObject.Type()}, + Embedded: fieldObject.Embedded() || gormTags.hasEmbedded(), + Tags: gormTags, }) } diff --git a/cli/cmd/gen/conditions/file.go b/cli/cmd/gen/conditions/file.go index 7e03ab5..9fa5131 100644 --- a/cli/cmd/gen/conditions/file.go +++ b/cli/cmd/gen/conditions/file.go @@ -1,23 +1,19 @@ package conditions import ( - "errors" - "go/types" - "github.com/dave/jennifer/jen" - "github.com/ditrit/badaas-orm/cli/cmd/log" + "github.com/ditrit/badaas-orm/cli/cmd/version" ) -const badaasORMPath = "github.com/ditrit/badaas/orm" - type File struct { - destPkg string - jenFile *jen.File - name string + destPkg string + jenFile *jen.File + name string + codesAdded bool } -func NewConditionsFile(destPkg string, name string) *File { +func NewFile(destPkg, name string) *File { // Start a new file in destination package f := jen.NewFile(destPkg) @@ -31,68 +27,21 @@ func NewConditionsFile(destPkg string, name string) *File { } } -// Add conditions for an object in the file -func (file File) AddConditionsFor(object types.Object) error { - fields, err := getFields(Type{object.Type()}, "") - if err != nil { - return err +func (file *File) Add(codes ...jen.Code) { + if len(codes) > 0 { + file.codesAdded = true } - log.Logger.Infof("Generating conditions for type %q in %s", object.Name(), file.name) - - file.addConditionsForEachField(object, fields) - return nil -} - -// Add one condition for each field of the object -func (file File) addConditionsForEachField(object types.Object, fields []Field) { - conditions := file.generateConditionsForEachField(object, fields) - - for _, condition := range conditions { - for _, code := range condition.codes { - file.jenFile.Add(code) - } + for _, code := range codes { + file.jenFile.Add(code) } } // Write generated file func (file File) Save() error { - return file.jenFile.Save(file.name) -} - -// Generate the conditions for each of the object's fields -func (file File) generateConditionsForEachField(object types.Object, fields []Field) []*Condition { - conditions := []*Condition{} - for _, field := range fields { - log.Logger.Debugf("Generating condition for field %q", field.Name) - if field.Embedded { - conditions = append(conditions, file.generateEmbeddedConditions( - object, - field, - )...) - } else { - conditions = append(conditions, NewCondition( - file.destPkg, Type{object.Type()}, field, - )) - } - } - - return conditions -} - -// Generate conditions for a embedded field -// it will generate a condition for each of the field of the embedded field's type -func (file File) generateEmbeddedConditions(object types.Object, field Field) []*Condition { - embeddedStructType, ok := field.Type.Underlying().(*types.Struct) - if !ok { - panic(errors.New("unreachable! embedded objects are always structs")) - } - - fields, err := getStructFields(embeddedStructType, field.Tags.getEmbeddedPrefix()) - if err != nil { - // embedded field's type has not fields - return []*Condition{} + if file.codesAdded { + return file.jenFile.Save(file.name) } - return file.generateConditionsForEachField(object, fields) + return nil } diff --git a/cli/cmd/gen/conditions/main.go b/cli/cmd/gen/conditions/main.go index e2b0725..c8a1b86 100644 --- a/cli/cmd/gen/conditions/main.go +++ b/cli/cmd/gen/conditions/main.go @@ -5,15 +5,15 @@ import ( "fmt" "go/types" "os" + "path/filepath" "github.com/ettle/strcase" "github.com/spf13/cobra" "github.com/spf13/viper" + "golang.org/x/tools/go/packages" "github.com/ditrit/badaas-orm/cli/cmd/log" "github.com/ditrit/verdeter" - - "golang.org/x/tools/go/packages" ) var GenConditionsCmd = verdeter.BuildVerdeterCommand(verdeter.VerdeterConfig{ @@ -24,7 +24,10 @@ var GenConditionsCmd = verdeter.BuildVerdeterCommand(verdeter.VerdeterConfig{ Args: cobra.MinimumNArgs(1), }) -const DestPackageKey = "dest_package" +const ( + DestPackageKey = "dest_package" + badaasORMPath = "github.com/ditrit/badaas/orm" +) func init() { err := GenConditionsCmd.LKey( @@ -52,35 +55,47 @@ func generateConditions(_ *cobra.Command, args []string) { } // Generate conditions for each package - for _, pkg := range pkgs { - generateConditionsForPkg(destPkg, pkg) + for i, pkg := range pkgs { + generateConditionsForPkg(destPkg, args[i], pkg) } } // Generates a file with conditions for each Badaas model in the package -func generateConditionsForPkg(destPkg string, pkg *packages.Package) { +func generateConditionsForPkg(destPkg string, pkgPath string, pkg *packages.Package) { log.Logger.Infof("Generating conditions for types in package %q", pkg.Types.Name()) + relationGettersFile := NewFile(pkg.Types.Name(), filepath.Join(pkgPath, "badaas-orm.go")) + for _, name := range pkg.Types.Scope().Names() { object := getObject(pkg, name) if object != nil { - file := NewConditionsFile( - destPkg, - strcase.ToSnake(object.Name())+"_conditions.go", - ) - - err := file.AddConditionsFor(object) - if err != nil { - // object is not a Badaas model, do not generate conditions - continue - } - - err = file.Save() - if err != nil { - panic(err) - } + generateConditionsForObject(destPkg, object) + _ = NewRelationGettersGenerator(object).Into(relationGettersFile) } } + + err := relationGettersFile.Save() + if err != nil { + panic(err) + } +} + +func generateConditionsForObject(destPkg string, object types.Object) { + file := NewFile( + destPkg, + strcase.ToSnake(object.Name())+"_conditions.go", + ) + + err := NewConditionsGenerator(object).Into(file) + if err != nil { + // object is not a Badaas model, do not generate conditions + return + } + + err = file.Save() + if err != nil { + panic(err) + } } // Load package information from paths diff --git a/cli/cmd/gen/conditions/main_test.go b/cli/cmd/gen/conditions/main_test.go index 5b7b0cc..6b4e992 100644 --- a/cli/cmd/gen/conditions/main_test.go +++ b/cli/cmd/gen/conditions/main_test.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/viper" "gotest.tools/assert" - "github.com/ditrit/badaas-orm/cli/cmd/utils" + "github.com/ditrit/badaas-orm/cli/cmd/testutils" ) const chunkSize = 100000 @@ -18,66 +18,84 @@ func TestUIntModel(t *testing.T) { doTest(t, "./tests/uintmodel", []Comparison{ {Have: "uint_model_conditions.go", Expected: "./tests/results/uintmodel.go"}, }) + testutils.CheckFileNotExists(t, "./tests/uintmodel/badaas-orm.go") } func TestUUIDModel(t *testing.T) { doTest(t, "./tests/uuidmodel", []Comparison{ {Have: "uuid_model_conditions.go", Expected: "./tests/results/uuidmodel.go"}, }) + testutils.CheckFileNotExists(t, "./tests/uuidmodel/badaas-orm.go") } func TestBasicTypes(t *testing.T) { doTest(t, "./tests/basictypes", []Comparison{ {Have: "basic_types_conditions.go", Expected: "./tests/results/basictypes.go"}, }) + testutils.CheckFileNotExists(t, "./tests/basictypes/badaas-orm.go") } func TestBasicPointers(t *testing.T) { doTest(t, "./tests/basicpointers", []Comparison{ {Have: "basic_pointers_conditions.go", Expected: "./tests/results/basicpointers.go"}, }) + testutils.CheckFileNotExists(t, "./tests/basicpointers/badaas-orm.go") } func TestBasicSlices(t *testing.T) { doTest(t, "./tests/basicslices", []Comparison{ {Have: "basic_slices_conditions.go", Expected: "./tests/results/basicslices.go"}, }) + testutils.CheckFileNotExists(t, "./tests/basicslices/badaas-orm.go") } func TestBasicSlicesPointer(t *testing.T) { doTest(t, "./tests/basicslicespointer", []Comparison{ {Have: "basic_slices_pointer_conditions.go", Expected: "./tests/results/basicslicespointer.go"}, }) + testutils.CheckFileNotExists(t, "./tests/basicslicespointer/badaas-orm.go") } func TestGoEmbedded(t *testing.T) { doTest(t, "./tests/goembedded", []Comparison{ {Have: "go_embedded_conditions.go", Expected: "./tests/results/goembedded.go"}, }) + testutils.CheckFileNotExists(t, "./tests/goembedded/badaas-orm.go") } func TestGormEmbedded(t *testing.T) { doTest(t, "./tests/gormembedded", []Comparison{ {Have: "gorm_embedded_conditions.go", Expected: "./tests/results/gormembedded.go"}, }) + testutils.CheckFileNotExists(t, "./tests/gormembedded/badaas-orm.go") } func TestCustomType(t *testing.T) { doTest(t, "./tests/customtype", []Comparison{ {Have: "custom_type_conditions.go", Expected: "./tests/results/customtype.go"}, }) + testutils.CheckFileNotExists(t, "./tests/customtype/badaas-orm.go") +} + +func TestColumnDefinition(t *testing.T) { + doTest(t, "./tests/columndefinition", []Comparison{ + {Have: "column_definition_conditions.go", Expected: "./tests/results/columndefinition.go"}, + }) + testutils.CheckFileNotExists(t, "./tests/columndefinition/badaas-orm.go") } func TestNullableTypes(t *testing.T) { doTest(t, "./tests/nullabletypes", []Comparison{ {Have: "nullable_types_conditions.go", Expected: "./tests/results/nullabletypes.go"}, }) + testutils.CheckFileNotExists(t, "./tests/nullabletypes/badaas-orm.go") } func TestBelongsTo(t *testing.T) { doTest(t, "./tests/belongsto", []Comparison{ {Have: "owner_conditions.go", Expected: "./tests/results/belongsto_owner.go"}, {Have: "owned_conditions.go", Expected: "./tests/results/belongsto_owned.go"}, + {Have: "./tests/belongsto/badaas-orm.go", Expected: "./tests/belongsto/badaas-orm_result.go"}, }) } @@ -85,6 +103,7 @@ func TestHasOne(t *testing.T) { doTest(t, "./tests/hasone", []Comparison{ {Have: "country_conditions.go", Expected: "./tests/results/hasone_country.go"}, {Have: "city_conditions.go", Expected: "./tests/results/hasone_city.go"}, + {Have: "./tests/hasone/badaas-orm.go", Expected: "./tests/hasone/badaas-orm_result.go"}, }) } @@ -92,53 +111,65 @@ func TestHasMany(t *testing.T) { doTest(t, "./tests/hasmany", []Comparison{ {Have: "company_conditions.go", Expected: "./tests/results/hasmany_company.go"}, {Have: "seller_conditions.go", Expected: "./tests/results/hasmany_seller.go"}, + {Have: "./tests/hasmany/badaas-orm.go", Expected: "./tests/hasmany/badaas-orm_result.go"}, + }) +} + +func TestHasManyWithPointers(t *testing.T) { + doTest(t, "./tests/hasmanywithpointers", []Comparison{ + {Have: "company_with_pointers_conditions.go", Expected: "./tests/results/hasmanywithpointers_company.go"}, + {Have: "seller_in_pointers_conditions.go", Expected: "./tests/results/hasmanywithpointers_seller.go"}, + {Have: "./tests/hasmanywithpointers/badaas-orm.go", Expected: "./tests/hasmanywithpointers/badaas-orm_result.go"}, }) } func TestSelfReferential(t *testing.T) { doTest(t, "./tests/selfreferential", []Comparison{ {Have: "employee_conditions.go", Expected: "./tests/results/selfreferential.go"}, + {Have: "./tests/selfreferential/badaas-orm.go", Expected: "./tests/selfreferential/badaas-orm_result.go"}, }) } func TestMultiplePackage(t *testing.T) { doTest(t, "./tests/multiplepackage/package1", []Comparison{ {Have: "package1_conditions.go", Expected: "./tests/results/multiplepackage_package1.go"}, + {Have: "./tests/multiplepackage/package1/badaas-orm.go", Expected: "./tests/multiplepackage/package1/badaas-orm_result.go"}, }) -} - -func TestColumnDefinition(t *testing.T) { - doTest(t, "./tests/columndefinition", []Comparison{ - {Have: "column_definition_conditions.go", Expected: "./tests/results/columndefinition.go"}, + doTest(t, "./tests/multiplepackage/package2", []Comparison{ + {Have: "package2_conditions.go", Expected: "./tests/results/multiplepackage_package2.go"}, }) } func TestOverrideForeignKey(t *testing.T) { doTest(t, "./tests/overrideforeignkey", []Comparison{ - {Have: "bicycle_conditions.go", Expected: "./tests/results/overrideforeignkey.go"}, + {Have: "bicycle_conditions.go", Expected: "./tests/results/overrideforeignkey_bicycle.go"}, + {Have: "person_conditions.go", Expected: "./tests/results/overrideforeignkey_person.go"}, + {Have: "./tests/overrideforeignkey/badaas-orm.go", Expected: "./tests/overrideforeignkey/badaas-orm_result.go"}, }) - utils.RemoveFile("person_conditions.go") } func TestOverrideReferences(t *testing.T) { doTest(t, "./tests/overridereferences", []Comparison{ - {Have: "phone_conditions.go", Expected: "./tests/results/overridereferences.go"}, + {Have: "phone_conditions.go", Expected: "./tests/results/overridereferences_phone.go"}, + {Have: "brand_conditions.go", Expected: "./tests/results/overridereferences_brand.go"}, + {Have: "./tests/overridereferences/badaas-orm.go", Expected: "./tests/overridereferences/badaas-orm_result.go"}, }) - utils.RemoveFile("brand_conditions.go") } func TestOverrideForeignKeyInverse(t *testing.T) { doTest(t, "./tests/overrideforeignkeyinverse", []Comparison{ - {Have: "user_conditions.go", Expected: "./tests/results/overrideforeignkeyinverse.go"}, + {Have: "user_conditions.go", Expected: "./tests/results/overrideforeignkeyinverse_user.go"}, + {Have: "credit_card_conditions.go", Expected: "./tests/results/overrideforeignkeyinverse_credit_card.go"}, + {Have: "./tests/overrideforeignkeyinverse/badaas-orm.go", Expected: "./tests/overrideforeignkeyinverse/badaas-orm_result.go"}, }) - utils.RemoveFile("credit_card_conditions.go") } func TestOverrideReferencesInverse(t *testing.T) { doTest(t, "./tests/overridereferencesinverse", []Comparison{ - {Have: "computer_conditions.go", Expected: "./tests/results/overridereferencesinverse.go"}, + {Have: "computer_conditions.go", Expected: "./tests/results/overridereferencesinverse_computer.go"}, + {Have: "processor_conditions.go", Expected: "./tests/results/overridereferencesinverse_processor.go"}, + {Have: "./tests/overridereferencesinverse/badaas-orm.go", Expected: "./tests/overridereferencesinverse/badaas-orm_result.go"}, }) - utils.RemoveFile("processor_conditions.go") } type Comparison struct { @@ -155,8 +186,8 @@ func doTest(t *testing.T, sourcePkg string, comparisons []Comparison) { } func checkFilesEqual(t *testing.T, file1, file2 string) { - stat1 := utils.CheckFileExists(t, file1) - stat2 := utils.CheckFileExists(t, file2) + stat1 := testutils.CheckFileExists(t, file1) + stat2 := testutils.CheckFileExists(t, file2) // do inputs at least have the same size? assert.Equal(t, stat1.Size(), stat2.Size(), "File lens are not equal") @@ -176,6 +207,7 @@ func checkFilesEqual(t *testing.T, file1, file2 string) { b1 := make([]byte, chunkSize) b2 := make([]byte, chunkSize) + for { n1, err1 := io.ReadFull(f1, b1) n2, err2 := io.ReadFull(f2, b2) @@ -190,10 +222,11 @@ func checkFilesEqual(t *testing.T, file1, file2 string) { if err1 != nil { t.Error(err1) } + if err2 != nil { t.Error(err2) } } - utils.RemoveFile(file1) + testutils.RemoveFile(file1) } diff --git a/cli/cmd/gen/conditions/relationGettersGenerator.go b/cli/cmd/gen/conditions/relationGettersGenerator.go new file mode 100644 index 0000000..3804cf5 --- /dev/null +++ b/cli/cmd/gen/conditions/relationGettersGenerator.go @@ -0,0 +1,224 @@ +package conditions + +import ( + "go/types" + + "github.com/dave/jennifer/jen" + "github.com/ettle/strcase" + + "github.com/ditrit/badaas-orm/cli/cmd/log" +) + +const ( + badaasORMVerifyStructLoaded = "VerifyStructLoaded" + badaasORMVerifyPointerLoaded = "VerifyPointerLoaded" + badaasORMVerifyPointerWithIDLoaded = "VerifyPointerWithIDLoaded" + badaasORMVerifyCollectionLoaded = "VerifyCollectionLoaded" +) + +type RelationGettersGenerator struct { + object types.Object + objectType Type +} + +func NewRelationGettersGenerator(object types.Object) *RelationGettersGenerator { + return &RelationGettersGenerator{ + object: object, + objectType: Type{object.Type()}, + } +} + +// Add conditions for an object in the file +func (generator RelationGettersGenerator) Into(file *File) error { + fields, err := getFields(generator.objectType) + if err != nil { + return err + } + + log.Logger.Infof("Generating relation getters for type %q in %s", generator.object.Name(), file.name) + + file.Add(generator.ForEachField(file, fields)...) + + return nil +} + +func (generator RelationGettersGenerator) ForEachField(file *File, fields []Field) []jen.Code { + relationGetters := []jen.Code{} + + for _, field := range fields { + if field.Embedded { + relationGetters = append( + relationGetters, + generateForEmbeddedField[jen.Code]( + file, + field, + generator, + )..., + ) + } else { + getterForField := generator.generateForField(field) + if getterForField != nil { + relationGetters = append(relationGetters, getterForField) + } + } + } + + return relationGetters +} + +func (generator RelationGettersGenerator) generateForField(field Field) jen.Code { + switch fieldType := field.GetType().(type) { + case *types.Named: + // the field is a named type (user defined structs) + _, err := field.Type.BadaasModelStruct() + if err == nil { + log.Logger.Debugf("Generating relation getter for type %q and field %s", generator.object.Name(), field.Name) + // field is a badaas Model + return generator.verifyStruct(field) + } + case *types.Pointer: + // the field is a pointer + return generator.generateForPointer(field.ChangeType(fieldType.Elem())) + default: + log.Logger.Debugf("struct field type not handled: %T", fieldType) + } + + return nil +} + +func (generator RelationGettersGenerator) generateForPointer(field Field) jen.Code { + switch fieldType := field.GetType().(type) { + case *types.Named: + _, err := field.Type.BadaasModelStruct() + if err == nil { + // field is a pointer to Badaas Model + fk, err := generator.objectType.GetFK(field) + if err != nil { + log.Logger.Debugf("unhandled: field is a pointer and object not has the fk: %s", field.Type) + return nil + } + + log.Logger.Debugf("Generating relation getter for type %q and field %s", generator.object.Name(), field.Name) + + switch fk.GetType().(type) { + case *types.Named: + if fk.IsModelID() { + return generator.verifyPointerWithID(field) + } + case *types.Pointer: + // the fk is a pointer + return generator.verifyPointer(field) + } + } + case *types.Slice: + return generator.generateForSlicePointer( + field.ChangeType(fieldType.Elem()), + nil, + ) + } + + return nil +} + +func (generator RelationGettersGenerator) generateForSlicePointer(field Field, fieldTypePrefix *jen.Statement) jen.Code { + switch fieldType := field.GetType().(type) { + case *types.Named: + _, err := field.Type.BadaasModelStruct() + if err == nil { + // field is a pointer to a slice of badaas Model + return generator.verifyCollection(field, fieldTypePrefix) + } + case *types.Pointer: + return generator.generateForSlicePointer( + field.ChangeType(fieldType.Elem()), + jen.Op("*"), + ) + } + + return nil +} + +func getGetterName(field Field) string { + return "Get" + strcase.ToPascal(field.Name) +} + +func (generator RelationGettersGenerator) verifyStruct(field Field) *jen.Statement { + return generator.verifyCommon( + field, + badaasORMVerifyStructLoaded, + jen.Op("*"), + nil, + jen.Op("&").Id("m").Op(".").Id(field.Name), + ) +} + +func (generator RelationGettersGenerator) verifyPointer(field Field) *jen.Statement { + return generator.verifyPointerCommon(field, badaasORMVerifyPointerLoaded) +} + +func (generator RelationGettersGenerator) verifyPointerWithID(field Field) *jen.Statement { + return generator.verifyPointerCommon(field, badaasORMVerifyPointerWithIDLoaded) +} + +func (generator RelationGettersGenerator) verifyCollection(field Field, fieldTypePrefix *jen.Statement) jen.Code { + return generator.verifyCommon( + field, + badaasORMVerifyCollectionLoaded, + jen.Index(), + fieldTypePrefix, + jen.Id("m").Op(".").Id(field.Name), + ) +} + +func (generator RelationGettersGenerator) verifyPointerCommon(field Field, verifyFunc string) *jen.Statement { + return generator.verifyCommon( + field, + verifyFunc, + jen.Op("*"), + nil, + jen.Id("m").Op(".").Id(field.Name+"ID"), + jen.Id("m").Op(".").Id(field.Name), + ) +} + +func (generator RelationGettersGenerator) verifyCommon( + field Field, + verifyFunc string, + returnType *jen.Statement, + fieldTypePrefix *jen.Statement, + callParams ...jen.Code, +) *jen.Statement { + fieldType := jen.Qual( + getRelativePackagePath( + generator.object.Pkg().Name(), + field.Type, + ), + field.TypeName(), + ) + + if fieldTypePrefix != nil { + fieldType = fieldTypePrefix.Add(fieldType) + } + + return jen.Func().Parens( + jen.Id("m").Id(generator.object.Name()), + ).Id(getGetterName(field)).Params().Add( + jen.Parens( + jen.List( + returnType.Add(fieldType), + jen.Id("error"), + ), + ), + ).Block( + jen.Return( + jen.Qual( + badaasORMPath, + verifyFunc, + ).Types( + fieldType, + ).Call( + callParams..., + ), + ), + ) +} diff --git a/cli/cmd/gen/conditions/tests/belongsto/badaas-orm_result.go b/cli/cmd/gen/conditions/tests/belongsto/badaas-orm_result.go new file mode 100644 index 0000000..e371a04 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/belongsto/badaas-orm_result.go @@ -0,0 +1,8 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package belongsto + +import orm "github.com/ditrit/badaas/orm" + +func (m Owned) GetOwner() (*Owner, error) { + return orm.VerifyStructLoaded[Owner](&m.Owner) +} diff --git a/cli/cmd/gen/conditions/tests/goembedded/goembedded.go b/cli/cmd/gen/conditions/tests/goembedded/goembedded.go index ff7c0e1..220add0 100644 --- a/cli/cmd/gen/conditions/tests/goembedded/goembedded.go +++ b/cli/cmd/gen/conditions/tests/goembedded/goembedded.go @@ -3,11 +3,12 @@ package goembedded import "github.com/ditrit/badaas/orm" type ToBeEmbedded struct { - EmbeddedInt int + Int int } type GoEmbedded struct { orm.UIntModel + Int int ToBeEmbedded } diff --git a/cli/cmd/gen/conditions/tests/gormembedded/gormembedded.go b/cli/cmd/gen/conditions/tests/gormembedded/gormembedded.go index 6b7c219..d991826 100644 --- a/cli/cmd/gen/conditions/tests/gormembedded/gormembedded.go +++ b/cli/cmd/gen/conditions/tests/gormembedded/gormembedded.go @@ -9,5 +9,7 @@ type ToBeGormEmbedded struct { type GormEmbedded struct { orm.UIntModel - GormEmbedded ToBeGormEmbedded `gorm:"embedded;embeddedPrefix:gorm_embedded_"` + Int int + GormEmbedded ToBeGormEmbedded `gorm:"embedded;embeddedPrefix:gorm_embedded_"` + GormEmbeddedNoPrefix ToBeGormEmbedded `gorm:"embedded"` } diff --git a/cli/cmd/gen/conditions/tests/hasmany/badaas-orm_result.go b/cli/cmd/gen/conditions/tests/hasmany/badaas-orm_result.go new file mode 100644 index 0000000..4ea630d --- /dev/null +++ b/cli/cmd/gen/conditions/tests/hasmany/badaas-orm_result.go @@ -0,0 +1,11 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package hasmany + +import orm "github.com/ditrit/badaas/orm" + +func (m Company) GetSellers() ([]Seller, error) { + return orm.VerifyCollectionLoaded[Seller](m.Sellers) +} +func (m Seller) GetCompany() (*Company, error) { + return orm.VerifyPointerLoaded[Company](m.CompanyID, m.Company) +} diff --git a/cli/cmd/gen/conditions/tests/hasmany/hasmany.go b/cli/cmd/gen/conditions/tests/hasmany/hasmany.go index 0eafe59..2cc579e 100644 --- a/cli/cmd/gen/conditions/tests/hasmany/hasmany.go +++ b/cli/cmd/gen/conditions/tests/hasmany/hasmany.go @@ -1,15 +1,16 @@ -package hasone +package hasmany import "github.com/ditrit/badaas/orm" type Company struct { orm.UUIDModel - Sellers []Seller // Company HasMany Sellers (Company 0..1 -> 0..* Seller) + Sellers *[]Seller // Company HasMany Sellers (Company 0..1 -> 0..* Seller) } type Seller struct { orm.UUIDModel + Company *Company CompanyID *orm.UUID // Company HasMany Sellers (Company 0..1 -> 0..* Seller) } diff --git a/cli/cmd/gen/conditions/tests/hasmanywithpointers/badaas-orm_result.go b/cli/cmd/gen/conditions/tests/hasmanywithpointers/badaas-orm_result.go new file mode 100644 index 0000000..51ddaf8 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/hasmanywithpointers/badaas-orm_result.go @@ -0,0 +1,11 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package hasmanywithpointers + +import orm "github.com/ditrit/badaas/orm" + +func (m CompanyWithPointers) GetSellers() ([]*SellerInPointers, error) { + return orm.VerifyCollectionLoaded[*SellerInPointers](m.Sellers) +} +func (m SellerInPointers) GetCompany() (*CompanyWithPointers, error) { + return orm.VerifyPointerLoaded[CompanyWithPointers](m.CompanyID, m.Company) +} diff --git a/cli/cmd/gen/conditions/tests/hasmanywithpointers/hasmanywithpointers.go b/cli/cmd/gen/conditions/tests/hasmanywithpointers/hasmanywithpointers.go new file mode 100644 index 0000000..97d7e28 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/hasmanywithpointers/hasmanywithpointers.go @@ -0,0 +1,18 @@ +package hasmanywithpointers + +import ( + "github.com/ditrit/badaas/orm" +) + +type CompanyWithPointers struct { + orm.UUIDModel + + Sellers *[]*SellerInPointers // CompanyWithPointers HasMany SellerInPointers +} + +type SellerInPointers struct { + orm.UUIDModel + + Company *CompanyWithPointers + CompanyID *orm.UUID // Company HasMany Seller +} diff --git a/cli/cmd/gen/conditions/tests/hasone/badaas-orm_result.go b/cli/cmd/gen/conditions/tests/hasone/badaas-orm_result.go new file mode 100644 index 0000000..8b54a6d --- /dev/null +++ b/cli/cmd/gen/conditions/tests/hasone/badaas-orm_result.go @@ -0,0 +1,11 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package hasone + +import orm "github.com/ditrit/badaas/orm" + +func (m City) GetCountry() (*Country, error) { + return orm.VerifyPointerWithIDLoaded[Country](m.CountryID, m.Country) +} +func (m Country) GetCapital() (*City, error) { + return orm.VerifyStructLoaded[City](&m.Capital) +} diff --git a/cli/cmd/gen/conditions/tests/hasone/hasone.go b/cli/cmd/gen/conditions/tests/hasone/hasone.go index cc29a90..c38b067 100644 --- a/cli/cmd/gen/conditions/tests/hasone/hasone.go +++ b/cli/cmd/gen/conditions/tests/hasone/hasone.go @@ -11,5 +11,6 @@ type Country struct { type City struct { orm.UUIDModel + Country *Country CountryID orm.UUID // Country HasOne City (Country 1 -> 1 City) } diff --git a/cli/cmd/gen/conditions/tests/multiplepackage/package1/badaas-orm_result.go b/cli/cmd/gen/conditions/tests/multiplepackage/package1/badaas-orm_result.go new file mode 100644 index 0000000..0d20365 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/multiplepackage/package1/badaas-orm_result.go @@ -0,0 +1,11 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package package1 + +import ( + package2 "github.com/ditrit/badaas-orm/cli/cmd/gen/conditions/tests/multiplepackage/package2" + orm "github.com/ditrit/badaas/orm" +) + +func (m Package1) GetPackage2() (*package2.Package2, error) { + return orm.VerifyStructLoaded[package2.Package2](&m.Package2) +} diff --git a/cli/cmd/gen/conditions/tests/overrideforeignkey/badaas-orm_result.go b/cli/cmd/gen/conditions/tests/overrideforeignkey/badaas-orm_result.go new file mode 100644 index 0000000..24a0918 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/overrideforeignkey/badaas-orm_result.go @@ -0,0 +1,8 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package overrideforeignkey + +import orm "github.com/ditrit/badaas/orm" + +func (m Bicycle) GetOwner() (*Person, error) { + return orm.VerifyStructLoaded[Person](&m.Owner) +} diff --git a/cli/cmd/gen/conditions/tests/overrideforeignkeyinverse/badaas-orm_result.go b/cli/cmd/gen/conditions/tests/overrideforeignkeyinverse/badaas-orm_result.go new file mode 100644 index 0000000..732988c --- /dev/null +++ b/cli/cmd/gen/conditions/tests/overrideforeignkeyinverse/badaas-orm_result.go @@ -0,0 +1,8 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package overrideforeignkeyinverse + +import orm "github.com/ditrit/badaas/orm" + +func (m User) GetCreditCard() (*CreditCard, error) { + return orm.VerifyStructLoaded[CreditCard](&m.CreditCard) +} diff --git a/cli/cmd/gen/conditions/tests/overridereferences/badaas-orm_result.go b/cli/cmd/gen/conditions/tests/overridereferences/badaas-orm_result.go new file mode 100644 index 0000000..03fad6e --- /dev/null +++ b/cli/cmd/gen/conditions/tests/overridereferences/badaas-orm_result.go @@ -0,0 +1,8 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package overridereferences + +import orm "github.com/ditrit/badaas/orm" + +func (m Phone) GetBrand() (*Brand, error) { + return orm.VerifyStructLoaded[Brand](&m.Brand) +} diff --git a/cli/cmd/gen/conditions/tests/overridereferencesinverse/badaas-orm_result.go b/cli/cmd/gen/conditions/tests/overridereferencesinverse/badaas-orm_result.go new file mode 100644 index 0000000..79b8211 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/overridereferencesinverse/badaas-orm_result.go @@ -0,0 +1,8 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package overridereferencesinverse + +import orm "github.com/ditrit/badaas/orm" + +func (m Computer) GetProcessor() (*Processor, error) { + return orm.VerifyStructLoaded[Processor](&m.Processor) +} diff --git a/cli/cmd/gen/conditions/tests/results/basicpointers.go b/cli/cmd/gen/conditions/tests/results/basicpointers.go index ac1c6b4..46e0b6e 100644 --- a/cli/cmd/gen/conditions/tests/results/basicpointers.go +++ b/cli/cmd/gen/conditions/tests/results/basicpointers.go @@ -9,133 +9,189 @@ import ( func BasicPointersId(operator orm.Operator[orm.UUID]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func BasicPointersCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func BasicPointersUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func BasicPointersDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var basicPointersBoolFieldID = orm.FieldIdentifier{Field: "Bool"} + func BasicPointersBool(operator orm.Operator[bool]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, bool]{ - Field: "Bool", - Operator: operator, + FieldIdentifier: basicPointersBoolFieldID, + Operator: operator, } } + +var basicPointersIntFieldID = orm.FieldIdentifier{Field: "Int"} + func BasicPointersInt(operator orm.Operator[int]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, int]{ - Field: "Int", - Operator: operator, + FieldIdentifier: basicPointersIntFieldID, + Operator: operator, } } + +var basicPointersInt8FieldID = orm.FieldIdentifier{Field: "Int8"} + func BasicPointersInt8(operator orm.Operator[int8]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, int8]{ - Field: "Int8", - Operator: operator, + FieldIdentifier: basicPointersInt8FieldID, + Operator: operator, } } + +var basicPointersInt16FieldID = orm.FieldIdentifier{Field: "Int16"} + func BasicPointersInt16(operator orm.Operator[int16]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, int16]{ - Field: "Int16", - Operator: operator, + FieldIdentifier: basicPointersInt16FieldID, + Operator: operator, } } + +var basicPointersInt32FieldID = orm.FieldIdentifier{Field: "Int32"} + func BasicPointersInt32(operator orm.Operator[int32]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, int32]{ - Field: "Int32", - Operator: operator, + FieldIdentifier: basicPointersInt32FieldID, + Operator: operator, } } + +var basicPointersInt64FieldID = orm.FieldIdentifier{Field: "Int64"} + func BasicPointersInt64(operator orm.Operator[int64]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, int64]{ - Field: "Int64", - Operator: operator, + FieldIdentifier: basicPointersInt64FieldID, + Operator: operator, } } + +var basicPointersUIntFieldID = orm.FieldIdentifier{Field: "UInt"} + func BasicPointersUInt(operator orm.Operator[uint]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, uint]{ - Field: "UInt", - Operator: operator, + FieldIdentifier: basicPointersUIntFieldID, + Operator: operator, } } + +var basicPointersUInt8FieldID = orm.FieldIdentifier{Field: "UInt8"} + func BasicPointersUInt8(operator orm.Operator[uint8]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, uint8]{ - Field: "UInt8", - Operator: operator, + FieldIdentifier: basicPointersUInt8FieldID, + Operator: operator, } } + +var basicPointersUInt16FieldID = orm.FieldIdentifier{Field: "UInt16"} + func BasicPointersUInt16(operator orm.Operator[uint16]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, uint16]{ - Field: "UInt16", - Operator: operator, + FieldIdentifier: basicPointersUInt16FieldID, + Operator: operator, } } + +var basicPointersUInt32FieldID = orm.FieldIdentifier{Field: "UInt32"} + func BasicPointersUInt32(operator orm.Operator[uint32]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, uint32]{ - Field: "UInt32", - Operator: operator, + FieldIdentifier: basicPointersUInt32FieldID, + Operator: operator, } } + +var basicPointersUInt64FieldID = orm.FieldIdentifier{Field: "UInt64"} + func BasicPointersUInt64(operator orm.Operator[uint64]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, uint64]{ - Field: "UInt64", - Operator: operator, + FieldIdentifier: basicPointersUInt64FieldID, + Operator: operator, } } + +var basicPointersUIntptrFieldID = orm.FieldIdentifier{Field: "UIntptr"} + func BasicPointersUIntptr(operator orm.Operator[uintptr]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, uintptr]{ - Field: "UIntptr", - Operator: operator, + FieldIdentifier: basicPointersUIntptrFieldID, + Operator: operator, } } + +var basicPointersFloat32FieldID = orm.FieldIdentifier{Field: "Float32"} + func BasicPointersFloat32(operator orm.Operator[float32]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, float32]{ - Field: "Float32", - Operator: operator, + FieldIdentifier: basicPointersFloat32FieldID, + Operator: operator, } } + +var basicPointersFloat64FieldID = orm.FieldIdentifier{Field: "Float64"} + func BasicPointersFloat64(operator orm.Operator[float64]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, float64]{ - Field: "Float64", - Operator: operator, + FieldIdentifier: basicPointersFloat64FieldID, + Operator: operator, } } + +var basicPointersComplex64FieldID = orm.FieldIdentifier{Field: "Complex64"} + func BasicPointersComplex64(operator orm.Operator[complex64]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, complex64]{ - Field: "Complex64", - Operator: operator, + FieldIdentifier: basicPointersComplex64FieldID, + Operator: operator, } } + +var basicPointersComplex128FieldID = orm.FieldIdentifier{Field: "Complex128"} + func BasicPointersComplex128(operator orm.Operator[complex128]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, complex128]{ - Field: "Complex128", - Operator: operator, + FieldIdentifier: basicPointersComplex128FieldID, + Operator: operator, } } + +var basicPointersStringFieldID = orm.FieldIdentifier{Field: "String"} + func BasicPointersString(operator orm.Operator[string]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, string]{ - Field: "String", - Operator: operator, + FieldIdentifier: basicPointersStringFieldID, + Operator: operator, } } + +var basicPointersByteFieldID = orm.FieldIdentifier{Field: "Byte"} + func BasicPointersByte(operator orm.Operator[uint8]) orm.WhereCondition[basicpointers.BasicPointers] { return orm.FieldCondition[basicpointers.BasicPointers, uint8]{ - Field: "Byte", - Operator: operator, + FieldIdentifier: basicPointersByteFieldID, + Operator: operator, } } + +var BasicPointersPreloadAttributes = orm.NewPreloadCondition[basicpointers.BasicPointers](basicPointersBoolFieldID, basicPointersIntFieldID, basicPointersInt8FieldID, basicPointersInt16FieldID, basicPointersInt32FieldID, basicPointersInt64FieldID, basicPointersUIntFieldID, basicPointersUInt8FieldID, basicPointersUInt16FieldID, basicPointersUInt32FieldID, basicPointersUInt64FieldID, basicPointersUIntptrFieldID, basicPointersFloat32FieldID, basicPointersFloat64FieldID, basicPointersComplex64FieldID, basicPointersComplex128FieldID, basicPointersStringFieldID, basicPointersByteFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/basicslices.go b/cli/cmd/gen/conditions/tests/results/basicslices.go index a0d3431..223690d 100644 --- a/cli/cmd/gen/conditions/tests/results/basicslices.go +++ b/cli/cmd/gen/conditions/tests/results/basicslices.go @@ -9,133 +9,189 @@ import ( func BasicSlicesId(operator orm.Operator[orm.UUID]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func BasicSlicesCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func BasicSlicesUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func BasicSlicesDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var basicSlicesBoolFieldID = orm.FieldIdentifier{Field: "Bool"} + func BasicSlicesBool(operator orm.Operator[[]bool]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []bool]{ - Field: "Bool", - Operator: operator, + FieldIdentifier: basicSlicesBoolFieldID, + Operator: operator, } } + +var basicSlicesIntFieldID = orm.FieldIdentifier{Field: "Int"} + func BasicSlicesInt(operator orm.Operator[[]int]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []int]{ - Field: "Int", - Operator: operator, + FieldIdentifier: basicSlicesIntFieldID, + Operator: operator, } } + +var basicSlicesInt8FieldID = orm.FieldIdentifier{Field: "Int8"} + func BasicSlicesInt8(operator orm.Operator[[]int8]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []int8]{ - Field: "Int8", - Operator: operator, + FieldIdentifier: basicSlicesInt8FieldID, + Operator: operator, } } + +var basicSlicesInt16FieldID = orm.FieldIdentifier{Field: "Int16"} + func BasicSlicesInt16(operator orm.Operator[[]int16]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []int16]{ - Field: "Int16", - Operator: operator, + FieldIdentifier: basicSlicesInt16FieldID, + Operator: operator, } } + +var basicSlicesInt32FieldID = orm.FieldIdentifier{Field: "Int32"} + func BasicSlicesInt32(operator orm.Operator[[]int32]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []int32]{ - Field: "Int32", - Operator: operator, + FieldIdentifier: basicSlicesInt32FieldID, + Operator: operator, } } + +var basicSlicesInt64FieldID = orm.FieldIdentifier{Field: "Int64"} + func BasicSlicesInt64(operator orm.Operator[[]int64]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []int64]{ - Field: "Int64", - Operator: operator, + FieldIdentifier: basicSlicesInt64FieldID, + Operator: operator, } } + +var basicSlicesUIntFieldID = orm.FieldIdentifier{Field: "UInt"} + func BasicSlicesUInt(operator orm.Operator[[]uint]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []uint]{ - Field: "UInt", - Operator: operator, + FieldIdentifier: basicSlicesUIntFieldID, + Operator: operator, } } + +var basicSlicesUInt8FieldID = orm.FieldIdentifier{Field: "UInt8"} + func BasicSlicesUInt8(operator orm.Operator[[]uint8]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []uint8]{ - Field: "UInt8", - Operator: operator, + FieldIdentifier: basicSlicesUInt8FieldID, + Operator: operator, } } + +var basicSlicesUInt16FieldID = orm.FieldIdentifier{Field: "UInt16"} + func BasicSlicesUInt16(operator orm.Operator[[]uint16]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []uint16]{ - Field: "UInt16", - Operator: operator, + FieldIdentifier: basicSlicesUInt16FieldID, + Operator: operator, } } + +var basicSlicesUInt32FieldID = orm.FieldIdentifier{Field: "UInt32"} + func BasicSlicesUInt32(operator orm.Operator[[]uint32]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []uint32]{ - Field: "UInt32", - Operator: operator, + FieldIdentifier: basicSlicesUInt32FieldID, + Operator: operator, } } + +var basicSlicesUInt64FieldID = orm.FieldIdentifier{Field: "UInt64"} + func BasicSlicesUInt64(operator orm.Operator[[]uint64]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []uint64]{ - Field: "UInt64", - Operator: operator, + FieldIdentifier: basicSlicesUInt64FieldID, + Operator: operator, } } + +var basicSlicesUIntptrFieldID = orm.FieldIdentifier{Field: "UIntptr"} + func BasicSlicesUIntptr(operator orm.Operator[[]uintptr]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []uintptr]{ - Field: "UIntptr", - Operator: operator, + FieldIdentifier: basicSlicesUIntptrFieldID, + Operator: operator, } } + +var basicSlicesFloat32FieldID = orm.FieldIdentifier{Field: "Float32"} + func BasicSlicesFloat32(operator orm.Operator[[]float32]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []float32]{ - Field: "Float32", - Operator: operator, + FieldIdentifier: basicSlicesFloat32FieldID, + Operator: operator, } } + +var basicSlicesFloat64FieldID = orm.FieldIdentifier{Field: "Float64"} + func BasicSlicesFloat64(operator orm.Operator[[]float64]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []float64]{ - Field: "Float64", - Operator: operator, + FieldIdentifier: basicSlicesFloat64FieldID, + Operator: operator, } } + +var basicSlicesComplex64FieldID = orm.FieldIdentifier{Field: "Complex64"} + func BasicSlicesComplex64(operator orm.Operator[[]complex64]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []complex64]{ - Field: "Complex64", - Operator: operator, + FieldIdentifier: basicSlicesComplex64FieldID, + Operator: operator, } } + +var basicSlicesComplex128FieldID = orm.FieldIdentifier{Field: "Complex128"} + func BasicSlicesComplex128(operator orm.Operator[[]complex128]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []complex128]{ - Field: "Complex128", - Operator: operator, + FieldIdentifier: basicSlicesComplex128FieldID, + Operator: operator, } } + +var basicSlicesStringFieldID = orm.FieldIdentifier{Field: "String"} + func BasicSlicesString(operator orm.Operator[[]string]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []string]{ - Field: "String", - Operator: operator, + FieldIdentifier: basicSlicesStringFieldID, + Operator: operator, } } + +var basicSlicesByteFieldID = orm.FieldIdentifier{Field: "Byte"} + func BasicSlicesByte(operator orm.Operator[[]uint8]) orm.WhereCondition[basicslices.BasicSlices] { return orm.FieldCondition[basicslices.BasicSlices, []uint8]{ - Field: "Byte", - Operator: operator, + FieldIdentifier: basicSlicesByteFieldID, + Operator: operator, } } + +var BasicSlicesPreloadAttributes = orm.NewPreloadCondition[basicslices.BasicSlices](basicSlicesBoolFieldID, basicSlicesIntFieldID, basicSlicesInt8FieldID, basicSlicesInt16FieldID, basicSlicesInt32FieldID, basicSlicesInt64FieldID, basicSlicesUIntFieldID, basicSlicesUInt8FieldID, basicSlicesUInt16FieldID, basicSlicesUInt32FieldID, basicSlicesUInt64FieldID, basicSlicesUIntptrFieldID, basicSlicesFloat32FieldID, basicSlicesFloat64FieldID, basicSlicesComplex64FieldID, basicSlicesComplex128FieldID, basicSlicesStringFieldID, basicSlicesByteFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/basicslicespointer.go b/cli/cmd/gen/conditions/tests/results/basicslicespointer.go index a4d47af..47f404f 100644 --- a/cli/cmd/gen/conditions/tests/results/basicslicespointer.go +++ b/cli/cmd/gen/conditions/tests/results/basicslicespointer.go @@ -9,133 +9,189 @@ import ( func BasicSlicesPointerId(operator orm.Operator[orm.UUID]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func BasicSlicesPointerCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func BasicSlicesPointerUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func BasicSlicesPointerDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var basicSlicesPointerBoolFieldID = orm.FieldIdentifier{Field: "Bool"} + func BasicSlicesPointerBool(operator orm.Operator[[]bool]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []bool]{ - Field: "Bool", - Operator: operator, + FieldIdentifier: basicSlicesPointerBoolFieldID, + Operator: operator, } } + +var basicSlicesPointerIntFieldID = orm.FieldIdentifier{Field: "Int"} + func BasicSlicesPointerInt(operator orm.Operator[[]int]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []int]{ - Field: "Int", - Operator: operator, + FieldIdentifier: basicSlicesPointerIntFieldID, + Operator: operator, } } + +var basicSlicesPointerInt8FieldID = orm.FieldIdentifier{Field: "Int8"} + func BasicSlicesPointerInt8(operator orm.Operator[[]int8]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []int8]{ - Field: "Int8", - Operator: operator, + FieldIdentifier: basicSlicesPointerInt8FieldID, + Operator: operator, } } + +var basicSlicesPointerInt16FieldID = orm.FieldIdentifier{Field: "Int16"} + func BasicSlicesPointerInt16(operator orm.Operator[[]int16]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []int16]{ - Field: "Int16", - Operator: operator, + FieldIdentifier: basicSlicesPointerInt16FieldID, + Operator: operator, } } + +var basicSlicesPointerInt32FieldID = orm.FieldIdentifier{Field: "Int32"} + func BasicSlicesPointerInt32(operator orm.Operator[[]int32]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []int32]{ - Field: "Int32", - Operator: operator, + FieldIdentifier: basicSlicesPointerInt32FieldID, + Operator: operator, } } + +var basicSlicesPointerInt64FieldID = orm.FieldIdentifier{Field: "Int64"} + func BasicSlicesPointerInt64(operator orm.Operator[[]int64]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []int64]{ - Field: "Int64", - Operator: operator, + FieldIdentifier: basicSlicesPointerInt64FieldID, + Operator: operator, } } + +var basicSlicesPointerUIntFieldID = orm.FieldIdentifier{Field: "UInt"} + func BasicSlicesPointerUInt(operator orm.Operator[[]uint]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []uint]{ - Field: "UInt", - Operator: operator, + FieldIdentifier: basicSlicesPointerUIntFieldID, + Operator: operator, } } + +var basicSlicesPointerUInt8FieldID = orm.FieldIdentifier{Field: "UInt8"} + func BasicSlicesPointerUInt8(operator orm.Operator[[]uint8]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []uint8]{ - Field: "UInt8", - Operator: operator, + FieldIdentifier: basicSlicesPointerUInt8FieldID, + Operator: operator, } } + +var basicSlicesPointerUInt16FieldID = orm.FieldIdentifier{Field: "UInt16"} + func BasicSlicesPointerUInt16(operator orm.Operator[[]uint16]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []uint16]{ - Field: "UInt16", - Operator: operator, + FieldIdentifier: basicSlicesPointerUInt16FieldID, + Operator: operator, } } + +var basicSlicesPointerUInt32FieldID = orm.FieldIdentifier{Field: "UInt32"} + func BasicSlicesPointerUInt32(operator orm.Operator[[]uint32]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []uint32]{ - Field: "UInt32", - Operator: operator, + FieldIdentifier: basicSlicesPointerUInt32FieldID, + Operator: operator, } } + +var basicSlicesPointerUInt64FieldID = orm.FieldIdentifier{Field: "UInt64"} + func BasicSlicesPointerUInt64(operator orm.Operator[[]uint64]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []uint64]{ - Field: "UInt64", - Operator: operator, + FieldIdentifier: basicSlicesPointerUInt64FieldID, + Operator: operator, } } + +var basicSlicesPointerUIntptrFieldID = orm.FieldIdentifier{Field: "UIntptr"} + func BasicSlicesPointerUIntptr(operator orm.Operator[[]uintptr]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []uintptr]{ - Field: "UIntptr", - Operator: operator, + FieldIdentifier: basicSlicesPointerUIntptrFieldID, + Operator: operator, } } + +var basicSlicesPointerFloat32FieldID = orm.FieldIdentifier{Field: "Float32"} + func BasicSlicesPointerFloat32(operator orm.Operator[[]float32]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []float32]{ - Field: "Float32", - Operator: operator, + FieldIdentifier: basicSlicesPointerFloat32FieldID, + Operator: operator, } } + +var basicSlicesPointerFloat64FieldID = orm.FieldIdentifier{Field: "Float64"} + func BasicSlicesPointerFloat64(operator orm.Operator[[]float64]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []float64]{ - Field: "Float64", - Operator: operator, + FieldIdentifier: basicSlicesPointerFloat64FieldID, + Operator: operator, } } + +var basicSlicesPointerComplex64FieldID = orm.FieldIdentifier{Field: "Complex64"} + func BasicSlicesPointerComplex64(operator orm.Operator[[]complex64]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []complex64]{ - Field: "Complex64", - Operator: operator, + FieldIdentifier: basicSlicesPointerComplex64FieldID, + Operator: operator, } } + +var basicSlicesPointerComplex128FieldID = orm.FieldIdentifier{Field: "Complex128"} + func BasicSlicesPointerComplex128(operator orm.Operator[[]complex128]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []complex128]{ - Field: "Complex128", - Operator: operator, + FieldIdentifier: basicSlicesPointerComplex128FieldID, + Operator: operator, } } + +var basicSlicesPointerStringFieldID = orm.FieldIdentifier{Field: "String"} + func BasicSlicesPointerString(operator orm.Operator[[]string]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []string]{ - Field: "String", - Operator: operator, + FieldIdentifier: basicSlicesPointerStringFieldID, + Operator: operator, } } + +var basicSlicesPointerByteFieldID = orm.FieldIdentifier{Field: "Byte"} + func BasicSlicesPointerByte(operator orm.Operator[[]uint8]) orm.WhereCondition[basicslicespointer.BasicSlicesPointer] { return orm.FieldCondition[basicslicespointer.BasicSlicesPointer, []uint8]{ - Field: "Byte", - Operator: operator, + FieldIdentifier: basicSlicesPointerByteFieldID, + Operator: operator, } } + +var BasicSlicesPointerPreloadAttributes = orm.NewPreloadCondition[basicslicespointer.BasicSlicesPointer](basicSlicesPointerBoolFieldID, basicSlicesPointerIntFieldID, basicSlicesPointerInt8FieldID, basicSlicesPointerInt16FieldID, basicSlicesPointerInt32FieldID, basicSlicesPointerInt64FieldID, basicSlicesPointerUIntFieldID, basicSlicesPointerUInt8FieldID, basicSlicesPointerUInt16FieldID, basicSlicesPointerUInt32FieldID, basicSlicesPointerUInt64FieldID, basicSlicesPointerUIntptrFieldID, basicSlicesPointerFloat32FieldID, basicSlicesPointerFloat64FieldID, basicSlicesPointerComplex64FieldID, basicSlicesPointerComplex128FieldID, basicSlicesPointerStringFieldID, basicSlicesPointerByteFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/basictypes.go b/cli/cmd/gen/conditions/tests/results/basictypes.go index f7ef573..524224a 100644 --- a/cli/cmd/gen/conditions/tests/results/basictypes.go +++ b/cli/cmd/gen/conditions/tests/results/basictypes.go @@ -9,133 +9,189 @@ import ( func BasicTypesId(operator orm.Operator[orm.UUID]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func BasicTypesCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func BasicTypesUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func BasicTypesDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var basicTypesBoolFieldID = orm.FieldIdentifier{Field: "Bool"} + func BasicTypesBool(operator orm.Operator[bool]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, bool]{ - Field: "Bool", - Operator: operator, + FieldIdentifier: basicTypesBoolFieldID, + Operator: operator, } } + +var basicTypesIntFieldID = orm.FieldIdentifier{Field: "Int"} + func BasicTypesInt(operator orm.Operator[int]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, int]{ - Field: "Int", - Operator: operator, + FieldIdentifier: basicTypesIntFieldID, + Operator: operator, } } + +var basicTypesInt8FieldID = orm.FieldIdentifier{Field: "Int8"} + func BasicTypesInt8(operator orm.Operator[int8]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, int8]{ - Field: "Int8", - Operator: operator, + FieldIdentifier: basicTypesInt8FieldID, + Operator: operator, } } + +var basicTypesInt16FieldID = orm.FieldIdentifier{Field: "Int16"} + func BasicTypesInt16(operator orm.Operator[int16]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, int16]{ - Field: "Int16", - Operator: operator, + FieldIdentifier: basicTypesInt16FieldID, + Operator: operator, } } + +var basicTypesInt32FieldID = orm.FieldIdentifier{Field: "Int32"} + func BasicTypesInt32(operator orm.Operator[int32]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, int32]{ - Field: "Int32", - Operator: operator, + FieldIdentifier: basicTypesInt32FieldID, + Operator: operator, } } + +var basicTypesInt64FieldID = orm.FieldIdentifier{Field: "Int64"} + func BasicTypesInt64(operator orm.Operator[int64]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, int64]{ - Field: "Int64", - Operator: operator, + FieldIdentifier: basicTypesInt64FieldID, + Operator: operator, } } + +var basicTypesUIntFieldID = orm.FieldIdentifier{Field: "UInt"} + func BasicTypesUInt(operator orm.Operator[uint]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, uint]{ - Field: "UInt", - Operator: operator, + FieldIdentifier: basicTypesUIntFieldID, + Operator: operator, } } + +var basicTypesUInt8FieldID = orm.FieldIdentifier{Field: "UInt8"} + func BasicTypesUInt8(operator orm.Operator[uint8]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, uint8]{ - Field: "UInt8", - Operator: operator, + FieldIdentifier: basicTypesUInt8FieldID, + Operator: operator, } } + +var basicTypesUInt16FieldID = orm.FieldIdentifier{Field: "UInt16"} + func BasicTypesUInt16(operator orm.Operator[uint16]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, uint16]{ - Field: "UInt16", - Operator: operator, + FieldIdentifier: basicTypesUInt16FieldID, + Operator: operator, } } + +var basicTypesUInt32FieldID = orm.FieldIdentifier{Field: "UInt32"} + func BasicTypesUInt32(operator orm.Operator[uint32]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, uint32]{ - Field: "UInt32", - Operator: operator, + FieldIdentifier: basicTypesUInt32FieldID, + Operator: operator, } } + +var basicTypesUInt64FieldID = orm.FieldIdentifier{Field: "UInt64"} + func BasicTypesUInt64(operator orm.Operator[uint64]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, uint64]{ - Field: "UInt64", - Operator: operator, + FieldIdentifier: basicTypesUInt64FieldID, + Operator: operator, } } + +var basicTypesUIntptrFieldID = orm.FieldIdentifier{Field: "UIntptr"} + func BasicTypesUIntptr(operator orm.Operator[uintptr]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, uintptr]{ - Field: "UIntptr", - Operator: operator, + FieldIdentifier: basicTypesUIntptrFieldID, + Operator: operator, } } + +var basicTypesFloat32FieldID = orm.FieldIdentifier{Field: "Float32"} + func BasicTypesFloat32(operator orm.Operator[float32]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, float32]{ - Field: "Float32", - Operator: operator, + FieldIdentifier: basicTypesFloat32FieldID, + Operator: operator, } } + +var basicTypesFloat64FieldID = orm.FieldIdentifier{Field: "Float64"} + func BasicTypesFloat64(operator orm.Operator[float64]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, float64]{ - Field: "Float64", - Operator: operator, + FieldIdentifier: basicTypesFloat64FieldID, + Operator: operator, } } + +var basicTypesComplex64FieldID = orm.FieldIdentifier{Field: "Complex64"} + func BasicTypesComplex64(operator orm.Operator[complex64]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, complex64]{ - Field: "Complex64", - Operator: operator, + FieldIdentifier: basicTypesComplex64FieldID, + Operator: operator, } } + +var basicTypesComplex128FieldID = orm.FieldIdentifier{Field: "Complex128"} + func BasicTypesComplex128(operator orm.Operator[complex128]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, complex128]{ - Field: "Complex128", - Operator: operator, + FieldIdentifier: basicTypesComplex128FieldID, + Operator: operator, } } + +var basicTypesStringFieldID = orm.FieldIdentifier{Field: "String"} + func BasicTypesString(operator orm.Operator[string]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, string]{ - Field: "String", - Operator: operator, + FieldIdentifier: basicTypesStringFieldID, + Operator: operator, } } + +var basicTypesByteFieldID = orm.FieldIdentifier{Field: "Byte"} + func BasicTypesByte(operator orm.Operator[uint8]) orm.WhereCondition[basictypes.BasicTypes] { return orm.FieldCondition[basictypes.BasicTypes, uint8]{ - Field: "Byte", - Operator: operator, + FieldIdentifier: basicTypesByteFieldID, + Operator: operator, } } + +var BasicTypesPreloadAttributes = orm.NewPreloadCondition[basictypes.BasicTypes](basicTypesBoolFieldID, basicTypesIntFieldID, basicTypesInt8FieldID, basicTypesInt16FieldID, basicTypesInt32FieldID, basicTypesInt64FieldID, basicTypesUIntFieldID, basicTypesUInt8FieldID, basicTypesUInt16FieldID, basicTypesUInt32FieldID, basicTypesUInt64FieldID, basicTypesUIntptrFieldID, basicTypesFloat32FieldID, basicTypesFloat64FieldID, basicTypesComplex64FieldID, basicTypesComplex128FieldID, basicTypesStringFieldID, basicTypesByteFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/belongsto_owned.go b/cli/cmd/gen/conditions/tests/results/belongsto_owned.go index b356c6e..de876fb 100644 --- a/cli/cmd/gen/conditions/tests/results/belongsto_owned.go +++ b/cli/cmd/gen/conditions/tests/results/belongsto_owned.go @@ -9,38 +9,47 @@ import ( func OwnedId(operator orm.Operator[orm.UUID]) orm.WhereCondition[belongsto.Owned] { return orm.FieldCondition[belongsto.Owned, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func OwnedCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[belongsto.Owned] { return orm.FieldCondition[belongsto.Owned, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func OwnedUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[belongsto.Owned] { return orm.FieldCondition[belongsto.Owned, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func OwnedDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[belongsto.Owned] { return orm.FieldCondition[belongsto.Owned, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } -func OwnedOwner(conditions ...orm.Condition[belongsto.Owner]) orm.Condition[belongsto.Owned] { +func OwnedOwner(conditions ...orm.Condition[belongsto.Owner]) orm.IJoinCondition[belongsto.Owned] { return orm.JoinCondition[belongsto.Owned, belongsto.Owner]{ - Conditions: conditions, - T1Field: "OwnerID", - T2Field: "ID", + Conditions: conditions, + RelationField: "Owner", + T1Field: "OwnerID", + T1PreloadCondition: OwnedPreloadAttributes, + T2Field: "ID", } } + +var OwnedPreloadOwner = OwnedOwner(OwnerPreloadAttributes) +var ownedOwnerIdFieldID = orm.FieldIdentifier{Field: "OwnerID"} + func OwnedOwnerId(operator orm.Operator[orm.UUID]) orm.WhereCondition[belongsto.Owned] { return orm.FieldCondition[belongsto.Owned, orm.UUID]{ - Field: "OwnerID", - Operator: operator, + FieldIdentifier: ownedOwnerIdFieldID, + Operator: operator, } } + +var OwnedPreloadAttributes = orm.NewPreloadCondition[belongsto.Owned](ownedOwnerIdFieldID) +var OwnedPreloadRelations = []orm.Condition[belongsto.Owned]{OwnedPreloadOwner} diff --git a/cli/cmd/gen/conditions/tests/results/belongsto_owner.go b/cli/cmd/gen/conditions/tests/results/belongsto_owner.go index 1023f3f..5f5b45e 100644 --- a/cli/cmd/gen/conditions/tests/results/belongsto_owner.go +++ b/cli/cmd/gen/conditions/tests/results/belongsto_owner.go @@ -9,25 +9,27 @@ import ( func OwnerId(operator orm.Operator[orm.UUID]) orm.WhereCondition[belongsto.Owner] { return orm.FieldCondition[belongsto.Owner, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func OwnerCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[belongsto.Owner] { return orm.FieldCondition[belongsto.Owner, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func OwnerUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[belongsto.Owner] { return orm.FieldCondition[belongsto.Owner, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func OwnerDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[belongsto.Owner] { return orm.FieldCondition[belongsto.Owner, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var OwnerPreloadAttributes = orm.NewPreloadCondition[belongsto.Owner]() diff --git a/cli/cmd/gen/conditions/tests/results/columndefinition.go b/cli/cmd/gen/conditions/tests/results/columndefinition.go index 17b5c2e..0f9748a 100644 --- a/cli/cmd/gen/conditions/tests/results/columndefinition.go +++ b/cli/cmd/gen/conditions/tests/results/columndefinition.go @@ -9,31 +9,36 @@ import ( func ColumnDefinitionId(operator orm.Operator[orm.UUID]) orm.WhereCondition[columndefinition.ColumnDefinition] { return orm.FieldCondition[columndefinition.ColumnDefinition, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func ColumnDefinitionCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[columndefinition.ColumnDefinition] { return orm.FieldCondition[columndefinition.ColumnDefinition, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func ColumnDefinitionUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[columndefinition.ColumnDefinition] { return orm.FieldCondition[columndefinition.ColumnDefinition, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func ColumnDefinitionDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[columndefinition.ColumnDefinition] { return orm.FieldCondition[columndefinition.ColumnDefinition, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var columnDefinitionStringFieldID = orm.FieldIdentifier{Column: "string_something_else"} + func ColumnDefinitionString(operator orm.Operator[string]) orm.WhereCondition[columndefinition.ColumnDefinition] { return orm.FieldCondition[columndefinition.ColumnDefinition, string]{ - Column: "string_something_else", - Operator: operator, + FieldIdentifier: columnDefinitionStringFieldID, + Operator: operator, } } + +var ColumnDefinitionPreloadAttributes = orm.NewPreloadCondition[columndefinition.ColumnDefinition](columnDefinitionStringFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/customtype.go b/cli/cmd/gen/conditions/tests/results/customtype.go index 0c21b8a..7abc784 100644 --- a/cli/cmd/gen/conditions/tests/results/customtype.go +++ b/cli/cmd/gen/conditions/tests/results/customtype.go @@ -9,31 +9,36 @@ import ( func CustomTypeId(operator orm.Operator[orm.UUID]) orm.WhereCondition[customtype.CustomType] { return orm.FieldCondition[customtype.CustomType, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func CustomTypeCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[customtype.CustomType] { return orm.FieldCondition[customtype.CustomType, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func CustomTypeUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[customtype.CustomType] { return orm.FieldCondition[customtype.CustomType, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func CustomTypeDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[customtype.CustomType] { return orm.FieldCondition[customtype.CustomType, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var customTypeCustomFieldID = orm.FieldIdentifier{Field: "Custom"} + func CustomTypeCustom(operator orm.Operator[customtype.MultiString]) orm.WhereCondition[customtype.CustomType] { return orm.FieldCondition[customtype.CustomType, customtype.MultiString]{ - Field: "Custom", - Operator: operator, + FieldIdentifier: customTypeCustomFieldID, + Operator: operator, } } + +var CustomTypePreloadAttributes = orm.NewPreloadCondition[customtype.CustomType](customTypeCustomFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/goembedded.go b/cli/cmd/gen/conditions/tests/results/goembedded.go index 47f6ba7..e3d5bc8 100644 --- a/cli/cmd/gen/conditions/tests/results/goembedded.go +++ b/cli/cmd/gen/conditions/tests/results/goembedded.go @@ -7,33 +7,47 @@ import ( "time" ) -func GoEmbeddedId(operator orm.Operator[uint]) orm.WhereCondition[goembedded.GoEmbedded] { - return orm.FieldCondition[goembedded.GoEmbedded, uint]{ - Field: "ID", - Operator: operator, +func GoEmbeddedId(operator orm.Operator[orm.UIntID]) orm.WhereCondition[goembedded.GoEmbedded] { + return orm.FieldCondition[goembedded.GoEmbedded, orm.UIntID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func GoEmbeddedCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[goembedded.GoEmbedded] { return orm.FieldCondition[goembedded.GoEmbedded, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func GoEmbeddedUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[goembedded.GoEmbedded] { return orm.FieldCondition[goembedded.GoEmbedded, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func GoEmbeddedDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[goembedded.GoEmbedded] { return orm.FieldCondition[goembedded.GoEmbedded, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } -func GoEmbeddedEmbeddedInt(operator orm.Operator[int]) orm.WhereCondition[goembedded.GoEmbedded] { + +var goEmbeddedIntFieldID = orm.FieldIdentifier{Field: "Int"} + +func GoEmbeddedInt(operator orm.Operator[int]) orm.WhereCondition[goembedded.GoEmbedded] { + return orm.FieldCondition[goembedded.GoEmbedded, int]{ + FieldIdentifier: goEmbeddedIntFieldID, + Operator: operator, + } +} + +var goEmbeddedToBeEmbeddedIntFieldID = orm.FieldIdentifier{Field: "Int"} + +func GoEmbeddedToBeEmbeddedInt(operator orm.Operator[int]) orm.WhereCondition[goembedded.GoEmbedded] { return orm.FieldCondition[goembedded.GoEmbedded, int]{ - Field: "EmbeddedInt", - Operator: operator, + FieldIdentifier: goEmbeddedToBeEmbeddedIntFieldID, + Operator: operator, } } + +var GoEmbeddedPreloadAttributes = orm.NewPreloadCondition[goembedded.GoEmbedded](goEmbeddedIntFieldID, goEmbeddedToBeEmbeddedIntFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/gormembedded.go b/cli/cmd/gen/conditions/tests/results/gormembedded.go index 47fb5eb..5501c42 100644 --- a/cli/cmd/gen/conditions/tests/results/gormembedded.go +++ b/cli/cmd/gen/conditions/tests/results/gormembedded.go @@ -7,34 +7,59 @@ import ( "time" ) -func GormEmbeddedId(operator orm.Operator[uint]) orm.WhereCondition[gormembedded.GormEmbedded] { - return orm.FieldCondition[gormembedded.GormEmbedded, uint]{ - Field: "ID", - Operator: operator, +func GormEmbeddedId(operator orm.Operator[orm.UIntID]) orm.WhereCondition[gormembedded.GormEmbedded] { + return orm.FieldCondition[gormembedded.GormEmbedded, orm.UIntID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func GormEmbeddedCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[gormembedded.GormEmbedded] { return orm.FieldCondition[gormembedded.GormEmbedded, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func GormEmbeddedUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[gormembedded.GormEmbedded] { return orm.FieldCondition[gormembedded.GormEmbedded, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func GormEmbeddedDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[gormembedded.GormEmbedded] { return orm.FieldCondition[gormembedded.GormEmbedded, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var gormEmbeddedIntFieldID = orm.FieldIdentifier{Field: "Int"} + +func GormEmbeddedInt(operator orm.Operator[int]) orm.WhereCondition[gormembedded.GormEmbedded] { + return orm.FieldCondition[gormembedded.GormEmbedded, int]{ + FieldIdentifier: gormEmbeddedIntFieldID, + Operator: operator, + } +} + +var gormEmbeddedGormEmbeddedIntFieldID = orm.FieldIdentifier{ + ColumnPrefix: "gorm_embedded_", + Field: "Int", +} + func GormEmbeddedGormEmbeddedInt(operator orm.Operator[int]) orm.WhereCondition[gormembedded.GormEmbedded] { return orm.FieldCondition[gormembedded.GormEmbedded, int]{ - ColumnPrefix: "gorm_embedded_", - Field: "Int", - Operator: operator, + FieldIdentifier: gormEmbeddedGormEmbeddedIntFieldID, + Operator: operator, } } + +var gormEmbeddedGormEmbeddedNoPrefixIntFieldID = orm.FieldIdentifier{Field: "Int"} + +func GormEmbeddedGormEmbeddedNoPrefixInt(operator orm.Operator[int]) orm.WhereCondition[gormembedded.GormEmbedded] { + return orm.FieldCondition[gormembedded.GormEmbedded, int]{ + FieldIdentifier: gormEmbeddedGormEmbeddedNoPrefixIntFieldID, + Operator: operator, + } +} + +var GormEmbeddedPreloadAttributes = orm.NewPreloadCondition[gormembedded.GormEmbedded](gormEmbeddedIntFieldID, gormEmbeddedGormEmbeddedIntFieldID, gormEmbeddedGormEmbeddedNoPrefixIntFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/hasmany_company.go b/cli/cmd/gen/conditions/tests/results/hasmany_company.go index 7e24755..d492aaf 100644 --- a/cli/cmd/gen/conditions/tests/results/hasmany_company.go +++ b/cli/cmd/gen/conditions/tests/results/hasmany_company.go @@ -9,32 +9,31 @@ import ( func CompanyId(operator orm.Operator[orm.UUID]) orm.WhereCondition[hasmany.Company] { return orm.FieldCondition[hasmany.Company, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func CompanyCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmany.Company] { return orm.FieldCondition[hasmany.Company, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func CompanyUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmany.Company] { return orm.FieldCondition[hasmany.Company, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func CompanyDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmany.Company] { return orm.FieldCondition[hasmany.Company, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } -func SellerCompany(conditions ...orm.Condition[hasmany.Company]) orm.Condition[hasmany.Seller] { - return orm.JoinCondition[hasmany.Seller, hasmany.Company]{ - Conditions: conditions, - T1Field: "CompanyID", - T2Field: "ID", - } +func CompanyPreloadSellers(nestedPreloads ...orm.IJoinCondition[hasmany.Seller]) orm.Condition[hasmany.Company] { + return orm.NewCollectionPreloadCondition[hasmany.Company, hasmany.Seller]("Sellers", nestedPreloads) } + +var CompanyPreloadAttributes = orm.NewPreloadCondition[hasmany.Company]() +var CompanyPreloadRelations = []orm.Condition[hasmany.Company]{CompanyPreloadSellers()} diff --git a/cli/cmd/gen/conditions/tests/results/hasmany_seller.go b/cli/cmd/gen/conditions/tests/results/hasmany_seller.go index 501ee06..b8245c8 100644 --- a/cli/cmd/gen/conditions/tests/results/hasmany_seller.go +++ b/cli/cmd/gen/conditions/tests/results/hasmany_seller.go @@ -9,31 +9,47 @@ import ( func SellerId(operator orm.Operator[orm.UUID]) orm.WhereCondition[hasmany.Seller] { return orm.FieldCondition[hasmany.Seller, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func SellerCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmany.Seller] { return orm.FieldCondition[hasmany.Seller, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func SellerUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmany.Seller] { return orm.FieldCondition[hasmany.Seller, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func SellerDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmany.Seller] { return orm.FieldCondition[hasmany.Seller, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } +func SellerCompany(conditions ...orm.Condition[hasmany.Company]) orm.IJoinCondition[hasmany.Seller] { + return orm.JoinCondition[hasmany.Seller, hasmany.Company]{ + Conditions: conditions, + RelationField: "Company", + T1Field: "CompanyID", + T1PreloadCondition: SellerPreloadAttributes, + T2Field: "ID", + } +} + +var SellerPreloadCompany = SellerCompany(CompanyPreloadAttributes) +var sellerCompanyIdFieldID = orm.FieldIdentifier{Field: "CompanyID"} + func SellerCompanyId(operator orm.Operator[orm.UUID]) orm.WhereCondition[hasmany.Seller] { return orm.FieldCondition[hasmany.Seller, orm.UUID]{ - Field: "CompanyID", - Operator: operator, + FieldIdentifier: sellerCompanyIdFieldID, + Operator: operator, } } + +var SellerPreloadAttributes = orm.NewPreloadCondition[hasmany.Seller](sellerCompanyIdFieldID) +var SellerPreloadRelations = []orm.Condition[hasmany.Seller]{SellerPreloadCompany} diff --git a/cli/cmd/gen/conditions/tests/results/hasmanywithpointers_company.go b/cli/cmd/gen/conditions/tests/results/hasmanywithpointers_company.go new file mode 100644 index 0000000..0a88f08 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/results/hasmanywithpointers_company.go @@ -0,0 +1,39 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + hasmanywithpointers "github.com/ditrit/badaas-orm/cli/cmd/gen/conditions/tests/hasmanywithpointers" + orm "github.com/ditrit/badaas/orm" + "time" +) + +func CompanyWithPointersId(operator orm.Operator[orm.UUID]) orm.WhereCondition[hasmanywithpointers.CompanyWithPointers] { + return orm.FieldCondition[hasmanywithpointers.CompanyWithPointers, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func CompanyWithPointersCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmanywithpointers.CompanyWithPointers] { + return orm.FieldCondition[hasmanywithpointers.CompanyWithPointers, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func CompanyWithPointersUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmanywithpointers.CompanyWithPointers] { + return orm.FieldCondition[hasmanywithpointers.CompanyWithPointers, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func CompanyWithPointersDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmanywithpointers.CompanyWithPointers] { + return orm.FieldCondition[hasmanywithpointers.CompanyWithPointers, time.Time]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} +func CompanyWithPointersPreloadSellers(nestedPreloads ...orm.IJoinCondition[hasmanywithpointers.SellerInPointers]) orm.Condition[hasmanywithpointers.CompanyWithPointers] { + return orm.NewCollectionPreloadCondition[hasmanywithpointers.CompanyWithPointers, hasmanywithpointers.SellerInPointers]("Sellers", nestedPreloads) +} + +var CompanyWithPointersPreloadAttributes = orm.NewPreloadCondition[hasmanywithpointers.CompanyWithPointers]() +var CompanyWithPointersPreloadRelations = []orm.Condition[hasmanywithpointers.CompanyWithPointers]{CompanyWithPointersPreloadSellers()} diff --git a/cli/cmd/gen/conditions/tests/results/hasmanywithpointers_seller.go b/cli/cmd/gen/conditions/tests/results/hasmanywithpointers_seller.go new file mode 100644 index 0000000..869b4c7 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/results/hasmanywithpointers_seller.go @@ -0,0 +1,55 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + hasmanywithpointers "github.com/ditrit/badaas-orm/cli/cmd/gen/conditions/tests/hasmanywithpointers" + orm "github.com/ditrit/badaas/orm" + "time" +) + +func SellerInPointersId(operator orm.Operator[orm.UUID]) orm.WhereCondition[hasmanywithpointers.SellerInPointers] { + return orm.FieldCondition[hasmanywithpointers.SellerInPointers, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func SellerInPointersCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmanywithpointers.SellerInPointers] { + return orm.FieldCondition[hasmanywithpointers.SellerInPointers, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func SellerInPointersUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmanywithpointers.SellerInPointers] { + return orm.FieldCondition[hasmanywithpointers.SellerInPointers, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func SellerInPointersDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasmanywithpointers.SellerInPointers] { + return orm.FieldCondition[hasmanywithpointers.SellerInPointers, time.Time]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} +func SellerInPointersCompany(conditions ...orm.Condition[hasmanywithpointers.CompanyWithPointers]) orm.IJoinCondition[hasmanywithpointers.SellerInPointers] { + return orm.JoinCondition[hasmanywithpointers.SellerInPointers, hasmanywithpointers.CompanyWithPointers]{ + Conditions: conditions, + RelationField: "Company", + T1Field: "CompanyID", + T1PreloadCondition: SellerInPointersPreloadAttributes, + T2Field: "ID", + } +} + +var SellerInPointersPreloadCompany = SellerInPointersCompany(CompanyWithPointersPreloadAttributes) +var sellerInPointersCompanyIdFieldID = orm.FieldIdentifier{Field: "CompanyID"} + +func SellerInPointersCompanyId(operator orm.Operator[orm.UUID]) orm.WhereCondition[hasmanywithpointers.SellerInPointers] { + return orm.FieldCondition[hasmanywithpointers.SellerInPointers, orm.UUID]{ + FieldIdentifier: sellerInPointersCompanyIdFieldID, + Operator: operator, + } +} + +var SellerInPointersPreloadAttributes = orm.NewPreloadCondition[hasmanywithpointers.SellerInPointers](sellerInPointersCompanyIdFieldID) +var SellerInPointersPreloadRelations = []orm.Condition[hasmanywithpointers.SellerInPointers]{SellerInPointersPreloadCompany} diff --git a/cli/cmd/gen/conditions/tests/results/hasone_city.go b/cli/cmd/gen/conditions/tests/results/hasone_city.go index 288dd96..bfbfe1d 100644 --- a/cli/cmd/gen/conditions/tests/results/hasone_city.go +++ b/cli/cmd/gen/conditions/tests/results/hasone_city.go @@ -9,31 +9,47 @@ import ( func CityId(operator orm.Operator[orm.UUID]) orm.WhereCondition[hasone.City] { return orm.FieldCondition[hasone.City, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func CityCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasone.City] { return orm.FieldCondition[hasone.City, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func CityUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasone.City] { return orm.FieldCondition[hasone.City, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func CityDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasone.City] { return orm.FieldCondition[hasone.City, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } +func CityCountry(conditions ...orm.Condition[hasone.Country]) orm.IJoinCondition[hasone.City] { + return orm.JoinCondition[hasone.City, hasone.Country]{ + Conditions: conditions, + RelationField: "Country", + T1Field: "CountryID", + T1PreloadCondition: CityPreloadAttributes, + T2Field: "ID", + } +} + +var CityPreloadCountry = CityCountry(CountryPreloadAttributes) +var cityCountryIdFieldID = orm.FieldIdentifier{Field: "CountryID"} + func CityCountryId(operator orm.Operator[orm.UUID]) orm.WhereCondition[hasone.City] { return orm.FieldCondition[hasone.City, orm.UUID]{ - Field: "CountryID", - Operator: operator, + FieldIdentifier: cityCountryIdFieldID, + Operator: operator, } } + +var CityPreloadAttributes = orm.NewPreloadCondition[hasone.City](cityCountryIdFieldID) +var CityPreloadRelations = []orm.Condition[hasone.City]{CityPreloadCountry} diff --git a/cli/cmd/gen/conditions/tests/results/hasone_country.go b/cli/cmd/gen/conditions/tests/results/hasone_country.go index bd7a126..38df31c 100644 --- a/cli/cmd/gen/conditions/tests/results/hasone_country.go +++ b/cli/cmd/gen/conditions/tests/results/hasone_country.go @@ -9,39 +9,38 @@ import ( func CountryId(operator orm.Operator[orm.UUID]) orm.WhereCondition[hasone.Country] { return orm.FieldCondition[hasone.Country, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func CountryCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasone.Country] { return orm.FieldCondition[hasone.Country, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func CountryUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasone.Country] { return orm.FieldCondition[hasone.Country, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func CountryDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[hasone.Country] { return orm.FieldCondition[hasone.Country, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } -func CountryCapital(conditions ...orm.Condition[hasone.City]) orm.Condition[hasone.Country] { +func CountryCapital(conditions ...orm.Condition[hasone.City]) orm.IJoinCondition[hasone.Country] { return orm.JoinCondition[hasone.Country, hasone.City]{ - Conditions: conditions, - T1Field: "ID", - T2Field: "CountryID", - } -} -func CityCountry(conditions ...orm.Condition[hasone.Country]) orm.Condition[hasone.City] { - return orm.JoinCondition[hasone.City, hasone.Country]{ - Conditions: conditions, - T1Field: "CountryID", - T2Field: "ID", + Conditions: conditions, + RelationField: "Capital", + T1Field: "ID", + T1PreloadCondition: CountryPreloadAttributes, + T2Field: "CountryID", } } + +var CountryPreloadCapital = CountryCapital(CityPreloadAttributes) +var CountryPreloadAttributes = orm.NewPreloadCondition[hasone.Country]() +var CountryPreloadRelations = []orm.Condition[hasone.Country]{CountryPreloadCapital} diff --git a/cli/cmd/gen/conditions/tests/results/multiplepackage_package1.go b/cli/cmd/gen/conditions/tests/results/multiplepackage_package1.go index e932579..6465ba2 100644 --- a/cli/cmd/gen/conditions/tests/results/multiplepackage_package1.go +++ b/cli/cmd/gen/conditions/tests/results/multiplepackage_package1.go @@ -10,39 +10,38 @@ import ( func Package1Id(operator orm.Operator[orm.UUID]) orm.WhereCondition[package1.Package1] { return orm.FieldCondition[package1.Package1, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func Package1CreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[package1.Package1] { return orm.FieldCondition[package1.Package1, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func Package1UpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[package1.Package1] { return orm.FieldCondition[package1.Package1, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func Package1DeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[package1.Package1] { return orm.FieldCondition[package1.Package1, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } -func Package1Package2(conditions ...orm.Condition[package2.Package2]) orm.Condition[package1.Package1] { +func Package1Package2(conditions ...orm.Condition[package2.Package2]) orm.IJoinCondition[package1.Package1] { return orm.JoinCondition[package1.Package1, package2.Package2]{ - Conditions: conditions, - T1Field: "ID", - T2Field: "Package1ID", - } -} -func Package2Package1(conditions ...orm.Condition[package1.Package1]) orm.Condition[package2.Package2] { - return orm.JoinCondition[package2.Package2, package1.Package1]{ - Conditions: conditions, - T1Field: "Package1ID", - T2Field: "ID", + Conditions: conditions, + RelationField: "Package2", + T1Field: "ID", + T1PreloadCondition: Package1PreloadAttributes, + T2Field: "Package1ID", } } + +var Package1PreloadPackage2 = Package1Package2(Package2PreloadAttributes) +var Package1PreloadAttributes = orm.NewPreloadCondition[package1.Package1]() +var Package1PreloadRelations = []orm.Condition[package1.Package1]{Package1PreloadPackage2} diff --git a/cli/cmd/gen/conditions/tests/results/multiplepackage_package2.go b/cli/cmd/gen/conditions/tests/results/multiplepackage_package2.go new file mode 100644 index 0000000..6a37cfc --- /dev/null +++ b/cli/cmd/gen/conditions/tests/results/multiplepackage_package2.go @@ -0,0 +1,44 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + package2 "github.com/ditrit/badaas-orm/cli/cmd/gen/conditions/tests/multiplepackage/package2" + orm "github.com/ditrit/badaas/orm" + "time" +) + +func Package2Id(operator orm.Operator[orm.UUID]) orm.WhereCondition[package2.Package2] { + return orm.FieldCondition[package2.Package2, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func Package2CreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[package2.Package2] { + return orm.FieldCondition[package2.Package2, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func Package2UpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[package2.Package2] { + return orm.FieldCondition[package2.Package2, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func Package2DeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[package2.Package2] { + return orm.FieldCondition[package2.Package2, time.Time]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} + +var package2Package1IdFieldID = orm.FieldIdentifier{Field: "Package1ID"} + +func Package2Package1Id(operator orm.Operator[orm.UUID]) orm.WhereCondition[package2.Package2] { + return orm.FieldCondition[package2.Package2, orm.UUID]{ + FieldIdentifier: package2Package1IdFieldID, + Operator: operator, + } +} + +var Package2PreloadAttributes = orm.NewPreloadCondition[package2.Package2](package2Package1IdFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/nullabletypes.go b/cli/cmd/gen/conditions/tests/results/nullabletypes.go index 6cfca38..6fe3c34 100644 --- a/cli/cmd/gen/conditions/tests/results/nullabletypes.go +++ b/cli/cmd/gen/conditions/tests/results/nullabletypes.go @@ -9,73 +9,99 @@ import ( func NullableTypesId(operator orm.Operator[orm.UUID]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func NullableTypesCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func NullableTypesUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func NullableTypesDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var nullableTypesStringFieldID = orm.FieldIdentifier{Field: "String"} + func NullableTypesString(operator orm.Operator[string]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, string]{ - Field: "String", - Operator: operator, + FieldIdentifier: nullableTypesStringFieldID, + Operator: operator, } } + +var nullableTypesInt64FieldID = orm.FieldIdentifier{Field: "Int64"} + func NullableTypesInt64(operator orm.Operator[int64]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, int64]{ - Field: "Int64", - Operator: operator, + FieldIdentifier: nullableTypesInt64FieldID, + Operator: operator, } } + +var nullableTypesInt32FieldID = orm.FieldIdentifier{Field: "Int32"} + func NullableTypesInt32(operator orm.Operator[int32]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, int32]{ - Field: "Int32", - Operator: operator, + FieldIdentifier: nullableTypesInt32FieldID, + Operator: operator, } } + +var nullableTypesInt16FieldID = orm.FieldIdentifier{Field: "Int16"} + func NullableTypesInt16(operator orm.Operator[int16]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, int16]{ - Field: "Int16", - Operator: operator, + FieldIdentifier: nullableTypesInt16FieldID, + Operator: operator, } } + +var nullableTypesByteFieldID = orm.FieldIdentifier{Field: "Byte"} + func NullableTypesByte(operator orm.Operator[int8]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, int8]{ - Field: "Byte", - Operator: operator, + FieldIdentifier: nullableTypesByteFieldID, + Operator: operator, } } + +var nullableTypesFloat64FieldID = orm.FieldIdentifier{Field: "Float64"} + func NullableTypesFloat64(operator orm.Operator[float64]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, float64]{ - Field: "Float64", - Operator: operator, + FieldIdentifier: nullableTypesFloat64FieldID, + Operator: operator, } } + +var nullableTypesBoolFieldID = orm.FieldIdentifier{Field: "Bool"} + func NullableTypesBool(operator orm.Operator[bool]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, bool]{ - Field: "Bool", - Operator: operator, + FieldIdentifier: nullableTypesBoolFieldID, + Operator: operator, } } + +var nullableTypesTimeFieldID = orm.FieldIdentifier{Field: "Time"} + func NullableTypesTime(operator orm.Operator[time.Time]) orm.WhereCondition[nullabletypes.NullableTypes] { return orm.FieldCondition[nullabletypes.NullableTypes, time.Time]{ - Field: "Time", - Operator: operator, + FieldIdentifier: nullableTypesTimeFieldID, + Operator: operator, } } + +var NullableTypesPreloadAttributes = orm.NewPreloadCondition[nullabletypes.NullableTypes](nullableTypesStringFieldID, nullableTypesInt64FieldID, nullableTypesInt32FieldID, nullableTypesInt16FieldID, nullableTypesByteFieldID, nullableTypesFloat64FieldID, nullableTypesBoolFieldID, nullableTypesTimeFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/overrideforeignkey.go b/cli/cmd/gen/conditions/tests/results/overrideforeignkey_bicycle.go similarity index 56% rename from cli/cmd/gen/conditions/tests/results/overrideforeignkey.go rename to cli/cmd/gen/conditions/tests/results/overrideforeignkey_bicycle.go index 393d984..020db56 100644 --- a/cli/cmd/gen/conditions/tests/results/overrideforeignkey.go +++ b/cli/cmd/gen/conditions/tests/results/overrideforeignkey_bicycle.go @@ -9,38 +9,47 @@ import ( func BicycleId(operator orm.Operator[orm.UUID]) orm.WhereCondition[overrideforeignkey.Bicycle] { return orm.FieldCondition[overrideforeignkey.Bicycle, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func BicycleCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkey.Bicycle] { return orm.FieldCondition[overrideforeignkey.Bicycle, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func BicycleUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkey.Bicycle] { return orm.FieldCondition[overrideforeignkey.Bicycle, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func BicycleDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkey.Bicycle] { return orm.FieldCondition[overrideforeignkey.Bicycle, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } -func BicycleOwner(conditions ...orm.Condition[overrideforeignkey.Person]) orm.Condition[overrideforeignkey.Bicycle] { +func BicycleOwner(conditions ...orm.Condition[overrideforeignkey.Person]) orm.IJoinCondition[overrideforeignkey.Bicycle] { return orm.JoinCondition[overrideforeignkey.Bicycle, overrideforeignkey.Person]{ - Conditions: conditions, - T1Field: "OwnerSomethingID", - T2Field: "ID", + Conditions: conditions, + RelationField: "Owner", + T1Field: "OwnerSomethingID", + T1PreloadCondition: BicyclePreloadAttributes, + T2Field: "ID", } } + +var BicyclePreloadOwner = BicycleOwner(PersonPreloadAttributes) +var bicycleOwnerSomethingIdFieldID = orm.FieldIdentifier{Field: "OwnerSomethingID"} + func BicycleOwnerSomethingId(operator orm.Operator[string]) orm.WhereCondition[overrideforeignkey.Bicycle] { return orm.FieldCondition[overrideforeignkey.Bicycle, string]{ - Field: "OwnerSomethingID", - Operator: operator, + FieldIdentifier: bicycleOwnerSomethingIdFieldID, + Operator: operator, } } + +var BicyclePreloadAttributes = orm.NewPreloadCondition[overrideforeignkey.Bicycle](bicycleOwnerSomethingIdFieldID) +var BicyclePreloadRelations = []orm.Condition[overrideforeignkey.Bicycle]{BicyclePreloadOwner} diff --git a/cli/cmd/gen/conditions/tests/results/overrideforeignkey_person.go b/cli/cmd/gen/conditions/tests/results/overrideforeignkey_person.go new file mode 100644 index 0000000..0c4d708 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/results/overrideforeignkey_person.go @@ -0,0 +1,35 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + overrideforeignkey "github.com/ditrit/badaas-orm/cli/cmd/gen/conditions/tests/overrideforeignkey" + orm "github.com/ditrit/badaas/orm" + "time" +) + +func PersonId(operator orm.Operator[orm.UUID]) orm.WhereCondition[overrideforeignkey.Person] { + return orm.FieldCondition[overrideforeignkey.Person, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func PersonCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkey.Person] { + return orm.FieldCondition[overrideforeignkey.Person, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func PersonUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkey.Person] { + return orm.FieldCondition[overrideforeignkey.Person, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func PersonDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkey.Person] { + return orm.FieldCondition[overrideforeignkey.Person, time.Time]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} + +var PersonPreloadAttributes = orm.NewPreloadCondition[overrideforeignkey.Person]() diff --git a/cli/cmd/gen/conditions/tests/results/overrideforeignkeyinverse_credit_card.go b/cli/cmd/gen/conditions/tests/results/overrideforeignkeyinverse_credit_card.go new file mode 100644 index 0000000..0ee8534 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/results/overrideforeignkeyinverse_credit_card.go @@ -0,0 +1,44 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + overrideforeignkeyinverse "github.com/ditrit/badaas-orm/cli/cmd/gen/conditions/tests/overrideforeignkeyinverse" + orm "github.com/ditrit/badaas/orm" + "time" +) + +func CreditCardId(operator orm.Operator[orm.UUID]) orm.WhereCondition[overrideforeignkeyinverse.CreditCard] { + return orm.FieldCondition[overrideforeignkeyinverse.CreditCard, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func CreditCardCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkeyinverse.CreditCard] { + return orm.FieldCondition[overrideforeignkeyinverse.CreditCard, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func CreditCardUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkeyinverse.CreditCard] { + return orm.FieldCondition[overrideforeignkeyinverse.CreditCard, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func CreditCardDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkeyinverse.CreditCard] { + return orm.FieldCondition[overrideforeignkeyinverse.CreditCard, time.Time]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} + +var creditCardUserReferenceFieldID = orm.FieldIdentifier{Field: "UserReference"} + +func CreditCardUserReference(operator orm.Operator[orm.UUID]) orm.WhereCondition[overrideforeignkeyinverse.CreditCard] { + return orm.FieldCondition[overrideforeignkeyinverse.CreditCard, orm.UUID]{ + FieldIdentifier: creditCardUserReferenceFieldID, + Operator: operator, + } +} + +var CreditCardPreloadAttributes = orm.NewPreloadCondition[overrideforeignkeyinverse.CreditCard](creditCardUserReferenceFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/overrideforeignkeyinverse.go b/cli/cmd/gen/conditions/tests/results/overrideforeignkeyinverse_user.go similarity index 58% rename from cli/cmd/gen/conditions/tests/results/overrideforeignkeyinverse.go rename to cli/cmd/gen/conditions/tests/results/overrideforeignkeyinverse_user.go index 2ed5dfc..20e4645 100644 --- a/cli/cmd/gen/conditions/tests/results/overrideforeignkeyinverse.go +++ b/cli/cmd/gen/conditions/tests/results/overrideforeignkeyinverse_user.go @@ -9,39 +9,38 @@ import ( func UserId(operator orm.Operator[orm.UUID]) orm.WhereCondition[overrideforeignkeyinverse.User] { return orm.FieldCondition[overrideforeignkeyinverse.User, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func UserCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkeyinverse.User] { return orm.FieldCondition[overrideforeignkeyinverse.User, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func UserUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkeyinverse.User] { return orm.FieldCondition[overrideforeignkeyinverse.User, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func UserDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overrideforeignkeyinverse.User] { return orm.FieldCondition[overrideforeignkeyinverse.User, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } -func UserCreditCard(conditions ...orm.Condition[overrideforeignkeyinverse.CreditCard]) orm.Condition[overrideforeignkeyinverse.User] { +func UserCreditCard(conditions ...orm.Condition[overrideforeignkeyinverse.CreditCard]) orm.IJoinCondition[overrideforeignkeyinverse.User] { return orm.JoinCondition[overrideforeignkeyinverse.User, overrideforeignkeyinverse.CreditCard]{ - Conditions: conditions, - T1Field: "ID", - T2Field: "UserReference", - } -} -func CreditCardUser(conditions ...orm.Condition[overrideforeignkeyinverse.User]) orm.Condition[overrideforeignkeyinverse.CreditCard] { - return orm.JoinCondition[overrideforeignkeyinverse.CreditCard, overrideforeignkeyinverse.User]{ - Conditions: conditions, - T1Field: "UserReference", - T2Field: "ID", + Conditions: conditions, + RelationField: "CreditCard", + T1Field: "ID", + T1PreloadCondition: UserPreloadAttributes, + T2Field: "UserReference", } } + +var UserPreloadCreditCard = UserCreditCard(CreditCardPreloadAttributes) +var UserPreloadAttributes = orm.NewPreloadCondition[overrideforeignkeyinverse.User]() +var UserPreloadRelations = []orm.Condition[overrideforeignkeyinverse.User]{UserPreloadCreditCard} diff --git a/cli/cmd/gen/conditions/tests/results/overridereferences_brand.go b/cli/cmd/gen/conditions/tests/results/overridereferences_brand.go new file mode 100644 index 0000000..e649069 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/results/overridereferences_brand.go @@ -0,0 +1,44 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + overridereferences "github.com/ditrit/badaas-orm/cli/cmd/gen/conditions/tests/overridereferences" + orm "github.com/ditrit/badaas/orm" + "time" +) + +func BrandId(operator orm.Operator[orm.UUID]) orm.WhereCondition[overridereferences.Brand] { + return orm.FieldCondition[overridereferences.Brand, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func BrandCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferences.Brand] { + return orm.FieldCondition[overridereferences.Brand, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func BrandUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferences.Brand] { + return orm.FieldCondition[overridereferences.Brand, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func BrandDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferences.Brand] { + return orm.FieldCondition[overridereferences.Brand, time.Time]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} + +var brandNameFieldID = orm.FieldIdentifier{Field: "Name"} + +func BrandName(operator orm.Operator[string]) orm.WhereCondition[overridereferences.Brand] { + return orm.FieldCondition[overridereferences.Brand, string]{ + FieldIdentifier: brandNameFieldID, + Operator: operator, + } +} + +var BrandPreloadAttributes = orm.NewPreloadCondition[overridereferences.Brand](brandNameFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/overridereferences.go b/cli/cmd/gen/conditions/tests/results/overridereferences_phone.go similarity index 57% rename from cli/cmd/gen/conditions/tests/results/overridereferences.go rename to cli/cmd/gen/conditions/tests/results/overridereferences_phone.go index 5398d5d..3bb3df6 100644 --- a/cli/cmd/gen/conditions/tests/results/overridereferences.go +++ b/cli/cmd/gen/conditions/tests/results/overridereferences_phone.go @@ -9,38 +9,47 @@ import ( func PhoneId(operator orm.Operator[orm.UUID]) orm.WhereCondition[overridereferences.Phone] { return orm.FieldCondition[overridereferences.Phone, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func PhoneCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferences.Phone] { return orm.FieldCondition[overridereferences.Phone, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func PhoneUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferences.Phone] { return orm.FieldCondition[overridereferences.Phone, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func PhoneDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferences.Phone] { return orm.FieldCondition[overridereferences.Phone, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } -func PhoneBrand(conditions ...orm.Condition[overridereferences.Brand]) orm.Condition[overridereferences.Phone] { +func PhoneBrand(conditions ...orm.Condition[overridereferences.Brand]) orm.IJoinCondition[overridereferences.Phone] { return orm.JoinCondition[overridereferences.Phone, overridereferences.Brand]{ - Conditions: conditions, - T1Field: "BrandName", - T2Field: "Name", + Conditions: conditions, + RelationField: "Brand", + T1Field: "BrandName", + T1PreloadCondition: PhonePreloadAttributes, + T2Field: "Name", } } + +var PhonePreloadBrand = PhoneBrand(BrandPreloadAttributes) +var phoneBrandNameFieldID = orm.FieldIdentifier{Field: "BrandName"} + func PhoneBrandName(operator orm.Operator[string]) orm.WhereCondition[overridereferences.Phone] { return orm.FieldCondition[overridereferences.Phone, string]{ - Field: "BrandName", - Operator: operator, + FieldIdentifier: phoneBrandNameFieldID, + Operator: operator, } } + +var PhonePreloadAttributes = orm.NewPreloadCondition[overridereferences.Phone](phoneBrandNameFieldID) +var PhonePreloadRelations = []orm.Condition[overridereferences.Phone]{PhonePreloadBrand} diff --git a/cli/cmd/gen/conditions/tests/results/overridereferencesinverse.go b/cli/cmd/gen/conditions/tests/results/overridereferencesinverse_computer.go similarity index 58% rename from cli/cmd/gen/conditions/tests/results/overridereferencesinverse.go rename to cli/cmd/gen/conditions/tests/results/overridereferencesinverse_computer.go index 7a94b49..68f9d10 100644 --- a/cli/cmd/gen/conditions/tests/results/overridereferencesinverse.go +++ b/cli/cmd/gen/conditions/tests/results/overridereferencesinverse_computer.go @@ -9,45 +9,47 @@ import ( func ComputerId(operator orm.Operator[orm.UUID]) orm.WhereCondition[overridereferencesinverse.Computer] { return orm.FieldCondition[overridereferencesinverse.Computer, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func ComputerCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferencesinverse.Computer] { return orm.FieldCondition[overridereferencesinverse.Computer, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func ComputerUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferencesinverse.Computer] { return orm.FieldCondition[overridereferencesinverse.Computer, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func ComputerDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferencesinverse.Computer] { return orm.FieldCondition[overridereferencesinverse.Computer, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var computerNameFieldID = orm.FieldIdentifier{Field: "Name"} + func ComputerName(operator orm.Operator[string]) orm.WhereCondition[overridereferencesinverse.Computer] { return orm.FieldCondition[overridereferencesinverse.Computer, string]{ - Field: "Name", - Operator: operator, + FieldIdentifier: computerNameFieldID, + Operator: operator, } } -func ComputerProcessor(conditions ...orm.Condition[overridereferencesinverse.Processor]) orm.Condition[overridereferencesinverse.Computer] { +func ComputerProcessor(conditions ...orm.Condition[overridereferencesinverse.Processor]) orm.IJoinCondition[overridereferencesinverse.Computer] { return orm.JoinCondition[overridereferencesinverse.Computer, overridereferencesinverse.Processor]{ - Conditions: conditions, - T1Field: "Name", - T2Field: "ComputerName", - } -} -func ProcessorComputer(conditions ...orm.Condition[overridereferencesinverse.Computer]) orm.Condition[overridereferencesinverse.Processor] { - return orm.JoinCondition[overridereferencesinverse.Processor, overridereferencesinverse.Computer]{ - Conditions: conditions, - T1Field: "ComputerName", - T2Field: "Name", + Conditions: conditions, + RelationField: "Processor", + T1Field: "Name", + T1PreloadCondition: ComputerPreloadAttributes, + T2Field: "ComputerName", } } + +var ComputerPreloadProcessor = ComputerProcessor(ProcessorPreloadAttributes) +var ComputerPreloadAttributes = orm.NewPreloadCondition[overridereferencesinverse.Computer](computerNameFieldID) +var ComputerPreloadRelations = []orm.Condition[overridereferencesinverse.Computer]{ComputerPreloadProcessor} diff --git a/cli/cmd/gen/conditions/tests/results/overridereferencesinverse_processor.go b/cli/cmd/gen/conditions/tests/results/overridereferencesinverse_processor.go new file mode 100644 index 0000000..75b3bd0 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/results/overridereferencesinverse_processor.go @@ -0,0 +1,44 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + overridereferencesinverse "github.com/ditrit/badaas-orm/cli/cmd/gen/conditions/tests/overridereferencesinverse" + orm "github.com/ditrit/badaas/orm" + "time" +) + +func ProcessorId(operator orm.Operator[orm.UUID]) orm.WhereCondition[overridereferencesinverse.Processor] { + return orm.FieldCondition[overridereferencesinverse.Processor, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func ProcessorCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferencesinverse.Processor] { + return orm.FieldCondition[overridereferencesinverse.Processor, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func ProcessorUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferencesinverse.Processor] { + return orm.FieldCondition[overridereferencesinverse.Processor, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func ProcessorDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[overridereferencesinverse.Processor] { + return orm.FieldCondition[overridereferencesinverse.Processor, time.Time]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} + +var processorComputerNameFieldID = orm.FieldIdentifier{Field: "ComputerName"} + +func ProcessorComputerName(operator orm.Operator[string]) orm.WhereCondition[overridereferencesinverse.Processor] { + return orm.FieldCondition[overridereferencesinverse.Processor, string]{ + FieldIdentifier: processorComputerNameFieldID, + Operator: operator, + } +} + +var ProcessorPreloadAttributes = orm.NewPreloadCondition[overridereferencesinverse.Processor](processorComputerNameFieldID) diff --git a/cli/cmd/gen/conditions/tests/results/selfreferential.go b/cli/cmd/gen/conditions/tests/results/selfreferential.go index 2ad8e18..485744c 100644 --- a/cli/cmd/gen/conditions/tests/results/selfreferential.go +++ b/cli/cmd/gen/conditions/tests/results/selfreferential.go @@ -9,38 +9,47 @@ import ( func EmployeeId(operator orm.Operator[orm.UUID]) orm.WhereCondition[selfreferential.Employee] { return orm.FieldCondition[selfreferential.Employee, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func EmployeeCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[selfreferential.Employee] { return orm.FieldCondition[selfreferential.Employee, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func EmployeeUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[selfreferential.Employee] { return orm.FieldCondition[selfreferential.Employee, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func EmployeeDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[selfreferential.Employee] { return orm.FieldCondition[selfreferential.Employee, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } -func EmployeeBoss(conditions ...orm.Condition[selfreferential.Employee]) orm.Condition[selfreferential.Employee] { +func EmployeeBoss(conditions ...orm.Condition[selfreferential.Employee]) orm.IJoinCondition[selfreferential.Employee] { return orm.JoinCondition[selfreferential.Employee, selfreferential.Employee]{ - Conditions: conditions, - T1Field: "BossID", - T2Field: "ID", + Conditions: conditions, + RelationField: "Boss", + T1Field: "BossID", + T1PreloadCondition: EmployeePreloadAttributes, + T2Field: "ID", } } + +var EmployeePreloadBoss = EmployeeBoss(EmployeePreloadAttributes) +var employeeBossIdFieldID = orm.FieldIdentifier{Field: "BossID"} + func EmployeeBossId(operator orm.Operator[orm.UUID]) orm.WhereCondition[selfreferential.Employee] { return orm.FieldCondition[selfreferential.Employee, orm.UUID]{ - Field: "BossID", - Operator: operator, + FieldIdentifier: employeeBossIdFieldID, + Operator: operator, } } + +var EmployeePreloadAttributes = orm.NewPreloadCondition[selfreferential.Employee](employeeBossIdFieldID) +var EmployeePreloadRelations = []orm.Condition[selfreferential.Employee]{EmployeePreloadBoss} diff --git a/cli/cmd/gen/conditions/tests/results/uintmodel.go b/cli/cmd/gen/conditions/tests/results/uintmodel.go index 109c4e2..c770fd6 100644 --- a/cli/cmd/gen/conditions/tests/results/uintmodel.go +++ b/cli/cmd/gen/conditions/tests/results/uintmodel.go @@ -7,27 +7,29 @@ import ( "time" ) -func UintModelId(operator orm.Operator[uint]) orm.WhereCondition[uintmodel.UintModel] { - return orm.FieldCondition[uintmodel.UintModel, uint]{ - Field: "ID", - Operator: operator, +func UintModelId(operator orm.Operator[orm.UIntID]) orm.WhereCondition[uintmodel.UintModel] { + return orm.FieldCondition[uintmodel.UintModel, orm.UIntID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func UintModelCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[uintmodel.UintModel] { return orm.FieldCondition[uintmodel.UintModel, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func UintModelUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[uintmodel.UintModel] { return orm.FieldCondition[uintmodel.UintModel, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func UintModelDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[uintmodel.UintModel] { return orm.FieldCondition[uintmodel.UintModel, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var UintModelPreloadAttributes = orm.NewPreloadCondition[uintmodel.UintModel]() diff --git a/cli/cmd/gen/conditions/tests/results/uuidmodel.go b/cli/cmd/gen/conditions/tests/results/uuidmodel.go index a3c8699..fb64ac8 100644 --- a/cli/cmd/gen/conditions/tests/results/uuidmodel.go +++ b/cli/cmd/gen/conditions/tests/results/uuidmodel.go @@ -9,25 +9,27 @@ import ( func UUIDModelId(operator orm.Operator[orm.UUID]) orm.WhereCondition[uuidmodel.UUIDModel] { return orm.FieldCondition[uuidmodel.UUIDModel, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func UUIDModelCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[uuidmodel.UUIDModel] { return orm.FieldCondition[uuidmodel.UUIDModel, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func UUIDModelUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[uuidmodel.UUIDModel] { return orm.FieldCondition[uuidmodel.UUIDModel, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func UUIDModelDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[uuidmodel.UUIDModel] { return orm.FieldCondition[uuidmodel.UUIDModel, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var UUIDModelPreloadAttributes = orm.NewPreloadCondition[uuidmodel.UUIDModel]() diff --git a/cli/cmd/gen/conditions/tests/selfreferential/badaas-orm_result.go b/cli/cmd/gen/conditions/tests/selfreferential/badaas-orm_result.go new file mode 100644 index 0000000..a377a92 --- /dev/null +++ b/cli/cmd/gen/conditions/tests/selfreferential/badaas-orm_result.go @@ -0,0 +1,8 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package selfreferential + +import orm "github.com/ditrit/badaas/orm" + +func (m Employee) GetBoss() (*Employee, error) { + return orm.VerifyPointerLoaded[Employee](m.BossID, m.Boss) +} diff --git a/cli/cmd/gen/conditions/type.go b/cli/cmd/gen/conditions/type.go index 22a576c..36c1c10 100644 --- a/cli/cmd/gen/conditions/type.go +++ b/cli/cmd/gen/conditions/type.go @@ -1,17 +1,23 @@ package conditions import ( + "errors" "fmt" "go/types" "regexp" "strings" "github.com/elliotchance/pie/v2" + + "github.com/ditrit/badaas-orm/cli/cmd/utils" ) var ( // badaas/orm/baseModels.go - badaasORMBaseModels = []string{"github.com/ditrit/badaas/orm.UUIDModel", "github.com/ditrit/badaas/orm.UIntModel", "gorm.io/gorm.Model"} + badaasORMBaseModels = []string{ + badaasORMPath + "." + uuidModel, + badaasORMPath + "." + uIntModel, + } // database/sql nullString = "database/sql.NullString" @@ -29,6 +35,8 @@ var ( } ) +var ErrFkNotInTypeFields = errors.New("fk not in type's fields") + type Type struct { types.Type } @@ -69,7 +77,7 @@ func isBadaasModel(structType *types.Struct) bool { for i := 0; i < structType.NumFields(); i++ { field := structType.Field(i) - if field.Embedded() && pie.Contains(badaasORMBaseModels, field.Type().String()) { + if field.Embedded() && isBaseModel(field.Type().String()) { return true } } @@ -77,16 +85,27 @@ func isBadaasModel(structType *types.Struct) bool { return false } -// Returns true is the type has a foreign key to the field's object +func isBaseModel(fieldName string) bool { + return pie.Contains(badaasORMBaseModels, fieldName) +} + +// Returns the fk field of the type to the "field"'s object // (another field that references that object) -func (t Type) HasFK(field Field) (bool, error) { - objectFields, err := getFields(t, "") +func (t Type) GetFK(field Field) (*Field, error) { + objectFields, err := getFields(t) if err != nil { - return false, err + return nil, err } - return pie.Any(objectFields, func(otherField Field) bool { - return otherField.Name == field.getFKAttribute() - }), nil + + fk := utils.FindFirst(objectFields, func(otherField Field) bool { + return strings.EqualFold(otherField.Name, field.getFKAttribute()) + }) + + if fk == nil { + return nil, ErrFkNotInTypeFields + } + + return fk, nil } var ( diff --git a/cli/cmd/gen/docker_test.go b/cli/cmd/gen/docker_test.go index 0118add..1488de6 100644 --- a/cli/cmd/gen/docker_test.go +++ b/cli/cmd/gen/docker_test.go @@ -5,8 +5,9 @@ import ( "path/filepath" "testing" - "github.com/ditrit/badaas-orm/cli/cmd/utils" "github.com/stretchr/testify/assert" + + "github.com/ditrit/badaas-orm/cli/cmd/testutils" ) func TestGenerateDockerFilesCreateFilesWhenDestinationFolderNotExists(t *testing.T) { @@ -159,21 +160,21 @@ func assertPanic(t *testing.T, functionShouldPanic func(), errorMessage string) } func checkFilesExist(t *testing.T) { - utils.CheckFileExists(t, ".dockerignore") - utils.CheckFileExists(t, "Makefile") - utils.CheckFileExists(t, filepath.Join("badaas", "config", "badaas.yml")) - utils.CheckFileExists(t, filepath.Join("badaas", "docker", "api", "docker-compose.yml")) - utils.CheckFileExists(t, filepath.Join("badaas", "docker", "api", "Dockerfile")) + testutils.CheckFileExists(t, ".dockerignore") + testutils.CheckFileExists(t, "Makefile") + testutils.CheckFileExists(t, filepath.Join("badaas", "config", "badaas.yml")) + testutils.CheckFileExists(t, filepath.Join("badaas", "docker", "api", "docker-compose.yml")) + testutils.CheckFileExists(t, filepath.Join("badaas", "docker", "api", "Dockerfile")) checkDockerDBFilesExist(t) } func checkDockerDBFilesExist(t *testing.T) { - utils.CheckFileExists(t, filepath.Join("badaas", "docker", "db", "docker-compose.yml")) + testutils.CheckFileExists(t, filepath.Join("badaas", "docker", "db", "docker-compose.yml")) } func teardown() { - utils.RemoveFile(".dockerignore") - utils.RemoveFile("Makefile") - utils.RemoveFile("file.txt") - utils.RemoveFile("badaas") + testutils.RemoveFile(".dockerignore") + testutils.RemoveFile("Makefile") + testutils.RemoveFile("file.txt") + testutils.RemoveFile("badaas") } diff --git a/cli/cmd/testutils/file.go b/cli/cmd/testutils/file.go new file mode 100644 index 0000000..f7c153a --- /dev/null +++ b/cli/cmd/testutils/file.go @@ -0,0 +1,31 @@ +package testutils + +import ( + "io/fs" + "log" + "os" + "testing" +) + +func CheckFileNotExists(t *testing.T, name string) { + _, err := os.Stat(name) + if err == nil { + t.Error(err, "Should have been an error") + } +} + +func CheckFileExists(t *testing.T, name string) fs.FileInfo { + stat, err := os.Stat(name) + if err != nil { + t.Error(err) + } + + return stat +} + +func RemoveFile(name string) { + err := os.RemoveAll(name) + if err != nil { + log.Fatal(err) + } +} diff --git a/cli/cmd/utils/slice.go b/cli/cmd/utils/slice.go new file mode 100644 index 0000000..2b37095 --- /dev/null +++ b/cli/cmd/utils/slice.go @@ -0,0 +1,15 @@ +package utils + +import ( + "github.com/elliotchance/pie/v2" +) + +func FindFirst[T any](ss []T, fn func(value T) bool) *T { + index := pie.FindFirstUsing(ss, fn) + + if index == -1 { + return nil + } + + return &ss[index] +} diff --git a/cli/cmd/utils/slice_test.go b/cli/cmd/utils/slice_test.go new file mode 100644 index 0000000..d39551b --- /dev/null +++ b/cli/cmd/utils/slice_test.go @@ -0,0 +1,59 @@ +package utils_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ditrit/badaas-orm/cli/cmd/utils" +) + +var ( + testResult3 = 33.04 + testResult4 = 0.11 +) + +var findFirstTests = []struct { + ss []float64 + expression func(value float64) bool + expected *float64 +}{ + { + nil, + func(value float64) bool { return value == 1.5 }, + nil, + }, + { + []float64{}, + func(value float64) bool { return value == 0.1 }, + nil, + }, + { + []float64{0.0, 1.5, 3.2}, + func(value float64) bool { return value == 9.99 }, + nil, + }, + { + []float64{5.4, 6.98, 4.987, 33.04}, + func(value float64) bool { return value == 33.04 }, + &testResult3, + }, + { + []float64{9.0, 0.11, 150.44, 33.04}, + func(value float64) bool { return value == 0.11 }, + &testResult4, + }, +} + +func TestFindFirst(t *testing.T) { + for _, test := range findFirstTests { + t.Run("", func(t *testing.T) { + result := utils.FindFirst(test.ss, test.expression) + if result == nil { + assert.Nil(t, test.expected) + } else { + assert.Equal(t, *test.expected, *result) + } + }) + } +} diff --git a/cli/go.mod b/cli/go.mod index 5fd94a1..beeae97 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/dave/jennifer v1.6.1 - github.com/ditrit/badaas v0.0.0-20230802090641-cb55dbcce177 + github.com/ditrit/badaas v0.0.0-20230807114103-72cff2a37890 github.com/ditrit/verdeter v0.4.0 github.com/elliotchance/pie/v2 v2.7.0 github.com/ettle/strcase v0.1.1 @@ -14,7 +14,6 @@ require ( github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 golang.org/x/tools v0.11.1 - gorm.io/gorm v1.25.1 gotest.tools v2.2.0+incompatible ) @@ -54,4 +53,5 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/postgres v1.5.2 // indirect + gorm.io/gorm v1.25.1 // indirect ) diff --git a/cli/go.sum b/cli/go.sum index aec99dd..ef2d92d 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -53,8 +53,8 @@ github.com/dave/jennifer v1.6.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/ditrit/badaas v0.0.0-20230802090641-cb55dbcce177 h1:0PIcEg9WlEq8t8TNPTF7GFWU8ZRt77t8JK1Ecm95lfc= -github.com/ditrit/badaas v0.0.0-20230802090641-cb55dbcce177/go.mod h1:FS3I+obfV7FiYp3tUbZObckOclqmEPtGwTXsGOk8WJs= +github.com/ditrit/badaas v0.0.0-20230807114103-72cff2a37890 h1:Y4oG6q2kJI/G0m+bCPuwv/mrKYhtJP4cqYHsuFsAn0M= +github.com/ditrit/badaas v0.0.0-20230807114103-72cff2a37890/go.mod h1:FS3I+obfV7FiYp3tUbZObckOclqmEPtGwTXsGOk8WJs= github.com/ditrit/verdeter v0.4.0 h1:DzEOFauuXEGNQYP6OgYtHwEyb3w9riem99u0xE/l7+o= github.com/ditrit/verdeter v0.4.0/go.mod h1:sKpWuOvYqNabLN4aNXqeBhcWpt7nf0frwqk0B5M6ax0= github.com/elliotchance/pie/v2 v2.7.0 h1:FqoIKg4uj0G/CrLGuMS9ejnFKa92lxE1dEgBD3pShXg= diff --git a/mocks/configuration/Holder.go b/mocks/configuration/Holder.go new file mode 100644 index 0000000..4dfc618 --- /dev/null +++ b/mocks/configuration/Holder.go @@ -0,0 +1,38 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + zap "go.uber.org/zap" +) + +// Holder is an autogenerated mock type for the Holder type +type Holder struct { + mock.Mock +} + +// Log provides a mock function with given fields: logger +func (_m *Holder) Log(logger *zap.Logger) { + _m.Called(logger) +} + +// Reload provides a mock function with given fields: +func (_m *Holder) Reload() { + _m.Called() +} + +type mockConstructorTestingTNewHolder interface { + mock.TestingT + Cleanup(func()) +} + +// NewHolder creates a new instance of Holder. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewHolder(t mockConstructorTestingTNewHolder) *Holder { + mock := &Holder{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/orm/CRUDRepository.go b/mocks/orm/CRUDRepository.go index db93a68..d9894c1 100644 --- a/mocks/orm/CRUDRepository.go +++ b/mocks/orm/CRUDRepository.go @@ -9,7 +9,7 @@ import ( ) // CRUDRepository is an autogenerated mock type for the CRUDRepository type -type CRUDRepository[T interface{}, ID orm.BadaasID] struct { +type CRUDRepository[T orm.Model, ID orm.ModelID] struct { mock.Mock } @@ -153,7 +153,7 @@ type mockConstructorTestingTNewCRUDRepository interface { } // NewCRUDRepository creates a new instance of CRUDRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewCRUDRepository[T interface{}, ID orm.BadaasID](t mockConstructorTestingTNewCRUDRepository) *CRUDRepository[T, ID] { +func NewCRUDRepository[T orm.Model, ID orm.ModelID](t mockConstructorTestingTNewCRUDRepository) *CRUDRepository[T, ID] { mock := &CRUDRepository[T, ID]{} mock.Mock.Test(t) diff --git a/mocks/orm/CRUDService.go b/mocks/orm/CRUDService.go index 1a04733..21c4d59 100644 --- a/mocks/orm/CRUDService.go +++ b/mocks/orm/CRUDService.go @@ -8,7 +8,7 @@ import ( ) // CRUDService is an autogenerated mock type for the CRUDService type -type CRUDService[T interface{}, ID orm.BadaasID] struct { +type CRUDService[T orm.Model, ID orm.ModelID] struct { mock.Mock } @@ -108,7 +108,7 @@ type mockConstructorTestingTNewCRUDService interface { } // NewCRUDService creates a new instance of CRUDService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewCRUDService[T interface{}, ID orm.BadaasID](t mockConstructorTestingTNewCRUDService) *CRUDService[T, ID] { +func NewCRUDService[T orm.Model, ID orm.ModelID](t mockConstructorTestingTNewCRUDService) *CRUDService[T, ID] { mock := &CRUDService[T, ID]{} mock.Mock.Test(t) diff --git a/mocks/orm/Condition.go b/mocks/orm/Condition.go index 2d214a0..d977576 100644 --- a/mocks/orm/Condition.go +++ b/mocks/orm/Condition.go @@ -3,34 +3,35 @@ package mocks import ( + orm "github.com/ditrit/badaas/orm" mock "github.com/stretchr/testify/mock" gorm "gorm.io/gorm" ) // Condition is an autogenerated mock type for the Condition type -type Condition[T interface{}] struct { +type Condition[T orm.Model] struct { mock.Mock } -// ApplyTo provides a mock function with given fields: query, tableName -func (_m *Condition[T]) ApplyTo(query *gorm.DB, tableName string) (*gorm.DB, error) { - ret := _m.Called(query, tableName) +// ApplyTo provides a mock function with given fields: query, table +func (_m *Condition[T]) ApplyTo(query *gorm.DB, table orm.Table) (*gorm.DB, error) { + ret := _m.Called(query, table) var r0 *gorm.DB var r1 error - if rf, ok := ret.Get(0).(func(*gorm.DB, string) (*gorm.DB, error)); ok { - return rf(query, tableName) + if rf, ok := ret.Get(0).(func(*gorm.DB, orm.Table) (*gorm.DB, error)); ok { + return rf(query, table) } - if rf, ok := ret.Get(0).(func(*gorm.DB, string) *gorm.DB); ok { - r0 = rf(query, tableName) + if rf, ok := ret.Get(0).(func(*gorm.DB, orm.Table) *gorm.DB); ok { + r0 = rf(query, table) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*gorm.DB) } } - if rf, ok := ret.Get(1).(func(*gorm.DB, string) error); ok { - r1 = rf(query, tableName) + if rf, ok := ret.Get(1).(func(*gorm.DB, orm.Table) error); ok { + r1 = rf(query, table) } else { r1 = ret.Error(1) } @@ -49,7 +50,7 @@ type mockConstructorTestingTNewCondition interface { } // NewCondition creates a new instance of Condition. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewCondition[T interface{}](t mockConstructorTestingTNewCondition) *Condition[T] { +func NewCondition[T orm.Model](t mockConstructorTestingTNewCondition) *Condition[T] { mock := &Condition[T]{} mock.Mock.Test(t) diff --git a/mocks/orm/IJoinCondition.go b/mocks/orm/IJoinCondition.go new file mode 100644 index 0000000..c1c4411 --- /dev/null +++ b/mocks/orm/IJoinCondition.go @@ -0,0 +1,88 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package mocks + +import ( + orm "github.com/ditrit/badaas/orm" + mock "github.com/stretchr/testify/mock" + gorm "gorm.io/gorm" +) + +// IJoinCondition is an autogenerated mock type for the IJoinCondition type +type IJoinCondition[T orm.Model] struct { + mock.Mock +} + +// ApplyTo provides a mock function with given fields: query, table +func (_m *IJoinCondition[T]) ApplyTo(query *gorm.DB, table orm.Table) (*gorm.DB, error) { + ret := _m.Called(query, table) + + var r0 *gorm.DB + var r1 error + if rf, ok := ret.Get(0).(func(*gorm.DB, orm.Table) (*gorm.DB, error)); ok { + return rf(query, table) + } + if rf, ok := ret.Get(0).(func(*gorm.DB, orm.Table) *gorm.DB); ok { + r0 = rf(query, table) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gorm.DB) + } + } + + if rf, ok := ret.Get(1).(func(*gorm.DB, orm.Table) error); ok { + r1 = rf(query, table) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// interfaceVerificationMethod provides a mock function with given fields: _a0 +func (_m *IJoinCondition[T]) interfaceVerificationMethod(_a0 T) { + _m.Called(_a0) +} + +// makesFilter provides a mock function with given fields: +func (_m *IJoinCondition[T]) makesFilter() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// makesPreload provides a mock function with given fields: +func (_m *IJoinCondition[T]) makesPreload() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +type mockConstructorTestingTNewIJoinCondition interface { + mock.TestingT + Cleanup(func()) +} + +// NewIJoinCondition creates a new instance of IJoinCondition. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewIJoinCondition[T orm.Model](t mockConstructorTestingTNewIJoinCondition) *IJoinCondition[T] { + mock := &IJoinCondition[T]{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/orm/Model.go b/mocks/orm/Model.go new file mode 100644 index 0000000..ca967b6 --- /dev/null +++ b/mocks/orm/Model.go @@ -0,0 +1,39 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Model is an autogenerated mock type for the Model type +type Model struct { + mock.Mock +} + +// IsLoaded provides a mock function with given fields: +func (_m *Model) IsLoaded() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +type mockConstructorTestingTNewModel interface { + mock.TestingT + Cleanup(func()) +} + +// NewModel creates a new instance of Model. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewModel(t mockConstructorTestingTNewModel) *Model { + mock := &Model{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/orm/ModelID.go b/mocks/orm/ModelID.go new file mode 100644 index 0000000..dfaee03 --- /dev/null +++ b/mocks/orm/ModelID.go @@ -0,0 +1,39 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// ModelID is an autogenerated mock type for the ModelID type +type ModelID struct { + mock.Mock +} + +// IsNil provides a mock function with given fields: +func (_m *ModelID) IsNil() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +type mockConstructorTestingTNewModelID interface { + mock.TestingT + Cleanup(func()) +} + +// NewModelID creates a new instance of ModelID. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewModelID(t mockConstructorTestingTNewModelID) *ModelID { + mock := &ModelID{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/orm/WhereCondition.go b/mocks/orm/WhereCondition.go index 725d3ef..94eb084 100644 --- a/mocks/orm/WhereCondition.go +++ b/mocks/orm/WhereCondition.go @@ -3,34 +3,35 @@ package mocks import ( + orm "github.com/ditrit/badaas/orm" mock "github.com/stretchr/testify/mock" gorm "gorm.io/gorm" ) // WhereCondition is an autogenerated mock type for the WhereCondition type -type WhereCondition[T interface{}] struct { +type WhereCondition[T orm.Model] struct { mock.Mock } -// ApplyTo provides a mock function with given fields: query, tableName -func (_m *WhereCondition[T]) ApplyTo(query *gorm.DB, tableName string) (*gorm.DB, error) { - ret := _m.Called(query, tableName) +// ApplyTo provides a mock function with given fields: query, table +func (_m *WhereCondition[T]) ApplyTo(query *gorm.DB, table orm.Table) (*gorm.DB, error) { + ret := _m.Called(query, table) var r0 *gorm.DB var r1 error - if rf, ok := ret.Get(0).(func(*gorm.DB, string) (*gorm.DB, error)); ok { - return rf(query, tableName) + if rf, ok := ret.Get(0).(func(*gorm.DB, orm.Table) (*gorm.DB, error)); ok { + return rf(query, table) } - if rf, ok := ret.Get(0).(func(*gorm.DB, string) *gorm.DB); ok { - r0 = rf(query, tableName) + if rf, ok := ret.Get(0).(func(*gorm.DB, orm.Table) *gorm.DB); ok { + r0 = rf(query, table) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*gorm.DB) } } - if rf, ok := ret.Get(1).(func(*gorm.DB, string) error); ok { - r1 = rf(query, tableName) + if rf, ok := ret.Get(1).(func(*gorm.DB, orm.Table) error); ok { + r1 = rf(query, table) } else { r1 = ret.Error(1) } @@ -38,32 +39,32 @@ func (_m *WhereCondition[T]) ApplyTo(query *gorm.DB, tableName string) (*gorm.DB return r0, r1 } -// GetSQL provides a mock function with given fields: query, tableName -func (_m *WhereCondition[T]) GetSQL(query *gorm.DB, tableName string) (string, []interface{}, error) { - ret := _m.Called(query, tableName) +// GetSQL provides a mock function with given fields: query, table +func (_m *WhereCondition[T]) GetSQL(query *gorm.DB, table orm.Table) (string, []interface{}, error) { + ret := _m.Called(query, table) var r0 string var r1 []interface{} var r2 error - if rf, ok := ret.Get(0).(func(*gorm.DB, string) (string, []interface{}, error)); ok { - return rf(query, tableName) + if rf, ok := ret.Get(0).(func(*gorm.DB, orm.Table) (string, []interface{}, error)); ok { + return rf(query, table) } - if rf, ok := ret.Get(0).(func(*gorm.DB, string) string); ok { - r0 = rf(query, tableName) + if rf, ok := ret.Get(0).(func(*gorm.DB, orm.Table) string); ok { + r0 = rf(query, table) } else { r0 = ret.Get(0).(string) } - if rf, ok := ret.Get(1).(func(*gorm.DB, string) []interface{}); ok { - r1 = rf(query, tableName) + if rf, ok := ret.Get(1).(func(*gorm.DB, orm.Table) []interface{}); ok { + r1 = rf(query, table) } else { if ret.Get(1) != nil { r1 = ret.Get(1).([]interface{}) } } - if rf, ok := ret.Get(2).(func(*gorm.DB, string) error); ok { - r2 = rf(query, tableName) + if rf, ok := ret.Get(2).(func(*gorm.DB, orm.Table) error); ok { + r2 = rf(query, table) } else { r2 = ret.Error(2) } @@ -96,7 +97,7 @@ type mockConstructorTestingTNewWhereCondition interface { } // NewWhereCondition creates a new instance of WhereCondition. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewWhereCondition[T interface{}](t mockConstructorTestingTNewWhereCondition) *WhereCondition[T] { +func NewWhereCondition[T orm.Model](t mockConstructorTestingTNewWhereCondition) *WhereCondition[T] { mock := &WhereCondition[T]{} mock.Mock.Test(t) diff --git a/orm/ModuleFx.go b/orm/ModuleFx.go index a55b9bf..fe1cf33 100644 --- a/orm/ModuleFx.go +++ b/orm/ModuleFx.go @@ -24,7 +24,7 @@ var AutoMigrate = fx.Module( ), ) -func GetCRUDServiceModule[T any]() fx.Option { +func GetCRUDServiceModule[T Model]() fx.Option { entity := *new(T) moduleName := fmt.Sprintf( @@ -46,9 +46,9 @@ func GetCRUDServiceModule[T any]() fx.Option { return fx.Module( moduleName, // repository - fx.Provide(NewCRUDRepository[T, uint]), + fx.Provide(NewCRUDRepository[T, UIntID]), // service - fx.Provide(NewCRUDService[T, uint]), + fx.Provide(NewCRUDService[T, UIntID]), ) default: log.Printf("type %T is not a BaDaaS model\n", entity) @@ -68,7 +68,7 @@ const ( KindNotModel ) -func getModelKind(entity any) modelKind { +func getModelKind(entity Model) modelKind { entityType := getEntityType(entity) _, isUUIDModel := entityType.FieldByName("UUIDModel") diff --git a/orm/README.md b/orm/README.md index 8f18d44..240a0cf 100644 --- a/orm/README.md +++ b/orm/README.md @@ -44,4 +44,4 @@ The difference between them is the type they will use as primary key: a random u - `crudCompanyService orm.CRUDService[models.Company, orm.UUID]` - `crudCompanyRepository orm.CRUDRepository[models.Company, orm.UUID]` -These classes will allow you to perform queries using the compilable query system generated with badaas-cli. For details on how to do this visit [badaas-cli docs](github.com/ditrit/badaas-orm/cli/README.md). +These classes will allow you to perform queries using the compilable query system generated with badaas-cli. For details on how to do this visit [badaas-cli docs](github.com/ditrit/badaas-cli/README.md). diff --git a/orm/baseModels.go b/orm/baseModels.go index 3a0b481..c6349ae 100644 --- a/orm/baseModels.go +++ b/orm/baseModels.go @@ -3,14 +3,18 @@ package orm import ( "time" - "github.com/google/uuid" - "gorm.io/gorm" ) // supported types for model identifier -type BadaasID interface { - uint | UUID +type ModelID interface { + UIntID | UUID + + IsNil() bool +} + +type Model interface { + IsLoaded() bool } // Base Model for gorm @@ -24,11 +28,32 @@ type UUIDModel struct { DeletedAt gorm.DeletedAt `gorm:"index"` } -func (model *UUIDModel) BeforeCreate(tx *gorm.DB) (err error) { - if model.ID == UUID(uuid.Nil) { - model.ID = UUID(uuid.New()) +func (model UUIDModel) IsLoaded() bool { + return !model.ID.IsNil() +} + +func (model *UUIDModel) BeforeCreate(_ *gorm.DB) (err error) { + if model.ID == NilUUID { + model.ID = NewUUID() } return nil } -type UIntModel gorm.Model +type UIntID uint + +const NilUIntID = 0 + +func (id UIntID) IsNil() bool { + return id == NilUIntID +} + +type UIntModel struct { + ID UIntID `gorm:"primarykey;not null"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` +} + +func (model UIntModel) IsLoaded() bool { + return !model.ID.IsNil() +} diff --git a/orm/condition.go b/orm/condition.go index bb67a77..e755fac 100644 --- a/orm/condition.go +++ b/orm/condition.go @@ -9,15 +9,58 @@ import ( "gorm.io/gorm" ) -const DeletedAtField = "DeletedAt" +const deletedAtField = "DeletedAt" -var ErrEmptyConditions = errors.New("condition must have at least one inner condition") +var ( + IDFieldID = FieldIdentifier{Field: "ID"} + CreatedAtFieldID = FieldIdentifier{Field: "CreatedAt"} + UpdatedAtFieldID = FieldIdentifier{Field: "UpdatedAt"} + DeletedAtFieldID = FieldIdentifier{Field: deletedAtField} +) + +var ( + ErrEmptyConditions = errors.New("condition must have at least one inner condition") + ErrOnlyPreloadsAllowed = errors.New("only conditions that do a preload are allowed") +) + +type Table struct { + Name string + Alias string + Initial bool +} + +// Returns true if the Table is the initial table in a query +func (table Table) IsInitial() bool { + return table.Initial +} + +// Returns the related Table corresponding to the model +func (table Table) DeliverTable(query *gorm.DB, model Model, relationName string) (Table, error) { + // get the name of the table for the model + tableName, err := getTableName(query, model) + if err != nil { + return Table{}, err + } + + // add a suffix to avoid tables with the same name when joining + // the same table more than once + tableAlias := relationName + if !table.IsInitial() { + tableAlias = table.Alias + "__" + relationName + } -type Condition[T any] interface { + return Table{ + Name: tableName, + Alias: tableAlias, + Initial: false, + }, nil +} + +type Condition[T Model] interface { // Applies the condition to the "query" // using the "tableName" as name for the table holding // the data for object of type T - ApplyTo(query *gorm.DB, tableName string) (*gorm.DB, error) + ApplyTo(query *gorm.DB, table Table) (*gorm.DB, error) // This method is necessary to get the compiler to verify // that an object is of type Condition[T], @@ -28,11 +71,11 @@ type Condition[T any] interface { // Conditions that can be used in a where clause // (or in a on of a join) -type WhereCondition[T any] interface { +type WhereCondition[T Model] interface { Condition[T] // Get the sql string and values to use in the query - GetSQL(query *gorm.DB, tableName string) (string, []any, error) + GetSQL(query *gorm.DB, table Table) (string, []any, error) // Returns true if the DeletedAt column if affected by the condition // If no condition affects the DeletedAt, the verification that it's null will be added automatically @@ -41,7 +84,7 @@ type WhereCondition[T any] interface { // Condition that contains a internal condition. // Example: NOT (internal condition) -type ContainerCondition[T any] struct { +type ContainerCondition[T Model] struct { ConnectionCondition WhereCondition[T] Prefix string } @@ -52,12 +95,12 @@ func (condition ContainerCondition[T]) interfaceVerificationMethod(_ T) { // that an object is of type Condition[T] } -func (condition ContainerCondition[T]) ApplyTo(query *gorm.DB, tableName string) (*gorm.DB, error) { - return applyWhereCondition[T](condition, query, tableName) +func (condition ContainerCondition[T]) ApplyTo(query *gorm.DB, table Table) (*gorm.DB, error) { + return applyWhereCondition[T](condition, query, table) } -func (condition ContainerCondition[T]) GetSQL(query *gorm.DB, tableName string) (string, []any, error) { - sqlString, values, err := condition.ConnectionCondition.GetSQL(query, tableName) +func (condition ContainerCondition[T]) GetSQL(query *gorm.DB, table Table) (string, []any, error) { + sqlString, values, err := condition.ConnectionCondition.GetSQL(query, table) if err != nil { return "", nil, err } @@ -74,7 +117,7 @@ func (condition ContainerCondition[T]) affectsDeletedAt() bool { // Condition that contains a internal condition. // Example: NOT (internal condition) -func NewContainerCondition[T any](prefix string, conditions ...WhereCondition[T]) WhereCondition[T] { +func NewContainerCondition[T Model](prefix string, conditions ...WhereCondition[T]) WhereCondition[T] { if len(conditions) == 0 { return NewInvalidCondition[T](ErrEmptyConditions) } @@ -87,7 +130,7 @@ func NewContainerCondition[T any](prefix string, conditions ...WhereCondition[T] // Condition that connects multiple conditions. // Example: condition1 AND condition2 -type ConnectionCondition[T any] struct { +type ConnectionCondition[T Model] struct { Connector string Conditions []WhereCondition[T] } @@ -98,16 +141,16 @@ func (condition ConnectionCondition[T]) interfaceVerificationMethod(_ T) { // that an object is of type Condition[T] } -func (condition ConnectionCondition[T]) ApplyTo(query *gorm.DB, tableName string) (*gorm.DB, error) { - return applyWhereCondition[T](condition, query, tableName) +func (condition ConnectionCondition[T]) ApplyTo(query *gorm.DB, table Table) (*gorm.DB, error) { + return applyWhereCondition[T](condition, query, table) } -func (condition ConnectionCondition[T]) GetSQL(query *gorm.DB, tableName string) (string, []any, error) { +func (condition ConnectionCondition[T]) GetSQL(query *gorm.DB, table Table) (string, []any, error) { sqlStrings := []string{} values := []any{} for _, internalCondition := range condition.Conditions { - internalSQLString, internalValues, err := internalCondition.GetSQL(query, tableName) + internalSQLString, internalValues, err := internalCondition.GetSQL(query, table) if err != nil { return "", nil, err } @@ -129,20 +172,128 @@ func (condition ConnectionCondition[T]) affectsDeletedAt() bool { // Condition that connects multiple conditions. // Example: condition1 AND condition2 -func NewConnectionCondition[T any](connector string, conditions ...WhereCondition[T]) WhereCondition[T] { +func NewConnectionCondition[T Model](connector string, conditions ...WhereCondition[T]) WhereCondition[T] { return ConnectionCondition[T]{ Connector: connector, Conditions: conditions, } } -// Condition that verifies the value of a field, -// using the Operator -type FieldCondition[TObject any, TAtribute any] struct { - Field string +type FieldIdentifier struct { Column string + Field string ColumnPrefix string - Operator Operator[TAtribute] +} + +func (columnID FieldIdentifier) ColumnName(db *gorm.DB, table Table) string { + columnName := columnID.Column + if columnName == "" { + columnName = db.NamingStrategy.ColumnName(table.Name, columnID.Field) + } + + // add column prefix and table name once we know the column name + return columnID.ColumnPrefix + columnName +} + +// Condition used to the preload the attributes of a model +type PreloadCondition[T Model] struct { + Fields []FieldIdentifier +} + +//nolint:unused // see inside +func (condition PreloadCondition[T]) interfaceVerificationMethod(_ T) { + // This method is necessary to get the compiler to verify + // that an object is of type Condition[T] +} + +func (condition PreloadCondition[T]) ApplyTo(query *gorm.DB, table Table) (*gorm.DB, error) { + for _, fieldID := range condition.Fields { + columnName := fieldID.ColumnName(query, table) + + query.Statement.Selects = append( + query.Statement.Selects, + fmt.Sprintf( + "%[1]s.%[2]s AS \"%[1]s__%[2]s\"", // name used by gorm to load the fields inside the models + table.Alias, + columnName, + ), + ) + } + + return query, nil +} + +// Condition used to the preload the attributes of a model +func NewPreloadCondition[T Model](fields ...FieldIdentifier) PreloadCondition[T] { + return PreloadCondition[T]{ + Fields: append( + fields, + // base model fields + IDFieldID, + CreatedAtFieldID, + UpdatedAtFieldID, + DeletedAtFieldID, + ), + } +} + +// Condition used to the preload a collection of models of a model +type CollectionPreloadCondition[T1 Model, T2 Model] struct { + CollectionField string + NestedPreloads []IJoinCondition[T2] +} + +//nolint:unused // see inside +func (condition CollectionPreloadCondition[T1, T2]) interfaceVerificationMethod(_ T1) { + // This method is necessary to get the compiler to verify + // that an object is of type Condition[T1] +} + +func (condition CollectionPreloadCondition[T1, T2]) ApplyTo(query *gorm.DB, _ Table) (*gorm.DB, error) { + if len(condition.NestedPreloads) == 0 { + return query.Preload(condition.CollectionField), nil + } + + return query.Preload( + condition.CollectionField, + func(db *gorm.DB) *gorm.DB { + preloadsAsCondition := pie.Map( + condition.NestedPreloads, + func(joinCondition IJoinCondition[T2]) Condition[T2] { + return joinCondition + }, + ) + + query, err := applyConditionsToQuery[T2](db, preloadsAsCondition) + if err != nil { + _ = db.AddError(err) + return db + } + + return query + }, + ), nil +} + +// Condition used to the preload a collection of models of a model +func NewCollectionPreloadCondition[T1 Model, T2 Model](collectionField string, nestedPreloads []IJoinCondition[T2]) Condition[T1] { + if pie.Any(nestedPreloads, func(nestedPreload IJoinCondition[T2]) bool { + return !nestedPreload.makesPreload() || nestedPreload.makesFilter() + }) { + return NewInvalidCondition[T1](ErrOnlyPreloadsAllowed) + } + + return CollectionPreloadCondition[T1, T2]{ + CollectionField: collectionField, + NestedPreloads: nestedPreloads, + } +} + +// Condition that verifies the value of a field, +// using the Operator +type FieldCondition[TObject Model, TAtribute any] struct { + FieldIdentifier FieldIdentifier + Operator Operator[TAtribute] } //nolint:unused // see inside @@ -153,12 +304,12 @@ func (condition FieldCondition[TObject, TAtribute]) interfaceVerificationMethod( // Returns a gorm Where condition that can be used // to filter that the Field as a value of Value -func (condition FieldCondition[TObject, TAtribute]) ApplyTo(query *gorm.DB, tableName string) (*gorm.DB, error) { - return applyWhereCondition[TObject](condition, query, tableName) +func (condition FieldCondition[TObject, TAtribute]) ApplyTo(query *gorm.DB, table Table) (*gorm.DB, error) { + return applyWhereCondition[TObject](condition, query, table) } -func applyWhereCondition[T any](condition WhereCondition[T], query *gorm.DB, tableName string) (*gorm.DB, error) { - sql, values, err := condition.GetSQL(query, tableName) +func applyWhereCondition[T Model](condition WhereCondition[T], query *gorm.DB, table Table) (*gorm.DB, error) { + sql, values, err := condition.GetSQL(query, table) if err != nil { return nil, err } @@ -175,26 +326,33 @@ func applyWhereCondition[T any](condition WhereCondition[T], query *gorm.DB, tab //nolint:unused // is used func (condition FieldCondition[TObject, TAtribute]) affectsDeletedAt() bool { - return condition.Field == DeletedAtField + return condition.FieldIdentifier.Field == deletedAtField } -func (condition FieldCondition[TObject, TAtribute]) GetSQL(query *gorm.DB, tableName string) (string, []any, error) { - columnName := condition.Column - if columnName == "" { - columnName = query.NamingStrategy.ColumnName(tableName, condition.Field) - } +func (condition FieldCondition[TObject, TAtribute]) GetSQL(query *gorm.DB, table Table) (string, []any, error) { + columnName := table.Alias + "." + condition.FieldIdentifier.ColumnName(query, table) + return condition.Operator.ToSQL(columnName) +} - // add column prefix and table name once we know the column name - columnName = tableName + "." + condition.ColumnPrefix + columnName +// Interface of a join condition that joins T with any other model +type IJoinCondition[T Model] interface { + Condition[T] - return condition.Operator.ToSQL(columnName) + // Returns true if this condition or any nested condition makes a preload + makesPreload() bool + + // Returns true if the condition of nay nested condition applies a filter (has where conditions) + makesFilter() bool } // Condition that joins with other table -type JoinCondition[T1 any, T2 any] struct { - T1Field string - T2Field string - Conditions []Condition[T2] +type JoinCondition[T1 Model, T2 Model] struct { + T1Field string + T2Field string + RelationField string + Conditions []Condition[T2] + // condition to preload T1 in case T2 any nested object is preloaded by user + T1PreloadCondition PreloadCondition[T1] } func (condition JoinCondition[T1, T2]) interfaceVerificationMethod(t T1) { @@ -202,29 +360,50 @@ func (condition JoinCondition[T1, T2]) interfaceVerificationMethod(t T1) { // that an object is of type Condition[T] } +// Returns true if this condition or any nested condition makes a preload +func (condition JoinCondition[T1, T2]) makesPreload() bool { + _, joinConditions, t2PreloadCondition := divideConditionsByType(condition.Conditions) + + return t2PreloadCondition != nil || pie.Any(joinConditions, func(cond IJoinCondition[T2]) bool { + return cond.makesPreload() + }) +} + +// Returns true if the condition of nay nested condition applies a filter (has where conditions) +// +//nolint:unused // is used +func (condition JoinCondition[T1, T2]) makesFilter() bool { + whereConditions, joinConditions, _ := divideConditionsByType(condition.Conditions) + + return len(whereConditions) != 0 || pie.Any(joinConditions, func(cond IJoinCondition[T2]) bool { + return cond.makesFilter() + }) +} + // Applies a join between the tables of T1 and T2 // previousTableName is the name of the table of T1 // It also applies the nested conditions -func (condition JoinCondition[T1, T2]) ApplyTo(query *gorm.DB, previousTableName string) (*gorm.DB, error) { - // get the name of the table for T2 - toBeJoinedTableName, err := getTableName(query, *new(T2)) +func (condition JoinCondition[T1, T2]) ApplyTo(query *gorm.DB, t1Table Table) (*gorm.DB, error) { + whereConditions, joinConditions, t2PreloadCondition := divideConditionsByType(condition.Conditions) + + // get the sql to do the join with T2 + t2Table, err := t1Table.DeliverTable(query, *new(T2), condition.RelationField) if err != nil { return nil, err } - // add a suffix to avoid tables with the same name when joining - // the same table more than once - nextTableName := toBeJoinedTableName + "_" + previousTableName - - // get the sql to do the join with T2 - joinQuery := condition.getSQLJoin(query, toBeJoinedTableName, nextTableName, previousTableName) - - whereConditions, joinConditions := divideConditionsByType(condition.Conditions) + makesPreload := condition.makesPreload() + joinQuery := condition.getSQLJoin( + query, + t1Table, + t2Table, + len(whereConditions) == 0 && makesPreload, + ) - // apply WhereConditions to join in "on" clause + // apply WhereConditions to the join in the "on" clause connectionCondition := And(whereConditions...) - onQuery, onValues, err := connectionCondition.GetSQL(query, nextTableName) + onQuery, onValues, err := connectionCondition.GetSQL(query, t2Table) if err != nil { return nil, err } @@ -236,16 +415,36 @@ func (condition JoinCondition[T1, T2]) ApplyTo(query *gorm.DB, previousTableName if !connectionCondition.affectsDeletedAt() { joinQuery += fmt.Sprintf( " AND %s.deleted_at IS NULL", - nextTableName, + t2Table.Alias, ) } // add the join to the query query = query.Joins(joinQuery, onValues...) + // apply T1 preload condition + // if this condition has a T2 preload condition + // or any nested join condition has a preload condition + // and this is not first level (T1 is the type of the repository) + // because T1 is always loaded in that case + if makesPreload && !t1Table.IsInitial() { + query, err = condition.T1PreloadCondition.ApplyTo(query, t1Table) + if err != nil { + return nil, err + } + } + + // apply T2 preload condition + if t2PreloadCondition != nil { + query, err = t2PreloadCondition.ApplyTo(query, t2Table) + if err != nil { + return nil, err + } + } + // apply nested joins for _, joinCondition := range joinConditions { - query, err = joinCondition.ApplyTo(query, nextTableName) + query, err = joinCondition.ApplyTo(query, t2Table) if err != nil { return nil, err } @@ -257,28 +456,50 @@ func (condition JoinCondition[T1, T2]) ApplyTo(query *gorm.DB, previousTableName // Returns the SQL string to do a join between T1 and T2 // taking into account that the ID attribute necessary to do it // can be either in T1's or T2's table. -func (condition JoinCondition[T1, T2]) getSQLJoin(query *gorm.DB, toBeJoinedTableName, nextTableName, previousTableName string) string { +func (condition JoinCondition[T1, T2]) getSQLJoin( + query *gorm.DB, + t1Table Table, + t2Table Table, + isLeftJoin bool, +) string { + joinString := "INNER JOIN" + if isLeftJoin { + joinString = "LEFT JOIN" + } + return fmt.Sprintf( - `JOIN %[1]s %[2]s ON %[2]s.%[3]s = %[4]s.%[5]s + `%[6]s %[1]s %[2]s ON %[2]s.%[3]s = %[4]s.%[5]s `, - toBeJoinedTableName, - nextTableName, - query.NamingStrategy.ColumnName(nextTableName, condition.T2Field), - previousTableName, - query.NamingStrategy.ColumnName(previousTableName, condition.T1Field), + t2Table.Name, + t2Table.Alias, + query.NamingStrategy.ColumnName(t2Table.Name, condition.T2Field), + t1Table.Alias, + query.NamingStrategy.ColumnName(t1Table.Name, condition.T1Field), + joinString, ) } // Divides a list of conditions by its type: WhereConditions and JoinConditions -func divideConditionsByType[T any]( +func divideConditionsByType[T Model]( conditions []Condition[T], -) (thisEntityConditions []WhereCondition[T], joinConditions []Condition[T]) { +) (whereConditions []WhereCondition[T], joinConditions []IJoinCondition[T], preloadCondition *PreloadCondition[T]) { for _, condition := range conditions { - typedCondition, ok := condition.(WhereCondition[T]) + possibleWhereCondition, ok := condition.(WhereCondition[T]) + if ok { + whereConditions = append(whereConditions, possibleWhereCondition) + continue + } + + possiblePreloadCondition, ok := condition.(PreloadCondition[T]) + if ok { + preloadCondition = &possiblePreloadCondition + continue + } + + possibleJoinCondition, ok := condition.(IJoinCondition[T]) if ok { - thisEntityConditions = append(thisEntityConditions, typedCondition) - } else { - joinConditions = append(joinConditions, condition) + joinConditions = append(joinConditions, possibleJoinCondition) + continue } } @@ -287,7 +508,7 @@ func divideConditionsByType[T any]( // Condition that can be used to express conditions that are not supported (yet?) by BaDORM // Example: table1.columnX = table2.columnY -type UnsafeCondition[T any] struct { +type UnsafeCondition[T Model] struct { SQLCondition string Values []any } @@ -298,14 +519,14 @@ func (condition UnsafeCondition[T]) interfaceVerificationMethod(_ T) { // that an object is of type Condition[T] } -func (condition UnsafeCondition[T]) ApplyTo(query *gorm.DB, tableName string) (*gorm.DB, error) { - return applyWhereCondition[T](condition, query, tableName) +func (condition UnsafeCondition[T]) ApplyTo(query *gorm.DB, table Table) (*gorm.DB, error) { + return applyWhereCondition[T](condition, query, table) } -func (condition UnsafeCondition[T]) GetSQL(_ *gorm.DB, tableName string) (string, []any, error) { +func (condition UnsafeCondition[T]) GetSQL(_ *gorm.DB, table Table) (string, []any, error) { return fmt.Sprintf( condition.SQLCondition, - tableName, + table.Alias, ), condition.Values, nil } @@ -316,7 +537,7 @@ func (condition UnsafeCondition[T]) affectsDeletedAt() bool { // Condition that can be used to express conditions that are not supported (yet?) by BaDORM // Example: table1.columnX = table2.columnY -func NewUnsafeCondition[T any](condition string, values []any) UnsafeCondition[T] { +func NewUnsafeCondition[T Model](condition string, values []any) UnsafeCondition[T] { return UnsafeCondition[T]{ SQLCondition: condition, Values: values, @@ -334,11 +555,11 @@ func (condition InvalidCondition[T]) interfaceVerificationMethod(_ T) { // that an object is of type Condition[T] } -func (condition InvalidCondition[T]) ApplyTo(_ *gorm.DB, _ string) (*gorm.DB, error) { +func (condition InvalidCondition[T]) ApplyTo(_ *gorm.DB, _ Table) (*gorm.DB, error) { return nil, condition.Err } -func (condition InvalidCondition[T]) GetSQL(_ *gorm.DB, _ string) (string, []any, error) { +func (condition InvalidCondition[T]) GetSQL(_ *gorm.DB, _ Table) (string, []any, error) { return "", nil, condition.Err } @@ -357,14 +578,14 @@ func NewInvalidCondition[T any](err error) InvalidCondition[T] { // Logical Operators // ref: https://www.postgresql.org/docs/current/functions-logical.html -func And[T any](conditions ...WhereCondition[T]) WhereCondition[T] { +func And[T Model](conditions ...WhereCondition[T]) WhereCondition[T] { return NewConnectionCondition("AND", conditions...) } -func Or[T any](conditions ...WhereCondition[T]) WhereCondition[T] { +func Or[T Model](conditions ...WhereCondition[T]) WhereCondition[T] { return NewConnectionCondition("OR", conditions...) } -func Not[T any](conditions ...WhereCondition[T]) WhereCondition[T] { +func Not[T Model](conditions ...WhereCondition[T]) WhereCondition[T] { return NewContainerCondition("NOT", conditions...) } diff --git a/orm/crudRepository.go b/orm/crudRepository.go index b1d7883..308cba8 100644 --- a/orm/crudRepository.go +++ b/orm/crudRepository.go @@ -10,7 +10,7 @@ import ( // Generic CRUD Repository // T can be any model whose identifier attribute is of type ID -type CRUDRepository[T any, ID BadaasID] interface { +type CRUDRepository[T Model, ID ModelID] interface { // Create model "model" inside transaction "tx" Create(tx *gorm.DB, entity *T) error @@ -38,12 +38,12 @@ var ( ) // Implementation of the Generic CRUD Repository -type CRUDRepositoryImpl[T any, ID BadaasID] struct { +type CRUDRepositoryImpl[T Model, ID ModelID] struct { CRUDRepository[T, ID] } // Constructor of the Generic CRUD Repository -func NewCRUDRepository[T any, ID BadaasID]() CRUDRepository[T, ID] { +func NewCRUDRepository[T Model, ID ModelID]() CRUDRepository[T, ID] { return &CRUDRepositoryImpl[T, ID]{} } @@ -94,24 +94,39 @@ func (repository *CRUDRepositoryImpl[T, ID]) QueryOne(tx *gorm.DB, conditions .. // Get the list of models that match "conditions" inside transaction "tx" func (repository *CRUDRepositoryImpl[T, ID]) Query(tx *gorm.DB, conditions ...Condition[T]) ([]*T, error) { - initialTableName, err := getTableName(tx, *new(T)) + query, err := applyConditionsToQuery(tx, conditions) if err != nil { return nil, err } - query := tx + // execute query + var entities []*T + err = query.Find(&entities).Error + + return entities, err +} + +func applyConditionsToQuery[T Model](query *gorm.DB, conditions []Condition[T]) (*gorm.DB, error) { + initialTableName, err := getTableName(query, *new(T)) + if err != nil { + return nil, err + } + + initialTable := Table{ + Name: initialTableName, + Alias: initialTableName, + Initial: true, + } + + query = query.Select(initialTableName + ".*") for _, condition := range conditions { - query, err = condition.ApplyTo(query, initialTableName) + query, err = condition.ApplyTo(query, initialTable) if err != nil { return nil, err } } - // execute query - var entities []*T - err = query.Find(&entities).Error - - return entities, err + return query, nil } // Get the name of the table in "db" in which the data for "entity" is saved diff --git a/orm/crudService.go b/orm/crudService.go index eeb409b..579cc44 100644 --- a/orm/crudService.go +++ b/orm/crudService.go @@ -5,7 +5,7 @@ import ( ) // T can be any model whose identifier attribute is of type ID -type CRUDService[T any, ID BadaasID] interface { +type CRUDService[T Model, ID ModelID] interface { // Get the model of type T that has the "id" GetByID(id ID) (*T, error) @@ -21,13 +21,13 @@ type CRUDService[T any, ID BadaasID] interface { var _ CRUDService[UUIDModel, UUID] = (*crudServiceImpl[UUIDModel, UUID])(nil) // Implementation of the CRUD Service -type crudServiceImpl[T any, ID BadaasID] struct { +type crudServiceImpl[T Model, ID ModelID] struct { CRUDService[T, ID] db *gorm.DB repository CRUDRepository[T, ID] } -func NewCRUDService[T any, ID BadaasID]( +func NewCRUDService[T Model, ID ModelID]( db *gorm.DB, repository CRUDRepository[T, ID], ) CRUDService[T, ID] { diff --git a/orm/orm.go b/orm/orm.go index 0f52527..638330e 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -5,7 +5,7 @@ import ( "gorm.io/gorm" ) -func GetCRUD[T any, ID BadaasID](db *gorm.DB) (CRUDService[T, ID], CRUDRepository[T, ID]) { +func GetCRUD[T Model, ID ModelID](db *gorm.DB) (CRUDService[T, ID], CRUDRepository[T, ID]) { repository := NewCRUDRepository[T, ID]() return NewCRUDService(db, repository), repository } diff --git a/orm/preload.go b/orm/preload.go new file mode 100644 index 0000000..7e0ad5a --- /dev/null +++ b/orm/preload.go @@ -0,0 +1,41 @@ +package orm + +import "errors" + +var ErrRelationNotLoaded = errors.New("relation not loaded") + +func VerifyStructLoaded[T Model](toVerify *T) (*T, error) { + if toVerify == nil || !(*toVerify).IsLoaded() { + return nil, ErrRelationNotLoaded + } + + return toVerify, nil +} + +func VerifyPointerLoaded[TModel Model, TID ModelID](id *TID, toVerify *TModel) (*TModel, error) { + // when the pointer to the object is nil + // but the id pointer indicates that the relation is not nil + if id != nil && toVerify == nil { + return nil, ErrRelationNotLoaded + } + + return toVerify, nil +} + +func VerifyPointerWithIDLoaded[TModel Model, TID ModelID](id TID, toVerify *TModel) (*TModel, error) { + // when the pointer to the object is nil + // but the id indicates that the relation is not nil + if !id.IsNil() && toVerify == nil { + return nil, ErrRelationNotLoaded + } + + return toVerify, nil +} + +func VerifyCollectionLoaded[T Model](collection *[]T) ([]T, error) { + if collection == nil { + return nil, ErrRelationNotLoaded + } + + return *collection, nil +} diff --git a/orm/uuid.go b/orm/uuid.go index 6b6ca81..54b0c5c 100644 --- a/orm/uuid.go +++ b/orm/uuid.go @@ -54,8 +54,12 @@ func (id *UUID) Scan(src interface{}) error { return (*uuid.UUID)(id).Scan(src) } +func (id UUID) IsNil() bool { + return id == NilUUID +} + func (id UUID) GormValue(_ context.Context, _ *gorm.DB) clause.Expr { - if len(id) == 0 { + if id == NilUUID { return gorm.Expr("NULL") } diff --git a/persistence/models/User.go b/persistence/models/User.go index 0a38a6e..3a588a4 100644 --- a/persistence/models/User.go +++ b/persistence/models/User.go @@ -14,7 +14,9 @@ type User struct { func UserEmailCondition(operator orm.Operator[string]) orm.WhereCondition[User] { return orm.FieldCondition[User, string]{ + FieldIdentifier: orm.FieldIdentifier{ + Field: "Email", + }, Operator: operator, - Field: "Email", } } diff --git a/testintegration/asserts.go b/testintegration/asserts.go index b0c58e9..7f71762 100644 --- a/testintegration/asserts.go +++ b/testintegration/asserts.go @@ -23,10 +23,11 @@ func EqualList[T any](ts *suite.Suite, expectedList, actualList []T) { } } if j == expectedLen { - ts.Fail("Lists not equal", "element %v not in list %v", expectedList[i], actualList) for _, element := range actualList { log.Println(element) } + + ts.FailNow("Lists not equal", "element %v not in list %v", expectedList[i], actualList) } } } diff --git a/testintegration/conditions/bicycle_conditions.go b/testintegration/conditions/bicycle_conditions.go index b16e577..d8e7fa9 100644 --- a/testintegration/conditions/bicycle_conditions.go +++ b/testintegration/conditions/bicycle_conditions.go @@ -9,44 +9,56 @@ import ( func BicycleId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Bicycle] { return orm.FieldCondition[models.Bicycle, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func BicycleCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Bicycle] { return orm.FieldCondition[models.Bicycle, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func BicycleUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Bicycle] { return orm.FieldCondition[models.Bicycle, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func BicycleDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Bicycle] { return orm.FieldCondition[models.Bicycle, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var bicycleNameFieldID = orm.FieldIdentifier{Field: "Name"} + func BicycleName(operator orm.Operator[string]) orm.WhereCondition[models.Bicycle] { return orm.FieldCondition[models.Bicycle, string]{ - Field: "Name", - Operator: operator, + FieldIdentifier: bicycleNameFieldID, + Operator: operator, } } -func BicycleOwner(conditions ...orm.Condition[models.Person]) orm.Condition[models.Bicycle] { +func BicycleOwner(conditions ...orm.Condition[models.Person]) orm.IJoinCondition[models.Bicycle] { return orm.JoinCondition[models.Bicycle, models.Person]{ - Conditions: conditions, - T1Field: "OwnerName", - T2Field: "Name", + Conditions: conditions, + RelationField: "Owner", + T1Field: "OwnerName", + T1PreloadCondition: BicyclePreloadAttributes, + T2Field: "Name", } } + +var BicyclePreloadOwner = BicycleOwner(PersonPreloadAttributes) +var bicycleOwnerNameFieldID = orm.FieldIdentifier{Field: "OwnerName"} + func BicycleOwnerName(operator orm.Operator[string]) orm.WhereCondition[models.Bicycle] { return orm.FieldCondition[models.Bicycle, string]{ - Field: "OwnerName", - Operator: operator, + FieldIdentifier: bicycleOwnerNameFieldID, + Operator: operator, } } + +var BicyclePreloadAttributes = orm.NewPreloadCondition[models.Bicycle](bicycleNameFieldID, bicycleOwnerNameFieldID) +var BicyclePreloadRelations = []orm.Condition[models.Bicycle]{BicyclePreloadOwner} diff --git a/testintegration/conditions/brand_conditions.go b/testintegration/conditions/brand_conditions.go index 9d3421a..3823814 100644 --- a/testintegration/conditions/brand_conditions.go +++ b/testintegration/conditions/brand_conditions.go @@ -7,33 +7,38 @@ import ( "time" ) -func BrandId(operator orm.Operator[uint]) orm.WhereCondition[models.Brand] { - return orm.FieldCondition[models.Brand, uint]{ - Field: "ID", - Operator: operator, +func BrandId(operator orm.Operator[orm.UIntID]) orm.WhereCondition[models.Brand] { + return orm.FieldCondition[models.Brand, orm.UIntID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func BrandCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Brand] { return orm.FieldCondition[models.Brand, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func BrandUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Brand] { return orm.FieldCondition[models.Brand, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func BrandDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Brand] { return orm.FieldCondition[models.Brand, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var brandNameFieldID = orm.FieldIdentifier{Field: "Name"} + func BrandName(operator orm.Operator[string]) orm.WhereCondition[models.Brand] { return orm.FieldCondition[models.Brand, string]{ - Field: "Name", - Operator: operator, + FieldIdentifier: brandNameFieldID, + Operator: operator, } } + +var BrandPreloadAttributes = orm.NewPreloadCondition[models.Brand](brandNameFieldID) diff --git a/testintegration/conditions/child_conditions.go b/testintegration/conditions/child_conditions.go new file mode 100644 index 0000000..8b85634 --- /dev/null +++ b/testintegration/conditions/child_conditions.go @@ -0,0 +1,75 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + orm "github.com/ditrit/badaas/orm" + models "github.com/ditrit/badaas/testintegration/models" + gorm "gorm.io/gorm" + "time" +) + +func ChildId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Child] { + return orm.FieldCondition[models.Child, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func ChildCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Child] { + return orm.FieldCondition[models.Child, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func ChildUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Child] { + return orm.FieldCondition[models.Child, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func ChildDeletedAt(operator orm.Operator[gorm.DeletedAt]) orm.WhereCondition[models.Child] { + return orm.FieldCondition[models.Child, gorm.DeletedAt]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} +func ChildParent1(conditions ...orm.Condition[models.Parent1]) orm.IJoinCondition[models.Child] { + return orm.JoinCondition[models.Child, models.Parent1]{ + Conditions: conditions, + RelationField: "Parent1", + T1Field: "Parent1ID", + T1PreloadCondition: ChildPreloadAttributes, + T2Field: "ID", + } +} + +var ChildPreloadParent1 = ChildParent1(Parent1PreloadAttributes) +var childParent1IdFieldID = orm.FieldIdentifier{Field: "Parent1ID"} + +func ChildParent1Id(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Child] { + return orm.FieldCondition[models.Child, orm.UUID]{ + FieldIdentifier: childParent1IdFieldID, + Operator: operator, + } +} +func ChildParent2(conditions ...orm.Condition[models.Parent2]) orm.IJoinCondition[models.Child] { + return orm.JoinCondition[models.Child, models.Parent2]{ + Conditions: conditions, + RelationField: "Parent2", + T1Field: "Parent2ID", + T1PreloadCondition: ChildPreloadAttributes, + T2Field: "ID", + } +} + +var ChildPreloadParent2 = ChildParent2(Parent2PreloadAttributes) +var childParent2IdFieldID = orm.FieldIdentifier{Field: "Parent2ID"} + +func ChildParent2Id(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Child] { + return orm.FieldCondition[models.Child, orm.UUID]{ + FieldIdentifier: childParent2IdFieldID, + Operator: operator, + } +} + +var ChildPreloadAttributes = orm.NewPreloadCondition[models.Child](childParent1IdFieldID, childParent2IdFieldID) +var ChildPreloadRelations = []orm.Condition[models.Child]{ChildPreloadParent1, ChildPreloadParent2} diff --git a/testintegration/conditions/city_conditions.go b/testintegration/conditions/city_conditions.go index 1f0218f..458b878 100644 --- a/testintegration/conditions/city_conditions.go +++ b/testintegration/conditions/city_conditions.go @@ -9,37 +9,56 @@ import ( func CityId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.City] { return orm.FieldCondition[models.City, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func CityCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.City] { return orm.FieldCondition[models.City, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func CityUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.City] { return orm.FieldCondition[models.City, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func CityDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.City] { return orm.FieldCondition[models.City, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var cityNameFieldID = orm.FieldIdentifier{Field: "Name"} + func CityName(operator orm.Operator[string]) orm.WhereCondition[models.City] { return orm.FieldCondition[models.City, string]{ - Field: "Name", - Operator: operator, + FieldIdentifier: cityNameFieldID, + Operator: operator, + } +} +func CityCountry(conditions ...orm.Condition[models.Country]) orm.IJoinCondition[models.City] { + return orm.JoinCondition[models.City, models.Country]{ + Conditions: conditions, + RelationField: "Country", + T1Field: "CountryID", + T1PreloadCondition: CityPreloadAttributes, + T2Field: "ID", } } + +var CityPreloadCountry = CityCountry(CountryPreloadAttributes) +var cityCountryIdFieldID = orm.FieldIdentifier{Field: "CountryID"} + func CityCountryId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.City] { return orm.FieldCondition[models.City, orm.UUID]{ - Field: "CountryID", - Operator: operator, + FieldIdentifier: cityCountryIdFieldID, + Operator: operator, } } + +var CityPreloadAttributes = orm.NewPreloadCondition[models.City](cityNameFieldID, cityCountryIdFieldID) +var CityPreloadRelations = []orm.Condition[models.City]{CityPreloadCountry} diff --git a/testintegration/conditions/company_conditions.go b/testintegration/conditions/company_conditions.go index b87db9b..9a2a02d 100644 --- a/testintegration/conditions/company_conditions.go +++ b/testintegration/conditions/company_conditions.go @@ -9,38 +9,40 @@ import ( func CompanyId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Company] { return orm.FieldCondition[models.Company, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func CompanyCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Company] { return orm.FieldCondition[models.Company, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func CompanyUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Company] { return orm.FieldCondition[models.Company, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func CompanyDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Company] { return orm.FieldCondition[models.Company, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var companyNameFieldID = orm.FieldIdentifier{Field: "Name"} + func CompanyName(operator orm.Operator[string]) orm.WhereCondition[models.Company] { return orm.FieldCondition[models.Company, string]{ - Field: "Name", - Operator: operator, + FieldIdentifier: companyNameFieldID, + Operator: operator, } } -func SellerCompany(conditions ...orm.Condition[models.Company]) orm.Condition[models.Seller] { - return orm.JoinCondition[models.Seller, models.Company]{ - Conditions: conditions, - T1Field: "CompanyID", - T2Field: "ID", - } +func CompanyPreloadSellers(nestedPreloads ...orm.IJoinCondition[models.Seller]) orm.Condition[models.Company] { + return orm.NewCollectionPreloadCondition[models.Company, models.Seller]("Sellers", nestedPreloads) } + +var CompanyPreloadAttributes = orm.NewPreloadCondition[models.Company](companyNameFieldID) +var CompanyPreloadRelations = []orm.Condition[models.Company]{CompanyPreloadSellers()} diff --git a/testintegration/conditions/country_conditions.go b/testintegration/conditions/country_conditions.go index f00fddf..14dcaee 100644 --- a/testintegration/conditions/country_conditions.go +++ b/testintegration/conditions/country_conditions.go @@ -9,45 +9,47 @@ import ( func CountryId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Country] { return orm.FieldCondition[models.Country, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func CountryCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Country] { return orm.FieldCondition[models.Country, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func CountryUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Country] { return orm.FieldCondition[models.Country, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func CountryDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Country] { return orm.FieldCondition[models.Country, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var countryNameFieldID = orm.FieldIdentifier{Field: "Name"} + func CountryName(operator orm.Operator[string]) orm.WhereCondition[models.Country] { return orm.FieldCondition[models.Country, string]{ - Field: "Name", - Operator: operator, + FieldIdentifier: countryNameFieldID, + Operator: operator, } } -func CountryCapital(conditions ...orm.Condition[models.City]) orm.Condition[models.Country] { +func CountryCapital(conditions ...orm.Condition[models.City]) orm.IJoinCondition[models.Country] { return orm.JoinCondition[models.Country, models.City]{ - Conditions: conditions, - T1Field: "ID", - T2Field: "CountryID", - } -} -func CityCountry(conditions ...orm.Condition[models.Country]) orm.Condition[models.City] { - return orm.JoinCondition[models.City, models.Country]{ - Conditions: conditions, - T1Field: "CountryID", - T2Field: "ID", + Conditions: conditions, + RelationField: "Capital", + T1Field: "ID", + T1PreloadCondition: CountryPreloadAttributes, + T2Field: "CountryID", } } + +var CountryPreloadCapital = CountryCapital(CityPreloadAttributes) +var CountryPreloadAttributes = orm.NewPreloadCondition[models.Country](countryNameFieldID) +var CountryPreloadRelations = []orm.Condition[models.Country]{CountryPreloadCapital} diff --git a/testintegration/conditions/employee_conditions.go b/testintegration/conditions/employee_conditions.go index 7786023..b2f9f0d 100644 --- a/testintegration/conditions/employee_conditions.go +++ b/testintegration/conditions/employee_conditions.go @@ -9,44 +9,56 @@ import ( func EmployeeId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Employee] { return orm.FieldCondition[models.Employee, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func EmployeeCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Employee] { return orm.FieldCondition[models.Employee, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func EmployeeUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Employee] { return orm.FieldCondition[models.Employee, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func EmployeeDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Employee] { return orm.FieldCondition[models.Employee, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var employeeNameFieldID = orm.FieldIdentifier{Field: "Name"} + func EmployeeName(operator orm.Operator[string]) orm.WhereCondition[models.Employee] { return orm.FieldCondition[models.Employee, string]{ - Field: "Name", - Operator: operator, + FieldIdentifier: employeeNameFieldID, + Operator: operator, } } -func EmployeeBoss(conditions ...orm.Condition[models.Employee]) orm.Condition[models.Employee] { +func EmployeeBoss(conditions ...orm.Condition[models.Employee]) orm.IJoinCondition[models.Employee] { return orm.JoinCondition[models.Employee, models.Employee]{ - Conditions: conditions, - T1Field: "BossID", - T2Field: "ID", + Conditions: conditions, + RelationField: "Boss", + T1Field: "BossID", + T1PreloadCondition: EmployeePreloadAttributes, + T2Field: "ID", } } + +var EmployeePreloadBoss = EmployeeBoss(EmployeePreloadAttributes) +var employeeBossIdFieldID = orm.FieldIdentifier{Field: "BossID"} + func EmployeeBossId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Employee] { return orm.FieldCondition[models.Employee, orm.UUID]{ - Field: "BossID", - Operator: operator, + FieldIdentifier: employeeBossIdFieldID, + Operator: operator, } } + +var EmployeePreloadAttributes = orm.NewPreloadCondition[models.Employee](employeeNameFieldID, employeeBossIdFieldID) +var EmployeePreloadRelations = []orm.Condition[models.Employee]{EmployeePreloadBoss} diff --git a/testintegration/conditions/parent1_conditions.go b/testintegration/conditions/parent1_conditions.go new file mode 100644 index 0000000..6907024 --- /dev/null +++ b/testintegration/conditions/parent1_conditions.go @@ -0,0 +1,56 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + orm "github.com/ditrit/badaas/orm" + models "github.com/ditrit/badaas/testintegration/models" + gorm "gorm.io/gorm" + "time" +) + +func Parent1Id(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Parent1] { + return orm.FieldCondition[models.Parent1, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func Parent1CreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Parent1] { + return orm.FieldCondition[models.Parent1, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func Parent1UpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Parent1] { + return orm.FieldCondition[models.Parent1, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func Parent1DeletedAt(operator orm.Operator[gorm.DeletedAt]) orm.WhereCondition[models.Parent1] { + return orm.FieldCondition[models.Parent1, gorm.DeletedAt]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} +func Parent1ParentParent(conditions ...orm.Condition[models.ParentParent]) orm.IJoinCondition[models.Parent1] { + return orm.JoinCondition[models.Parent1, models.ParentParent]{ + Conditions: conditions, + RelationField: "ParentParent", + T1Field: "ParentParentID", + T1PreloadCondition: Parent1PreloadAttributes, + T2Field: "ID", + } +} + +var Parent1PreloadParentParent = Parent1ParentParent(ParentParentPreloadAttributes) +var parent1ParentParentIdFieldID = orm.FieldIdentifier{Field: "ParentParentID"} + +func Parent1ParentParentId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Parent1] { + return orm.FieldCondition[models.Parent1, orm.UUID]{ + FieldIdentifier: parent1ParentParentIdFieldID, + Operator: operator, + } +} + +var Parent1PreloadAttributes = orm.NewPreloadCondition[models.Parent1](parent1ParentParentIdFieldID) +var Parent1PreloadRelations = []orm.Condition[models.Parent1]{Parent1PreloadParentParent} diff --git a/testintegration/conditions/parent2_conditions.go b/testintegration/conditions/parent2_conditions.go new file mode 100644 index 0000000..96ed18d --- /dev/null +++ b/testintegration/conditions/parent2_conditions.go @@ -0,0 +1,56 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + orm "github.com/ditrit/badaas/orm" + models "github.com/ditrit/badaas/testintegration/models" + gorm "gorm.io/gorm" + "time" +) + +func Parent2Id(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Parent2] { + return orm.FieldCondition[models.Parent2, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func Parent2CreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Parent2] { + return orm.FieldCondition[models.Parent2, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func Parent2UpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Parent2] { + return orm.FieldCondition[models.Parent2, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func Parent2DeletedAt(operator orm.Operator[gorm.DeletedAt]) orm.WhereCondition[models.Parent2] { + return orm.FieldCondition[models.Parent2, gorm.DeletedAt]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} +func Parent2ParentParent(conditions ...orm.Condition[models.ParentParent]) orm.IJoinCondition[models.Parent2] { + return orm.JoinCondition[models.Parent2, models.ParentParent]{ + Conditions: conditions, + RelationField: "ParentParent", + T1Field: "ParentParentID", + T1PreloadCondition: Parent2PreloadAttributes, + T2Field: "ID", + } +} + +var Parent2PreloadParentParent = Parent2ParentParent(ParentParentPreloadAttributes) +var parent2ParentParentIdFieldID = orm.FieldIdentifier{Field: "ParentParentID"} + +func Parent2ParentParentId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Parent2] { + return orm.FieldCondition[models.Parent2, orm.UUID]{ + FieldIdentifier: parent2ParentParentIdFieldID, + Operator: operator, + } +} + +var Parent2PreloadAttributes = orm.NewPreloadCondition[models.Parent2](parent2ParentParentIdFieldID) +var Parent2PreloadRelations = []orm.Condition[models.Parent2]{Parent2PreloadParentParent} diff --git a/testintegration/conditions/parent_parent_conditions.go b/testintegration/conditions/parent_parent_conditions.go new file mode 100644 index 0000000..613881c --- /dev/null +++ b/testintegration/conditions/parent_parent_conditions.go @@ -0,0 +1,45 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + orm "github.com/ditrit/badaas/orm" + models "github.com/ditrit/badaas/testintegration/models" + gorm "gorm.io/gorm" + "time" +) + +func ParentParentId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.ParentParent] { + return orm.FieldCondition[models.ParentParent, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func ParentParentCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.ParentParent] { + return orm.FieldCondition[models.ParentParent, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func ParentParentUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.ParentParent] { + return orm.FieldCondition[models.ParentParent, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func ParentParentDeletedAt(operator orm.Operator[gorm.DeletedAt]) orm.WhereCondition[models.ParentParent] { + return orm.FieldCondition[models.ParentParent, gorm.DeletedAt]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} + +var parentParentNameFieldID = orm.FieldIdentifier{Field: "Name"} + +func ParentParentName(operator orm.Operator[string]) orm.WhereCondition[models.ParentParent] { + return orm.FieldCondition[models.ParentParent, string]{ + FieldIdentifier: parentParentNameFieldID, + Operator: operator, + } +} + +var ParentParentPreloadAttributes = orm.NewPreloadCondition[models.ParentParent](parentParentNameFieldID) diff --git a/testintegration/conditions/person_conditions.go b/testintegration/conditions/person_conditions.go index c378abe..6a67442 100644 --- a/testintegration/conditions/person_conditions.go +++ b/testintegration/conditions/person_conditions.go @@ -9,31 +9,36 @@ import ( func PersonId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Person] { return orm.FieldCondition[models.Person, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func PersonCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Person] { return orm.FieldCondition[models.Person, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func PersonUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Person] { return orm.FieldCondition[models.Person, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func PersonDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Person] { return orm.FieldCondition[models.Person, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var personNameFieldID = orm.FieldIdentifier{Field: "Name"} + func PersonName(operator orm.Operator[string]) orm.WhereCondition[models.Person] { return orm.FieldCondition[models.Person, string]{ - Field: "Name", - Operator: operator, + FieldIdentifier: personNameFieldID, + Operator: operator, } } + +var PersonPreloadAttributes = orm.NewPreloadCondition[models.Person](personNameFieldID) diff --git a/testintegration/conditions/phone_conditions.go b/testintegration/conditions/phone_conditions.go index 7766e08..93dac6a 100644 --- a/testintegration/conditions/phone_conditions.go +++ b/testintegration/conditions/phone_conditions.go @@ -7,46 +7,58 @@ import ( "time" ) -func PhoneId(operator orm.Operator[uint]) orm.WhereCondition[models.Phone] { - return orm.FieldCondition[models.Phone, uint]{ - Field: "ID", - Operator: operator, +func PhoneId(operator orm.Operator[orm.UIntID]) orm.WhereCondition[models.Phone] { + return orm.FieldCondition[models.Phone, orm.UIntID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func PhoneCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Phone] { return orm.FieldCondition[models.Phone, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func PhoneUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Phone] { return orm.FieldCondition[models.Phone, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func PhoneDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Phone] { return orm.FieldCondition[models.Phone, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var phoneNameFieldID = orm.FieldIdentifier{Field: "Name"} + func PhoneName(operator orm.Operator[string]) orm.WhereCondition[models.Phone] { return orm.FieldCondition[models.Phone, string]{ - Field: "Name", - Operator: operator, + FieldIdentifier: phoneNameFieldID, + Operator: operator, } } -func PhoneBrand(conditions ...orm.Condition[models.Brand]) orm.Condition[models.Phone] { +func PhoneBrand(conditions ...orm.Condition[models.Brand]) orm.IJoinCondition[models.Phone] { return orm.JoinCondition[models.Phone, models.Brand]{ - Conditions: conditions, - T1Field: "BrandID", - T2Field: "ID", + Conditions: conditions, + RelationField: "Brand", + T1Field: "BrandID", + T1PreloadCondition: PhonePreloadAttributes, + T2Field: "ID", } } + +var PhonePreloadBrand = PhoneBrand(BrandPreloadAttributes) +var phoneBrandIdFieldID = orm.FieldIdentifier{Field: "BrandID"} + func PhoneBrandId(operator orm.Operator[uint]) orm.WhereCondition[models.Phone] { return orm.FieldCondition[models.Phone, uint]{ - Field: "BrandID", - Operator: operator, + FieldIdentifier: phoneBrandIdFieldID, + Operator: operator, } } + +var PhonePreloadAttributes = orm.NewPreloadCondition[models.Phone](phoneNameFieldID, phoneBrandIdFieldID) +var PhonePreloadRelations = []orm.Condition[models.Phone]{PhonePreloadBrand} diff --git a/testintegration/conditions/product_conditions.go b/testintegration/conditions/product_conditions.go index 55f044f..cb794a5 100644 --- a/testintegration/conditions/product_conditions.go +++ b/testintegration/conditions/product_conditions.go @@ -9,92 +9,129 @@ import ( func ProductId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func ProductCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func ProductUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func ProductDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var productStringFieldID = orm.FieldIdentifier{Column: "string_something_else"} + func ProductString(operator orm.Operator[string]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, string]{ - Column: "string_something_else", - Operator: operator, + FieldIdentifier: productStringFieldID, + Operator: operator, } } + +var productIntFieldID = orm.FieldIdentifier{Field: "Int"} + func ProductInt(operator orm.Operator[int]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, int]{ - Field: "Int", - Operator: operator, + FieldIdentifier: productIntFieldID, + Operator: operator, } } + +var productIntPointerFieldID = orm.FieldIdentifier{Field: "IntPointer"} + func ProductIntPointer(operator orm.Operator[int]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, int]{ - Field: "IntPointer", - Operator: operator, + FieldIdentifier: productIntPointerFieldID, + Operator: operator, } } + +var productFloatFieldID = orm.FieldIdentifier{Field: "Float"} + func ProductFloat(operator orm.Operator[float64]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, float64]{ - Field: "Float", - Operator: operator, + FieldIdentifier: productFloatFieldID, + Operator: operator, } } + +var productNullFloatFieldID = orm.FieldIdentifier{Field: "NullFloat"} + func ProductNullFloat(operator orm.Operator[float64]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, float64]{ - Field: "NullFloat", - Operator: operator, + FieldIdentifier: productNullFloatFieldID, + Operator: operator, } } + +var productBoolFieldID = orm.FieldIdentifier{Field: "Bool"} + func ProductBool(operator orm.Operator[bool]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, bool]{ - Field: "Bool", - Operator: operator, + FieldIdentifier: productBoolFieldID, + Operator: operator, } } + +var productNullBoolFieldID = orm.FieldIdentifier{Field: "NullBool"} + func ProductNullBool(operator orm.Operator[bool]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, bool]{ - Field: "NullBool", - Operator: operator, + FieldIdentifier: productNullBoolFieldID, + Operator: operator, } } + +var productByteArrayFieldID = orm.FieldIdentifier{Field: "ByteArray"} + func ProductByteArray(operator orm.Operator[[]uint8]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, []uint8]{ - Field: "ByteArray", - Operator: operator, + FieldIdentifier: productByteArrayFieldID, + Operator: operator, } } + +var productMultiStringFieldID = orm.FieldIdentifier{Field: "MultiString"} + func ProductMultiString(operator orm.Operator[models.MultiString]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, models.MultiString]{ - Field: "MultiString", - Operator: operator, + FieldIdentifier: productMultiStringFieldID, + Operator: operator, } } -func ProductEmbeddedInt(operator orm.Operator[int]) orm.WhereCondition[models.Product] { + +var productToBeEmbeddedEmbeddedIntFieldID = orm.FieldIdentifier{Field: "EmbeddedInt"} + +func ProductToBeEmbeddedEmbeddedInt(operator orm.Operator[int]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, int]{ - Field: "EmbeddedInt", - Operator: operator, + FieldIdentifier: productToBeEmbeddedEmbeddedIntFieldID, + Operator: operator, } } + +var productGormEmbeddedIntFieldID = orm.FieldIdentifier{ + ColumnPrefix: "gorm_embedded_", + Field: "Int", +} + func ProductGormEmbeddedInt(operator orm.Operator[int]) orm.WhereCondition[models.Product] { return orm.FieldCondition[models.Product, int]{ - ColumnPrefix: "gorm_embedded_", - Field: "Int", - Operator: operator, + FieldIdentifier: productGormEmbeddedIntFieldID, + Operator: operator, } } + +var ProductPreloadAttributes = orm.NewPreloadCondition[models.Product](productStringFieldID, productIntFieldID, productIntPointerFieldID, productFloatFieldID, productNullFloatFieldID, productBoolFieldID, productNullBoolFieldID, productByteArrayFieldID, productMultiStringFieldID, productToBeEmbeddedEmbeddedIntFieldID, productGormEmbeddedIntFieldID) diff --git a/testintegration/conditions/sale_conditions.go b/testintegration/conditions/sale_conditions.go index 6e49ebc..5fb11c4 100644 --- a/testintegration/conditions/sale_conditions.go +++ b/testintegration/conditions/sale_conditions.go @@ -9,63 +9,84 @@ import ( func SaleId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Sale] { return orm.FieldCondition[models.Sale, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func SaleCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Sale] { return orm.FieldCondition[models.Sale, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func SaleUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Sale] { return orm.FieldCondition[models.Sale, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func SaleDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Sale] { return orm.FieldCondition[models.Sale, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var saleCodeFieldID = orm.FieldIdentifier{Field: "Code"} + func SaleCode(operator orm.Operator[int]) orm.WhereCondition[models.Sale] { return orm.FieldCondition[models.Sale, int]{ - Field: "Code", - Operator: operator, + FieldIdentifier: saleCodeFieldID, + Operator: operator, } } + +var saleDescriptionFieldID = orm.FieldIdentifier{Field: "Description"} + func SaleDescription(operator orm.Operator[string]) orm.WhereCondition[models.Sale] { return orm.FieldCondition[models.Sale, string]{ - Field: "Description", - Operator: operator, + FieldIdentifier: saleDescriptionFieldID, + Operator: operator, } } -func SaleProduct(conditions ...orm.Condition[models.Product]) orm.Condition[models.Sale] { +func SaleProduct(conditions ...orm.Condition[models.Product]) orm.IJoinCondition[models.Sale] { return orm.JoinCondition[models.Sale, models.Product]{ - Conditions: conditions, - T1Field: "ProductID", - T2Field: "ID", + Conditions: conditions, + RelationField: "Product", + T1Field: "ProductID", + T1PreloadCondition: SalePreloadAttributes, + T2Field: "ID", } } + +var SalePreloadProduct = SaleProduct(ProductPreloadAttributes) +var saleProductIdFieldID = orm.FieldIdentifier{Field: "ProductID"} + func SaleProductId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Sale] { return orm.FieldCondition[models.Sale, orm.UUID]{ - Field: "ProductID", - Operator: operator, + FieldIdentifier: saleProductIdFieldID, + Operator: operator, } } -func SaleSeller(conditions ...orm.Condition[models.Seller]) orm.Condition[models.Sale] { +func SaleSeller(conditions ...orm.Condition[models.Seller]) orm.IJoinCondition[models.Sale] { return orm.JoinCondition[models.Sale, models.Seller]{ - Conditions: conditions, - T1Field: "SellerID", - T2Field: "ID", + Conditions: conditions, + RelationField: "Seller", + T1Field: "SellerID", + T1PreloadCondition: SalePreloadAttributes, + T2Field: "ID", } } + +var SalePreloadSeller = SaleSeller(SellerPreloadAttributes) +var saleSellerIdFieldID = orm.FieldIdentifier{Field: "SellerID"} + func SaleSellerId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Sale] { return orm.FieldCondition[models.Sale, orm.UUID]{ - Field: "SellerID", - Operator: operator, + FieldIdentifier: saleSellerIdFieldID, + Operator: operator, } } + +var SalePreloadAttributes = orm.NewPreloadCondition[models.Sale](saleCodeFieldID, saleDescriptionFieldID, saleProductIdFieldID, saleSellerIdFieldID) +var SalePreloadRelations = []orm.Condition[models.Sale]{SalePreloadProduct, SalePreloadSeller} diff --git a/testintegration/conditions/seller_conditions.go b/testintegration/conditions/seller_conditions.go index 5390f2d..c206432 100644 --- a/testintegration/conditions/seller_conditions.go +++ b/testintegration/conditions/seller_conditions.go @@ -9,37 +9,75 @@ import ( func SellerId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Seller] { return orm.FieldCondition[models.Seller, orm.UUID]{ - Field: "ID", - Operator: operator, + FieldIdentifier: orm.IDFieldID, + Operator: operator, } } func SellerCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Seller] { return orm.FieldCondition[models.Seller, time.Time]{ - Field: "CreatedAt", - Operator: operator, + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, } } func SellerUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Seller] { return orm.FieldCondition[models.Seller, time.Time]{ - Field: "UpdatedAt", - Operator: operator, + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, } } func SellerDeletedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.Seller] { return orm.FieldCondition[models.Seller, time.Time]{ - Field: "DeletedAt", - Operator: operator, + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, } } + +var sellerNameFieldID = orm.FieldIdentifier{Field: "Name"} + func SellerName(operator orm.Operator[string]) orm.WhereCondition[models.Seller] { return orm.FieldCondition[models.Seller, string]{ - Field: "Name", - Operator: operator, + FieldIdentifier: sellerNameFieldID, + Operator: operator, + } +} +func SellerCompany(conditions ...orm.Condition[models.Company]) orm.IJoinCondition[models.Seller] { + return orm.JoinCondition[models.Seller, models.Company]{ + Conditions: conditions, + RelationField: "Company", + T1Field: "CompanyID", + T1PreloadCondition: SellerPreloadAttributes, + T2Field: "ID", } } + +var SellerPreloadCompany = SellerCompany(CompanyPreloadAttributes) +var sellerCompanyIdFieldID = orm.FieldIdentifier{Field: "CompanyID"} + func SellerCompanyId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Seller] { return orm.FieldCondition[models.Seller, orm.UUID]{ - Field: "CompanyID", - Operator: operator, + FieldIdentifier: sellerCompanyIdFieldID, + Operator: operator, + } +} +func SellerUniversity(conditions ...orm.Condition[models.University]) orm.IJoinCondition[models.Seller] { + return orm.JoinCondition[models.Seller, models.University]{ + Conditions: conditions, + RelationField: "University", + T1Field: "UniversityID", + T1PreloadCondition: SellerPreloadAttributes, + T2Field: "ID", + } +} + +var SellerPreloadUniversity = SellerUniversity(UniversityPreloadAttributes) +var sellerUniversityIdFieldID = orm.FieldIdentifier{Field: "UniversityID"} + +func SellerUniversityId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.Seller] { + return orm.FieldCondition[models.Seller, orm.UUID]{ + FieldIdentifier: sellerUniversityIdFieldID, + Operator: operator, } } + +var SellerPreloadAttributes = orm.NewPreloadCondition[models.Seller](sellerNameFieldID, sellerCompanyIdFieldID, sellerUniversityIdFieldID) +var SellerPreloadRelations = []orm.Condition[models.Seller]{SellerPreloadCompany, SellerPreloadUniversity} diff --git a/testintegration/conditions/university_conditions.go b/testintegration/conditions/university_conditions.go new file mode 100644 index 0000000..b670940 --- /dev/null +++ b/testintegration/conditions/university_conditions.go @@ -0,0 +1,45 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package conditions + +import ( + orm "github.com/ditrit/badaas/orm" + models "github.com/ditrit/badaas/testintegration/models" + gorm "gorm.io/gorm" + "time" +) + +func UniversityId(operator orm.Operator[orm.UUID]) orm.WhereCondition[models.University] { + return orm.FieldCondition[models.University, orm.UUID]{ + FieldIdentifier: orm.IDFieldID, + Operator: operator, + } +} +func UniversityCreatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.University] { + return orm.FieldCondition[models.University, time.Time]{ + FieldIdentifier: orm.CreatedAtFieldID, + Operator: operator, + } +} +func UniversityUpdatedAt(operator orm.Operator[time.Time]) orm.WhereCondition[models.University] { + return orm.FieldCondition[models.University, time.Time]{ + FieldIdentifier: orm.UpdatedAtFieldID, + Operator: operator, + } +} +func UniversityDeletedAt(operator orm.Operator[gorm.DeletedAt]) orm.WhereCondition[models.University] { + return orm.FieldCondition[models.University, gorm.DeletedAt]{ + FieldIdentifier: orm.DeletedAtFieldID, + Operator: operator, + } +} + +var universityNameFieldID = orm.FieldIdentifier{Field: "Name"} + +func UniversityName(operator orm.Operator[string]) orm.WhereCondition[models.University] { + return orm.FieldCondition[models.University, string]{ + FieldIdentifier: universityNameFieldID, + Operator: operator, + } +} + +var UniversityPreloadAttributes = orm.NewPreloadCondition[models.University](universityNameFieldID) diff --git a/testintegration/crudServiceCommon.go b/testintegration/crudServiceCommon.go index 4769ac3..1fd6348 100644 --- a/testintegration/crudServiceCommon.go +++ b/testintegration/crudServiceCommon.go @@ -125,3 +125,13 @@ func (ts *CRUDServiceCommonIntTestSuite) createPhone(name string, brand models.B return entity } + +func (ts *CRUDServiceCommonIntTestSuite) createUniversity(name string) *models.University { + entity := &models.University{ + Name: name, + } + err := ts.db.Create(entity).Error + ts.Nil(err) + + return entity +} diff --git a/testintegration/db_models.go b/testintegration/db_models.go index 2c24b63..fdbb11e 100644 --- a/testintegration/db_models.go +++ b/testintegration/db_models.go @@ -22,6 +22,10 @@ var ListOfTables = []any{ models.Bicycle{}, models.Brand{}, models.Phone{}, + models.ParentParent{}, + models.Parent1{}, + models.Parent2{}, + models.Child{}, } func GetModels() orm.GetModelsResult { diff --git a/testintegration/join_conditions_test.go b/testintegration/join_conditions_test.go index 71d2103..b783339 100644 --- a/testintegration/join_conditions_test.go +++ b/testintegration/join_conditions_test.go @@ -16,7 +16,7 @@ type JoinConditionsIntTestSuite struct { crudCityService orm.CRUDService[models.City, orm.UUID] crudEmployeeService orm.CRUDService[models.Employee, orm.UUID] crudBicycleService orm.CRUDService[models.Bicycle, orm.UUID] - crudPhoneService orm.CRUDService[models.Phone, uint] + crudPhoneService orm.CRUDService[models.Phone, orm.UIntID] } func NewJoinConditionsIntTestSuite( @@ -27,7 +27,7 @@ func NewJoinConditionsIntTestSuite( crudCityService orm.CRUDService[models.City, orm.UUID], crudEmployeeService orm.CRUDService[models.Employee, orm.UUID], crudBicycleService orm.CRUDService[models.Bicycle, orm.UUID], - crudPhoneService orm.CRUDService[models.Phone, uint], + crudPhoneService orm.CRUDService[models.Phone, orm.UIntID], ) *JoinConditionsIntTestSuite { return &JoinConditionsIntTestSuite{ CRUDServiceCommonIntTestSuite: CRUDServiceCommonIntTestSuite{ @@ -354,7 +354,7 @@ func (ts *JoinConditionsIntTestSuite) TestConditionThatJoinsMultipleTimes() { EqualList(&ts.Suite, []*models.Sale{match}, entities) } -func (ts *WhereConditionsIntTestSuite) TestJoinWithUnsafeCondition() { +func (ts *JoinConditionsIntTestSuite) TestJoinWithUnsafeCondition() { product1 := ts.createProduct("", 0, 0.0, false, nil) product2 := ts.createProduct("", 0, 0.0, false, nil) @@ -370,7 +370,7 @@ func (ts *WhereConditionsIntTestSuite) TestJoinWithUnsafeCondition() { entities, err := ts.crudSaleService.Query( conditions.SaleSeller( conditions.SellerCompany( - orm.NewUnsafeCondition[models.Company]("%s.name = sellers_sales.name", []any{}), + orm.NewUnsafeCondition[models.Company]("%s.name = Seller.name", []any{}), ), ), ) @@ -379,7 +379,7 @@ func (ts *WhereConditionsIntTestSuite) TestJoinWithUnsafeCondition() { EqualList(&ts.Suite, []*models.Sale{match}, entities) } -func (ts *WhereConditionsIntTestSuite) TestJoinWithEmptyConnectionConditionMakesNothing() { +func (ts *JoinConditionsIntTestSuite) TestJoinWithEmptyConnectionConditionMakesNothing() { product1 := ts.createProduct("", 1, 0.0, false, nil) product2 := ts.createProduct("", 2, 0.0, false, nil) @@ -396,7 +396,7 @@ func (ts *WhereConditionsIntTestSuite) TestJoinWithEmptyConnectionConditionMakes EqualList(&ts.Suite, []*models.Sale{match1, match2}, entities) } -func (ts *WhereConditionsIntTestSuite) TestJoinWithEmptyContainerConditionReturnsError() { +func (ts *JoinConditionsIntTestSuite) TestJoinWithEmptyContainerConditionReturnsError() { _, err := ts.crudSaleService.Query( conditions.SaleProduct( orm.Not[models.Product](), diff --git a/testintegration/models/badaas-orm.go b/testintegration/models/badaas-orm.go new file mode 100644 index 0000000..d71a13c --- /dev/null +++ b/testintegration/models/badaas-orm.go @@ -0,0 +1,47 @@ +// Code generated by badaas-cli v0.0.0, DO NOT EDIT. +package models + +import orm "github.com/ditrit/badaas/orm" + +func (m Bicycle) GetOwner() (*Person, error) { + return orm.VerifyStructLoaded[Person](&m.Owner) +} +func (m Child) GetParent1() (*Parent1, error) { + return orm.VerifyStructLoaded[Parent1](&m.Parent1) +} +func (m Child) GetParent2() (*Parent2, error) { + return orm.VerifyStructLoaded[Parent2](&m.Parent2) +} +func (m City) GetCountry() (*Country, error) { + return orm.VerifyPointerWithIDLoaded[Country](m.CountryID, m.Country) +} +func (m Company) GetSellers() ([]Seller, error) { + return orm.VerifyCollectionLoaded[Seller](m.Sellers) +} +func (m Country) GetCapital() (*City, error) { + return orm.VerifyStructLoaded[City](&m.Capital) +} +func (m Employee) GetBoss() (*Employee, error) { + return orm.VerifyPointerLoaded[Employee](m.BossID, m.Boss) +} +func (m Parent1) GetParentParent() (*ParentParent, error) { + return orm.VerifyStructLoaded[ParentParent](&m.ParentParent) +} +func (m Parent2) GetParentParent() (*ParentParent, error) { + return orm.VerifyStructLoaded[ParentParent](&m.ParentParent) +} +func (m Phone) GetBrand() (*Brand, error) { + return orm.VerifyStructLoaded[Brand](&m.Brand) +} +func (m Sale) GetProduct() (*Product, error) { + return orm.VerifyStructLoaded[Product](&m.Product) +} +func (m Sale) GetSeller() (*Seller, error) { + return orm.VerifyPointerLoaded[Seller](m.SellerID, m.Seller) +} +func (m Seller) GetCompany() (*Company, error) { + return orm.VerifyPointerLoaded[Company](m.CompanyID, m.Company) +} +func (m Seller) GetUniversity() (*University, error) { + return orm.VerifyPointerLoaded[University](m.UniversityID, m.University) +} diff --git a/testintegration/models/models.go b/testintegration/models/models.go index a7d3f60..8b2f91f 100644 --- a/testintegration/models/models.go +++ b/testintegration/models/models.go @@ -25,7 +25,11 @@ type Company struct { orm.UUIDModel Name string - Sellers []Seller // Company HasMany Sellers (Company 0..1 -> 0..* Seller) + Sellers *[]Seller // Company HasMany Sellers (Company 0..1 -> 0..* Seller) +} + +func (m Company) Equal(other Company) bool { + return m.ID == other.ID } type MultiString []string @@ -83,11 +87,25 @@ func (m Product) Equal(other Product) bool { return m.ID == other.ID } +type University struct { + orm.UUIDModel + + Name string +} + +func (m University) Equal(other University) bool { + return m.ID == other.ID +} + type Seller struct { orm.UUIDModel Name string + Company *Company CompanyID *orm.UUID // Company HasMany Sellers (Company 0..1 -> 0..* Seller) + + University *University + UniversityID *orm.UUID } type Sale struct { @@ -100,7 +118,7 @@ type Sale struct { Product Product ProductID orm.UUID - // Sale HasOne Seller (Sale 0..* -> 0..1 Seller) + // Sale belongsTo Seller (Sale 0..* -> 0..1 Seller) Seller *Seller SellerID *orm.UUID } @@ -124,6 +142,7 @@ type City struct { orm.UUIDModel Name string + Country *Country CountryID orm.UUID // Country HasOne City (Country 1 -> 1 City) } @@ -180,3 +199,49 @@ type Phone struct { func (m Phone) Equal(other Phone) bool { return m.Name == other.Name } + +type ParentParent struct { + orm.UUIDModel + + Name string +} + +func (m ParentParent) Equal(other ParentParent) bool { + return m.ID == other.ID +} + +type Parent1 struct { + orm.UUIDModel + + ParentParent ParentParent + ParentParentID orm.UUID +} + +func (m Parent1) Equal(other Parent1) bool { + return m.ID == other.ID +} + +type Parent2 struct { + orm.UUIDModel + + ParentParent ParentParent + ParentParentID orm.UUID +} + +func (m Parent2) Equal(other Parent2) bool { + return m.ID == other.ID +} + +type Child struct { + orm.UUIDModel + + Parent1 Parent1 + Parent1ID orm.UUID + + Parent2 Parent2 + Parent2ID orm.UUID +} + +func (m Child) Equal(other Child) bool { + return m.ID == other.ID +} diff --git a/testintegration/orm_test.go b/testintegration/orm_test.go index 67953f6..1a11c6e 100644 --- a/testintegration/orm_test.go +++ b/testintegration/orm_test.go @@ -50,6 +50,7 @@ func TestBaDaaSORM(t *testing.T) { // create crud services for models orm.GetCRUDServiceModule[models.Seller](), + orm.GetCRUDServiceModule[models.Company](), orm.GetCRUDServiceModule[models.Product](), orm.GetCRUDServiceModule[models.Sale](), orm.GetCRUDServiceModule[models.City](), @@ -58,11 +59,13 @@ func TestBaDaaSORM(t *testing.T) { orm.GetCRUDServiceModule[models.Bicycle](), orm.GetCRUDServiceModule[models.Phone](), orm.GetCRUDServiceModule[models.Brand](), + orm.GetCRUDServiceModule[models.Child](), // create test suites fx.Provide(NewCRUDRepositoryIntTestSuite), fx.Provide(NewWhereConditionsIntTestSuite), fx.Provide(NewJoinConditionsIntTestSuite), + fx.Provide(NewPreloadConditionsIntTestSuite), fx.Provide(NewOperatorsIntTestSuite), // run tests @@ -74,6 +77,7 @@ func runORMTestSuites( tsCRUDRepository *CRUDRepositoryIntTestSuite, tsWhereConditions *WhereConditionsIntTestSuite, tsJoinConditions *JoinConditionsIntTestSuite, + tsPreloadConditions *PreloadConditionsIntTestSuite, tsOperators *OperatorsIntTestSuite, db *gorm.DB, shutdowner fx.Shutdowner, @@ -81,6 +85,7 @@ func runORMTestSuites( suite.Run(tGlobal, tsCRUDRepository) suite.Run(tGlobal, tsWhereConditions) suite.Run(tGlobal, tsJoinConditions) + suite.Run(tGlobal, tsPreloadConditions) suite.Run(tGlobal, tsOperators) shutdowner.Shutdown() diff --git a/testintegration/preload_conditions_test.go b/testintegration/preload_conditions_test.go new file mode 100644 index 0000000..791d217 --- /dev/null +++ b/testintegration/preload_conditions_test.go @@ -0,0 +1,887 @@ +package testintegration + +import ( + "errors" + + "github.com/elliotchance/pie/v2" + "gorm.io/gorm" + "gotest.tools/assert" + + "github.com/ditrit/badaas/orm" + "github.com/ditrit/badaas/testintegration/conditions" + "github.com/ditrit/badaas/testintegration/models" + "github.com/ditrit/badaas/utils" +) + +type PreloadConditionsIntTestSuite struct { + CRUDServiceCommonIntTestSuite + crudSaleService orm.CRUDService[models.Sale, orm.UUID] + crudCompanyService orm.CRUDService[models.Company, orm.UUID] + crudSellerService orm.CRUDService[models.Seller, orm.UUID] + crudCountryService orm.CRUDService[models.Country, orm.UUID] + crudCityService orm.CRUDService[models.City, orm.UUID] + crudEmployeeService orm.CRUDService[models.Employee, orm.UUID] + crudPhoneService orm.CRUDService[models.Phone, orm.UIntID] + crudChildService orm.CRUDService[models.Child, orm.UUID] +} + +func NewPreloadConditionsIntTestSuite( + db *gorm.DB, + crudSaleService orm.CRUDService[models.Sale, orm.UUID], + crudCompanyService orm.CRUDService[models.Company, orm.UUID], + crudSellerService orm.CRUDService[models.Seller, orm.UUID], + crudCountryService orm.CRUDService[models.Country, orm.UUID], + crudCityService orm.CRUDService[models.City, orm.UUID], + crudEmployeeService orm.CRUDService[models.Employee, orm.UUID], + crudPhoneService orm.CRUDService[models.Phone, orm.UIntID], + crudChildService orm.CRUDService[models.Child, orm.UUID], +) *PreloadConditionsIntTestSuite { + return &PreloadConditionsIntTestSuite{ + CRUDServiceCommonIntTestSuite: CRUDServiceCommonIntTestSuite{ + db: db, + }, + crudSaleService: crudSaleService, + crudCompanyService: crudCompanyService, + crudSellerService: crudSellerService, + crudCountryService: crudCountryService, + crudCityService: crudCityService, + crudEmployeeService: crudEmployeeService, + crudPhoneService: crudPhoneService, + crudChildService: crudChildService, + } +} + +func (ts *PreloadConditionsIntTestSuite) TestNoPreloadReturnsErrorOnGetRelation() { + product := ts.createProduct("a_string", 1, 0.0, false, nil) + seller := ts.createSeller("franco", nil) + sale := ts.createSale(0, product, seller) + + entities, err := ts.crudSaleService.Query() + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Sale{sale}, entities) + + saleLoaded := entities[0] + + ts.False(saleLoaded.Product.IsLoaded()) + _, err = saleLoaded.GetProduct() + ts.ErrorIs(err, orm.ErrRelationNotLoaded) + + ts.Nil(saleLoaded.Seller) // is nil but we cant determine why directly (not loaded or really null) + _, err = saleLoaded.GetSeller() // GetSeller give us that information + ts.ErrorIs(err, orm.ErrRelationNotLoaded) +} + +func (ts *PreloadConditionsIntTestSuite) TestNoPreloadWhenItsNullKnowsItsReallyNull() { + product := ts.createProduct("a_string", 1, 0.0, false, nil) + sale := ts.createSale(10, product, nil) + + entities, err := ts.crudSaleService.Query() + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Sale{sale}, entities) + + saleLoaded := entities[0] + + ts.False(saleLoaded.Product.IsLoaded()) + _, err = saleLoaded.GetProduct() + ts.ErrorIs(err, orm.ErrRelationNotLoaded) + + ts.Nil(saleLoaded.Seller) // is nil but we cant determine why directly (not loaded or really null) + saleSeller, err := saleLoaded.GetSeller() // GetSeller give us that information + ts.Nil(err) + ts.Nil(saleSeller) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadWithoutWhereConditionDoesNotFilter() { + product1 := ts.createProduct("a_string", 1, 0.0, false, nil) + product2 := ts.createProduct("", 2, 0.0, false, nil) + + seller1 := ts.createSeller("franco", nil) + + withSeller := ts.createSale(0, product1, seller1) + withoutSeller := ts.createSale(0, product2, nil) + + entities, err := ts.crudSaleService.Query( + conditions.SalePreloadSeller, + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Sale{withSeller, withoutSeller}, entities) + ts.True(pie.Any(entities, func(sale *models.Sale) bool { + saleSeller, err := sale.GetSeller() + return err == nil && saleSeller != nil && saleSeller.Equal(*seller1) + })) + ts.True(pie.Any(entities, func(sale *models.Sale) bool { + return sale.Seller == nil + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadNullableAtSecondLevel() { + product1 := ts.createProduct("a_string", 1, 0.0, false, nil) + product2 := ts.createProduct("", 2, 0.0, false, nil) + + company := ts.createCompany("ditrit") + + withCompany := ts.createSeller("with", company) + withoutCompany := ts.createSeller("without", nil) + + sale1 := ts.createSale(0, product1, withoutCompany) + sale2 := ts.createSale(0, product2, withCompany) + + entities, err := ts.crudSaleService.Query( + conditions.SaleSeller( + conditions.SellerPreloadCompany, + ), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Sale{sale1, sale2}, entities) + ts.True(pie.Any(entities, func(sale *models.Sale) bool { + saleSeller, err := sale.GetSeller() + if err != nil { + return false + } + + sellerCompany, err := saleSeller.GetCompany() + return err == nil && saleSeller.Name == "with" && sellerCompany != nil && sellerCompany.Equal(*company) + })) + ts.True(pie.Any(entities, func(sale *models.Sale) bool { + saleSeller, err := sale.GetSeller() + if err != nil { + return false + } + + sellerCompany, err := saleSeller.GetCompany() + return err == nil && saleSeller.Name == "without" && sellerCompany == nil + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadAtSecondLevelWorksWithManualPreload() { + product1 := ts.createProduct("a_string", 1, 0.0, false, nil) + product2 := ts.createProduct("", 2, 0.0, false, nil) + + company := ts.createCompany("ditrit") + + withCompany := ts.createSeller("with", company) + withoutCompany := ts.createSeller("without", nil) + + sale1 := ts.createSale(0, product1, withoutCompany) + sale2 := ts.createSale(0, product2, withCompany) + + entities, err := ts.crudSaleService.Query( + conditions.SaleSeller( + conditions.SellerPreloadAttributes, + conditions.SellerPreloadCompany, + ), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Sale{sale1, sale2}, entities) + ts.True(pie.Any(entities, func(sale *models.Sale) bool { + saleSeller, err := sale.GetSeller() + if err != nil { + return false + } + + sellerCompany, err := saleSeller.GetCompany() + return err == nil && saleSeller.Name == "with" && sellerCompany != nil && sellerCompany.Equal(*company) + })) + ts.True(pie.Any(entities, func(sale *models.Sale) bool { + saleSeller, err := sale.GetSeller() + if err != nil { + return false + } + + sellerCompany, err := saleSeller.GetCompany() + return err == nil && saleSeller.Name == "without" && sellerCompany == nil + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestNoPreloadNullableAtSecondLevel() { + product1 := ts.createProduct("a_string", 1, 0.0, false, nil) + product2 := ts.createProduct("", 2, 0.0, false, nil) + + company := ts.createCompany("ditrit") + + withCompany := ts.createSeller("with", company) + withoutCompany := ts.createSeller("without", nil) + + sale1 := ts.createSale(0, product1, withoutCompany) + sale2 := ts.createSale(0, product2, withCompany) + + entities, err := ts.crudSaleService.Query( + conditions.SalePreloadSeller, + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Sale{sale1, sale2}, entities) + ts.True(pie.Any(entities, func(sale *models.Sale) bool { + saleSeller, err := sale.GetSeller() + if err != nil { + return false + } + + // the not null one is not loaded + sellerCompany, err := saleSeller.GetCompany() + return errors.Is(err, orm.ErrRelationNotLoaded) && sellerCompany == nil + })) + ts.True(pie.Any(entities, func(sale *models.Sale) bool { + saleSeller, err := sale.GetSeller() + if err != nil { + return false + } + + // we can be sure the null one is null + sellerCompany, err := saleSeller.GetCompany() + return err == nil && sellerCompany == nil + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadWithoutWhereConditionDoesNotFilterAtSecondLevel() { + product1 := ts.createProduct("a_string", 1, 0.0, false, nil) + product2 := ts.createProduct("", 2, 0.0, false, nil) + + seller1 := ts.createSeller("franco", nil) + + withSeller := ts.createSale(0, product1, seller1) + withoutSeller := ts.createSale(0, product2, nil) + + entities, err := ts.crudSaleService.Query( + conditions.SaleSeller( + conditions.SellerPreloadCompany, + ), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Sale{withSeller, withoutSeller}, entities) + ts.True(pie.Any(entities, func(sale *models.Sale) bool { + saleSeller, err := sale.GetSeller() + if saleSeller == nil || err != nil { + return false + } + + sellerCompany, err := saleSeller.GetCompany() + + return err == nil && saleSeller.Equal(*seller1) && sellerCompany == nil + })) + ts.True(pie.Any(entities, func(sale *models.Sale) bool { + // in this case sale.Seller will also be nil + // but we can now it's really null in the db because err is nil + saleSeller, err := sale.GetSeller() + return err == nil && saleSeller == nil + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadUIntModel() { + brand1 := ts.createBrand("google") + brand2 := ts.createBrand("apple") + + phone1 := ts.createPhone("pixel", *brand1) + phone2 := ts.createPhone("iphone", *brand2) + + entities, err := ts.crudPhoneService.Query( + conditions.PhonePreloadBrand, + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Phone{phone1, phone2}, entities) + ts.True(pie.Any(entities, func(phone *models.Phone) bool { + phoneBrand, err := phone.GetBrand() + return err == nil && phoneBrand.Equal(*brand1) + })) + ts.True(pie.Any(entities, func(phone *models.Phone) bool { + phoneBrand, err := phone.GetBrand() + return err == nil && phoneBrand.Equal(*brand2) + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadWithWhereConditionFilters() { + product1 := ts.createProduct("a_string", 1, 0.0, false, nil) + product1.EmbeddedInt = 1 + product1.GormEmbedded.Int = 2 + err := ts.db.Save(product1).Error + ts.Nil(err) + + product2 := ts.createProduct("", 2, 0.0, false, nil) + + match := ts.createSale(0, product1, nil) + ts.createSale(0, product2, nil) + + entities, err := ts.crudSaleService.Query( + conditions.SaleProduct( + conditions.ProductPreloadAttributes, + conditions.ProductInt(orm.Eq(1)), + ), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Sale{match}, entities) + saleProduct, err := entities[0].GetProduct() + ts.Nil(err) + assert.DeepEqual(ts.T(), product1, saleProduct) + ts.Equal("a_string", saleProduct.String) + ts.Equal(1, saleProduct.EmbeddedInt) + ts.Equal(2, saleProduct.GormEmbedded.Int) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadOneToOne() { + capital1 := models.City{ + Name: "Buenos Aires", + } + capital2 := models.City{ + Name: "Paris", + } + + country1 := ts.createCountry("Argentina", capital1) + country2 := ts.createCountry("France", capital2) + + entities, err := ts.crudCityService.Query( + conditions.CityPreloadCountry, + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.City{&capital1, &capital2}, entities) + ts.True(pie.Any(entities, func(city *models.City) bool { + cityCountry, err := city.GetCountry() + if err != nil { + return false + } + + return cityCountry.Equal(*country1) + })) + ts.True(pie.Any(entities, func(city *models.City) bool { + cityCountry, err := city.GetCountry() + if err != nil { + return false + } + + return cityCountry.Equal(*country2) + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestNoPreloadOneToOne() { + capital1 := models.City{ + Name: "Buenos Aires", + } + + ts.createCountry("Argentina", capital1) + + entities, err := ts.crudCityService.Query() + ts.Nil(err) + + EqualList(&ts.Suite, []*models.City{&capital1}, entities) + _, err = entities[0].GetCountry() + ts.ErrorIs(err, orm.ErrRelationNotLoaded) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadOneToOneReversed() { + capital1 := models.City{ + Name: "Buenos Aires", + } + capital2 := models.City{ + Name: "Paris", + } + + country1 := ts.createCountry("Argentina", capital1) + country2 := ts.createCountry("France", capital2) + + entities, err := ts.crudCountryService.Query( + conditions.CountryPreloadCapital, + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Country{country1, country2}, entities) + ts.True(pie.Any(entities, func(country *models.Country) bool { + countryCapital, err := country.GetCapital() + return err == nil && countryCapital.Equal(capital1) + })) + ts.True(pie.Any(entities, func(country *models.Country) bool { + countryCapital, err := country.GetCapital() + return err == nil && countryCapital.Equal(capital2) + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadHasManyReversed() { + company1 := ts.createCompany("ditrit") + company2 := ts.createCompany("orness") + + seller1 := ts.createSeller("franco", company1) + seller2 := ts.createSeller("agustin", company2) + + entities, err := ts.crudSellerService.Query( + conditions.SellerPreloadCompany, + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Seller{seller1, seller2}, entities) + ts.True(pie.Any(entities, func(seller *models.Seller) bool { + sellerCompany, err := seller.GetCompany() + return err == nil && sellerCompany.Equal(*company1) + })) + ts.True(pie.Any(entities, func(seller *models.Seller) bool { + sellerCompany, err := seller.GetCompany() + return err == nil && sellerCompany.Equal(*company2) + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadSelfReferential() { + boss1 := &models.Employee{ + Name: "Xavier", + } + + employee1 := ts.createEmployee("franco", boss1) + employee2 := ts.createEmployee("pierre", nil) + + entities, err := ts.crudEmployeeService.Query( + conditions.EmployeePreloadBoss, + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Employee{boss1, employee1, employee2}, entities) + + ts.True(pie.Any(entities, func(employee *models.Employee) bool { + employeeBoss, err := employee.GetBoss() + return err == nil && employeeBoss != nil && employeeBoss.Equal(*boss1) + })) + ts.True(pie.Any(entities, func(employee *models.Employee) bool { + employeeBoss, err := employee.GetBoss() + return err == nil && employeeBoss == nil + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadSelfReferentialAtSecondLevel() { + bossBoss := &models.Employee{ + Name: "Xavier", + } + boss := &models.Employee{ + Name: "Vincent", + Boss: bossBoss, + } + employee := ts.createEmployee("franco", boss) + + entities, err := ts.crudEmployeeService.Query( + conditions.EmployeeBoss( + conditions.EmployeeBoss( + conditions.EmployeePreloadAttributes, + ), + ), + conditions.EmployeeName(orm.Eq("franco")), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Employee{employee}, entities) + + bossLoaded, err := entities[0].GetBoss() + ts.Nil(err) + ts.True(bossLoaded.Equal(*boss)) + + bossBossLoaded, err := bossLoaded.GetBoss() + ts.Nil(err) + ts.True(bossBossLoaded.Equal(*bossBoss)) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadDifferentEntitiesWithConditions() { + product1 := ts.createProduct("", 1, 0.0, false, nil) + product2 := ts.createProduct("", 2, 0.0, false, nil) + + seller1 := ts.createSeller("franco", nil) + seller2 := ts.createSeller("agustin", nil) + + match := ts.createSale(0, product1, seller1) + ts.createSale(0, product2, seller2) + ts.createSale(0, product1, seller2) + ts.createSale(0, product2, seller1) + + entities, err := ts.crudSaleService.Query( + conditions.SaleProduct( + conditions.ProductPreloadAttributes, + conditions.ProductInt(orm.Eq(1)), + ), + conditions.SaleSeller( + conditions.SellerPreloadAttributes, + conditions.SellerName(orm.Eq("franco")), + ), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Sale{match}, entities) + saleProduct, err := entities[0].GetProduct() + ts.Nil(err) + assert.DeepEqual(ts.T(), product1, saleProduct) + + saleSeller, err := entities[0].GetSeller() + ts.Nil(err) + assert.DeepEqual(ts.T(), seller1, saleSeller) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadDifferentEntitiesWithoutConditions() { + parentParent := &models.ParentParent{} + err := ts.db.Create(parentParent).Error + ts.Nil(err) + + parent1 := &models.Parent1{ParentParent: *parentParent} + err = ts.db.Create(parent1).Error + ts.Nil(err) + + parent2 := &models.Parent2{ParentParent: *parentParent} + err = ts.db.Create(parent2).Error + ts.Nil(err) + + child := &models.Child{Parent1: *parent1, Parent2: *parent2} + err = ts.db.Create(child).Error + ts.Nil(err) + + entities, err := ts.crudChildService.Query( + conditions.ChildPreloadParent1, + conditions.ChildPreloadParent2, + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Child{child}, entities) + childParent1, err := entities[0].GetParent1() + ts.Nil(err) + assert.DeepEqual(ts.T(), parent1, childParent1) + + childParent2, err := entities[0].GetParent2() + ts.Nil(err) + assert.DeepEqual(ts.T(), parent2, childParent2) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadRelations() { + parentParent := &models.ParentParent{} + err := ts.db.Create(parentParent).Error + ts.Nil(err) + + parent1 := &models.Parent1{ParentParent: *parentParent} + err = ts.db.Create(parent1).Error + ts.Nil(err) + + parent2 := &models.Parent2{ParentParent: *parentParent} + err = ts.db.Create(parent2).Error + ts.Nil(err) + + child := &models.Child{Parent1: *parent1, Parent2: *parent2} + err = ts.db.Create(child).Error + ts.Nil(err) + + entities, err := ts.crudChildService.Query( + conditions.ChildPreloadRelations..., + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Child{child}, entities) + childParent1, err := entities[0].GetParent1() + ts.Nil(err) + assert.DeepEqual(ts.T(), parent1, childParent1) + + childParent2, err := entities[0].GetParent2() + ts.Nil(err) + assert.DeepEqual(ts.T(), parent2, childParent2) +} + +func (ts *PreloadConditionsIntTestSuite) TestJoinMultipleTimesAndPreloadWithoutCondition() { + parentParent := &models.ParentParent{} + err := ts.db.Create(parentParent).Error + ts.Nil(err) + + parent1 := &models.Parent1{ParentParent: *parentParent} + err = ts.db.Create(parent1).Error + ts.Nil(err) + + parent2 := &models.Parent2{ParentParent: *parentParent} + err = ts.db.Create(parent2).Error + ts.Nil(err) + + child := &models.Child{Parent1: *parent1, Parent2: *parent2} + err = ts.db.Create(child).Error + ts.Nil(err) + + entities, err := ts.crudChildService.Query( + conditions.ChildParent1( + conditions.Parent1PreloadAttributes, + conditions.Parent1PreloadParentParent, + ), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Child{child}, entities) + childParent1, err := entities[0].GetParent1() + ts.Nil(err) + assert.DeepEqual(ts.T(), parent1, childParent1) + + childParentParent, err := childParent1.GetParentParent() + ts.Nil(err) + assert.DeepEqual(ts.T(), parentParent, childParentParent) +} + +func (ts *PreloadConditionsIntTestSuite) TestJoinMultipleTimesAndPreloadWithCondition() { + parentParent1 := &models.ParentParent{ + Name: "parentParent1", + } + err := ts.db.Create(parentParent1).Error + ts.Nil(err) + + parent11 := &models.Parent1{ParentParent: *parentParent1} + err = ts.db.Create(parent11).Error + ts.Nil(err) + + parent21 := &models.Parent2{ParentParent: *parentParent1} + err = ts.db.Create(parent21).Error + ts.Nil(err) + + child1 := &models.Child{Parent1: *parent11, Parent2: *parent21} + err = ts.db.Create(child1).Error + ts.Nil(err) + + parentParent2 := &models.ParentParent{} + err = ts.db.Create(parentParent2).Error + ts.Nil(err) + + parent12 := &models.Parent1{ParentParent: *parentParent2} + err = ts.db.Create(parent12).Error + ts.Nil(err) + + parent22 := &models.Parent2{ParentParent: *parentParent2} + err = ts.db.Create(parent22).Error + ts.Nil(err) + + child2 := &models.Child{Parent1: *parent12, Parent2: *parent22} + err = ts.db.Create(child2).Error + ts.Nil(err) + + entities, err := ts.crudChildService.Query( + conditions.ChildParent1( + conditions.Parent1PreloadAttributes, + conditions.Parent1ParentParent( + conditions.ParentParentPreloadAttributes, + conditions.ParentParentName(orm.Eq("parentParent1")), + ), + ), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Child{child1}, entities) + childParent1, err := entities[0].GetParent1() + ts.Nil(err) + assert.DeepEqual(ts.T(), parent11, childParent1) + + childParentParent, err := childParent1.GetParentParent() + ts.Nil(err) + assert.DeepEqual(ts.T(), parentParent1, childParentParent) +} + +func (ts *PreloadConditionsIntTestSuite) TestJoinMultipleTimesAndPreloadDiamond() { + parentParent := &models.ParentParent{} + err := ts.db.Create(parentParent).Error + ts.Nil(err) + + parent1 := &models.Parent1{ParentParent: *parentParent} + err = ts.db.Create(parent1).Error + ts.Nil(err) + + parent2 := &models.Parent2{ParentParent: *parentParent} + err = ts.db.Create(parent2).Error + ts.Nil(err) + + child := &models.Child{Parent1: *parent1, Parent2: *parent2} + err = ts.db.Create(child).Error + ts.Nil(err) + + entities, err := ts.crudChildService.Query( + conditions.ChildParent1( + conditions.Parent1PreloadParentParent, + ), + conditions.ChildParent2( + conditions.Parent2PreloadParentParent, + ), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Child{child}, entities) + childParent1, err := entities[0].GetParent1() + ts.Nil(err) + assert.DeepEqual(ts.T(), parent1, childParent1) + + childParent2, err := entities[0].GetParent2() + ts.Nil(err) + assert.DeepEqual(ts.T(), parent2, childParent2) + + childParent1Parent, err := childParent1.GetParentParent() + ts.Nil(err) + assert.DeepEqual(ts.T(), parentParent, childParent1Parent) + + childParent2Parent, err := childParent2.GetParentParent() + ts.Nil(err) + assert.DeepEqual(ts.T(), parentParent, childParent2Parent) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadCollection() { + company := ts.createCompany("ditrit") + seller1 := ts.createSeller("1", company) + seller2 := ts.createSeller("2", company) + + entities, err := ts.crudCompanyService.Query( + conditions.CompanyPreloadSellers(), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Company{company}, entities) + companySellers, err := entities[0].GetSellers() + ts.Nil(err) + EqualList(&ts.Suite, []models.Seller{*seller1, *seller2}, companySellers) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadEmptyCollection() { + company := ts.createCompany("ditrit") + + entities, err := ts.crudCompanyService.Query( + conditions.CompanyPreloadSellers(), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Company{company}, entities) + companySellers, err := entities[0].GetSellers() + ts.Nil(err) + EqualList(&ts.Suite, []models.Seller{}, companySellers) +} + +func (ts *PreloadConditionsIntTestSuite) TestNoPreloadCollection() { + company := ts.createCompany("ditrit") + + entities, err := ts.crudCompanyService.Query() + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Company{company}, entities) + _, err = entities[0].GetSellers() + ts.ErrorIs(err, orm.ErrRelationNotLoaded) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadListAndNestedAttributes() { + company := ts.createCompany("ditrit") + + university1 := ts.createUniversity("uni1") + seller1 := ts.createSeller("1", company) + seller1.University = university1 + err := ts.db.Save(seller1).Error + ts.Nil(err) + + university2 := ts.createUniversity("uni1") + seller2 := ts.createSeller("2", company) + seller2.University = university2 + err = ts.db.Save(seller2).Error + ts.Nil(err) + + entities, err := ts.crudCompanyService.Query( + conditions.CompanyPreloadSellers( + conditions.SellerPreloadUniversity, + ), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Company{company}, entities) + companySellers, err := entities[0].GetSellers() + ts.Nil(err) + EqualList(&ts.Suite, []models.Seller{*seller1, *seller2}, companySellers) + + ts.True(pie.Any(*entities[0].Sellers, func(seller models.Seller) bool { + sellerUniversity, err := seller.GetUniversity() + return err == nil && sellerUniversity.Equal(*university1) + })) + ts.True(pie.Any(*entities[0].Sellers, func(seller models.Seller) bool { + sellerUniversity, err := seller.GetUniversity() + return err == nil && sellerUniversity.Equal(*university2) + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadMultipleListsAndNestedAttributes() { + company1 := ts.createCompany("ditrit") + company2 := ts.createCompany("orness") + + university1 := ts.createUniversity("uni1") + seller1 := ts.createSeller("1", company1) + seller1.University = university1 + err := ts.db.Save(seller1).Error + ts.Nil(err) + + university2 := ts.createUniversity("uni1") + seller2 := ts.createSeller("2", company1) + seller2.University = university2 + err = ts.db.Save(seller2).Error + ts.Nil(err) + + seller3 := ts.createSeller("3", company2) + seller3.University = university1 + err = ts.db.Save(seller3).Error + ts.Nil(err) + + seller4 := ts.createSeller("4", company2) + seller4.University = university2 + err = ts.db.Save(seller4).Error + ts.Nil(err) + + entities, err := ts.crudCompanyService.Query( + conditions.CompanyPreloadSellers( + conditions.SellerPreloadUniversity, + ), + ) + ts.Nil(err) + + EqualList(&ts.Suite, []*models.Company{company1, company2}, entities) + + company1Loaded := *utils.FindFirst(entities, func(company *models.Company) bool { + return company.Equal(*company1) + }) + company2Loaded := *utils.FindFirst(entities, func(company *models.Company) bool { + return company.Equal(*company2) + }) + + company1Sellers, err := company1Loaded.GetSellers() + ts.Nil(err) + EqualList(&ts.Suite, []models.Seller{*seller1, *seller2}, company1Sellers) + + var sellerUniversity *models.University + + ts.True(pie.Any(*company1Loaded.Sellers, func(seller models.Seller) bool { + sellerUniversity, err = seller.GetUniversity() + return err == nil && sellerUniversity.Equal(*university1) + })) + ts.True(pie.Any(*company1Loaded.Sellers, func(seller models.Seller) bool { + sellerUniversity, err = seller.GetUniversity() + return err == nil && sellerUniversity.Equal(*university2) + })) + + company2Sellers, err := company2Loaded.GetSellers() + ts.Nil(err) + EqualList(&ts.Suite, []models.Seller{*seller3, *seller4}, company2Sellers) + + ts.True(pie.Any(*company2Loaded.Sellers, func(seller models.Seller) bool { + sellerUniversity, err := seller.GetUniversity() + return err == nil && sellerUniversity.Equal(*university1) + })) + ts.True(pie.Any(*company2Loaded.Sellers, func(seller models.Seller) bool { + sellerUniversity, err := seller.GetUniversity() + return err == nil && sellerUniversity.Equal(*university2) + })) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadListAndNestedAttributesWithFiltersReturnsError() { + _, err := ts.crudCompanyService.Query( + conditions.CompanyPreloadSellers( + conditions.SellerUniversity( + conditions.UniversityPreloadAttributes, + conditions.UniversityId(orm.Eq(orm.NilUUID)), + ), + ), + ) + ts.ErrorIs(err, orm.ErrOnlyPreloadsAllowed) +} + +func (ts *PreloadConditionsIntTestSuite) TestPreloadListAndNestedAttributesWithoutPreloadReturnsError() { + _, err := ts.crudCompanyService.Query( + conditions.CompanyPreloadSellers( + conditions.SellerUniversity(), + ), + ) + ts.ErrorIs(err, orm.ErrOnlyPreloadsAllowed) +} diff --git a/testintegration/where_conditions_test.go b/testintegration/where_conditions_test.go index 59888ce..0ec19ab 100644 --- a/testintegration/where_conditions_test.go +++ b/testintegration/where_conditions_test.go @@ -13,14 +13,14 @@ type WhereConditionsIntTestSuite struct { CRUDServiceCommonIntTestSuite crudProductService orm.CRUDService[models.Product, orm.UUID] crudSaleService orm.CRUDService[models.Sale, orm.UUID] - crudBrandService orm.CRUDService[models.Brand, uint] + crudBrandService orm.CRUDService[models.Brand, orm.UIntID] } func NewWhereConditionsIntTestSuite( db *gorm.DB, crudProductService orm.CRUDService[models.Product, orm.UUID], crudSaleService orm.CRUDService[models.Sale, orm.UUID], - crudBrandService orm.CRUDService[models.Brand, uint], + crudBrandService orm.CRUDService[models.Brand, orm.UIntID], ) *WhereConditionsIntTestSuite { return &WhereConditionsIntTestSuite{ CRUDServiceCommonIntTestSuite: CRUDServiceCommonIntTestSuite{ @@ -258,7 +258,7 @@ func (ts *WhereConditionsIntTestSuite) TestConditionOfEmbedded() { ts.Nil(err) entities, err := ts.crudProductService.Query( - conditions.ProductEmbeddedInt(orm.Eq(1)), + conditions.ProductToBeEmbeddedEmbeddedInt(orm.Eq(1)), ) ts.Nil(err) diff --git a/utils/slice.go b/utils/slice.go new file mode 100644 index 0000000..2b37095 --- /dev/null +++ b/utils/slice.go @@ -0,0 +1,15 @@ +package utils + +import ( + "github.com/elliotchance/pie/v2" +) + +func FindFirst[T any](ss []T, fn func(value T) bool) *T { + index := pie.FindFirstUsing(ss, fn) + + if index == -1 { + return nil + } + + return &ss[index] +} diff --git a/utils/slice_test.go b/utils/slice_test.go new file mode 100644 index 0000000..df05c09 --- /dev/null +++ b/utils/slice_test.go @@ -0,0 +1,59 @@ +package utils_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ditrit/badaas/utils" +) + +var ( + testResult3 = 33.04 + testResult4 = 0.11 +) + +var findFirstTests = []struct { + ss []float64 + expression func(value float64) bool + expected *float64 +}{ + { + nil, + func(value float64) bool { return value == 1.5 }, + nil, + }, + { + []float64{}, + func(value float64) bool { return value == 0.1 }, + nil, + }, + { + []float64{0.0, 1.5, 3.2}, + func(value float64) bool { return value == 9.99 }, + nil, + }, + { + []float64{5.4, 6.98, 4.987, 33.04}, + func(value float64) bool { return value == 33.04 }, + &testResult3, + }, + { + []float64{9.0, 0.11, 150.44, 33.04}, + func(value float64) bool { return value == 0.11 }, + &testResult4, + }, +} + +func TestFindFirst(t *testing.T) { + for _, test := range findFirstTests { + t.Run("", func(t *testing.T) { + result := utils.FindFirst(test.ss, test.expression) + if result == nil { + assert.Nil(t, test.expected) + } else { + assert.Equal(t, *test.expected, *result) + } + }) + } +}