diff --git a/condition/collection.go b/condition/collection.go index 324843c..178c71e 100644 --- a/condition/collection.go +++ b/condition/collection.go @@ -1,6 +1,8 @@ package condition import ( + "github.com/elliotchance/pie/v2" + "github.com/FrancoLiberali/cql/model" ) @@ -18,33 +20,37 @@ func (collection Collection[TObject, TAttribute]) Preload(nestedPreloads ...Join } // Any generates a condition that is true if at least one model in the collection fulfills the conditions -func (collection Collection[TObject, TAttribute]) Any(conditions ...WhereCondition[TAttribute]) WhereCondition[TObject] { - return existsCondition[TObject, TAttribute]{ - Conditions: conditions, - RelationField: collection.name, - T1Field: collection.t1Field, - T2Field: collection.t2Field, - } +func (collection Collection[TObject, TAttribute]) Any( + firstCondition WhereCondition[TAttribute], + conditions ...WhereCondition[TAttribute], +) WhereCondition[TObject] { + return newExistsCondition[TObject, TAttribute](firstCondition, conditions, collection.name, collection.t1Field, collection.t2Field) } // None generates a condition that is true if no model in the collection fulfills the conditions -func (collection Collection[TObject, TAttribute]) None(conditions ...WhereCondition[TAttribute]) WhereCondition[TObject] { - return Not[TObject](existsCondition[TObject, TAttribute]{ - Conditions: conditions, - RelationField: collection.name, - T1Field: collection.t1Field, - T2Field: collection.t2Field, - }) +func (collection Collection[TObject, TAttribute]) None( + firstCondition WhereCondition[TAttribute], + conditions ...WhereCondition[TAttribute], +) WhereCondition[TObject] { + return Not[TObject]( + newExistsCondition[TObject, TAttribute](firstCondition, conditions, collection.name, collection.t1Field, collection.t2Field), + ) } // All generates a condition that is true if all models in the collection fulfill the conditions (or is empty) -func (collection Collection[TObject, TAttribute]) All(conditions ...WhereCondition[TAttribute]) WhereCondition[TObject] { - return Not[TObject](existsCondition[TObject, TAttribute]{ - Conditions: []WhereCondition[TAttribute]{Not[TAttribute](conditions...)}, - RelationField: collection.name, - T1Field: collection.t1Field, - T2Field: collection.t2Field, - }) +func (collection Collection[TObject, TAttribute]) All( + firstCondition WhereCondition[TAttribute], + conditions ...WhereCondition[TAttribute], +) WhereCondition[TObject] { + return Not[TObject]( + newExistsCondition[TObject, TAttribute]( + Not[TAttribute]( + pie.Unshift(conditions, firstCondition)..., + ), + []WhereCondition[TAttribute]{}, + collection.name, collection.t1Field, collection.t2Field, + ), + ) } func NewCollection[TObject model.Model, TAttribute model.Model](name, t1Field, t2Field string) Collection[TObject, TAttribute] { diff --git a/condition/connection_condition.go b/condition/connection_condition.go index d9d7cdf..31fd262 100644 --- a/condition/connection_condition.go +++ b/condition/connection_condition.go @@ -64,7 +64,7 @@ func (condition connectionCondition[T]) affectsDeletedAt() bool { // Condition that connects multiple conditions. // Example: condition1 AND condition2 -func NewConnectionCondition[T model.Model](connector sql.Operator, conditions ...WhereCondition[T]) WhereCondition[T] { +func NewConnectionCondition[T model.Model](connector sql.Operator, conditions []WhereCondition[T]) WhereCondition[T] { return connectionCondition[T]{ Connector: connector, Conditions: conditions, diff --git a/condition/container_condition.go b/condition/container_condition.go index 855f57f..3b9b7ab 100644 --- a/condition/container_condition.go +++ b/condition/container_condition.go @@ -42,7 +42,7 @@ func (condition containerCondition[T]) affectsDeletedAt() bool { // Condition that contains a internal condition. // Example: NOT (internal condition) -func NewContainerCondition[T model.Model](prefix sql.Operator, conditions ...WhereCondition[T]) WhereCondition[T] { +func NewContainerCondition[T model.Model](prefix sql.Operator, conditions []WhereCondition[T]) WhereCondition[T] { if len(conditions) == 0 { return newInvalidCondition[T](emptyConditionsError[T](prefix)) } diff --git a/condition/delete.go b/condition/delete.go index 51fe7f0..b290769 100644 --- a/condition/delete.go +++ b/condition/delete.go @@ -61,7 +61,7 @@ func (deleteS *Delete[T]) Exec() (int64, error) { } // Create a Delete to which the conditions are applied inside transaction tx -func NewDelete[T model.Model](tx *gorm.DB, conditions ...Condition[T]) *Delete[T] { +func NewDelete[T model.Model](tx *gorm.DB, conditions []Condition[T]) *Delete[T] { var err error if len(conditions) == 0 { diff --git a/condition/exists_condition.go b/condition/exists_condition.go index 19c44dc..b482350 100644 --- a/condition/exists_condition.go +++ b/condition/exists_condition.go @@ -3,6 +3,8 @@ package condition import ( "fmt" + "github.com/elliotchance/pie/v2" + "github.com/FrancoLiberali/cql/model" ) @@ -14,6 +16,19 @@ type existsCondition[T1 model.Model, T2 model.Model] struct { T2Field string } +func newExistsCondition[T1 model.Model, T2 model.Model]( + firstCondition WhereCondition[T2], + conditions []WhereCondition[T2], + relationField, t1Field, t2Field string, +) existsCondition[T1, T2] { + return existsCondition[T1, T2]{ + Conditions: pie.Unshift(conditions, firstCondition), + RelationField: relationField, + T1Field: t1Field, + T2Field: t2Field, + } +} + //nolint:unused // is used func (condition existsCondition[T1, T2]) interfaceVerificationMethod(_ T1) { // This method is necessary to get the compiler to verify diff --git a/condition/logical.go b/condition/logical.go index d96e136..cd27c0c 100644 --- a/condition/logical.go +++ b/condition/logical.go @@ -6,9 +6,13 @@ import ( ) func And[T model.Model](conditions ...WhereCondition[T]) WhereCondition[T] { - return NewConnectionCondition(sql.And, conditions...) + return NewConnectionCondition(sql.And, conditions) +} + +func Or[T model.Model](conditions ...WhereCondition[T]) WhereCondition[T] { + return NewConnectionCondition(sql.Or, conditions) } func Not[T model.Model](conditions ...WhereCondition[T]) WhereCondition[T] { - return NewContainerCondition(sql.Not, conditions...) + return NewContainerCondition(sql.Not, conditions) } diff --git a/condition/update.go b/condition/update.go index eeec1eb..6c26f75 100644 --- a/condition/update.go +++ b/condition/update.go @@ -88,7 +88,7 @@ func (update *Update[T]) Returning(dest *[]T) *Update[T] { } // Create a Update to which the conditions are applied inside transaction tx -func NewUpdate[T model.Model](tx *gorm.DB, conditions ...Condition[T]) *Update[T] { +func NewUpdate[T model.Model](tx *gorm.DB, conditions []Condition[T]) *Update[T] { var err error if len(conditions) == 0 { diff --git a/delete.go b/delete.go index 1a2b33e..afd10a5 100644 --- a/delete.go +++ b/delete.go @@ -1,6 +1,7 @@ package cql import ( + "github.com/elliotchance/pie/v2" "gorm.io/gorm" "github.com/FrancoLiberali/cql/condition" @@ -16,6 +17,6 @@ import ( func Delete[T model.Model](tx *gorm.DB, firstCondition condition.Condition[T], conditions ...condition.Condition[T]) *condition.Delete[T] { return condition.NewDelete( tx, - append(conditions, firstCondition)..., + pie.Unshift(conditions, firstCondition), ) } diff --git a/logical.go b/logical.go index 42b81cc..29e6380 100644 --- a/logical.go +++ b/logical.go @@ -1,9 +1,10 @@ package cql import ( + "github.com/elliotchance/pie/v2" + "github.com/FrancoLiberali/cql/condition" "github.com/FrancoLiberali/cql/model" - "github.com/FrancoLiberali/cql/sql" "github.com/FrancoLiberali/cql/unsafe" ) @@ -17,8 +18,8 @@ import ( // Example: // // cql.And(conditions.City.Name.Is().Eq("Paris"), conditions.City.ZipCode.Is().Eq("75000")) -func And[T model.Model](conditions ...condition.WhereCondition[T]) condition.WhereCondition[T] { - return condition.And(conditions...) +func And[T model.Model](firstCondition condition.WhereCondition[T], conditions ...condition.WhereCondition[T]) condition.WhereCondition[T] { + return condition.And(pie.Unshift(conditions, firstCondition)...) } // Or allows the connection of multiple conditions by the OR logical connector. @@ -26,8 +27,8 @@ func And[T model.Model](conditions ...condition.WhereCondition[T]) condition.Whe // Example: // // cql.Or(conditions.City.Name.Is().Eq("Paris"), conditions.City.Name.Is().Eq("Buenos Aires")) -func Or[T model.Model](conditions ...condition.WhereCondition[T]) condition.WhereCondition[T] { - return condition.NewConnectionCondition(sql.Or, conditions...) +func Or[T model.Model](firstCondition condition.WhereCondition[T], conditions ...condition.WhereCondition[T]) condition.WhereCondition[T] { + return condition.Or(pie.Unshift(conditions, firstCondition)...) } // Not allows the negation of the conditions within it. Multiple conditions are connected by an AND by default. @@ -39,8 +40,8 @@ func Or[T model.Model](conditions ...condition.WhereCondition[T]) condition.Wher // translates as // // NOT (name = "Paris" AND name = "Buenos Aires") -func Not[T model.Model](conditions ...condition.WhereCondition[T]) condition.WhereCondition[T] { - return condition.Not(conditions...) +func Not[T model.Model](firstCondition condition.WhereCondition[T], conditions ...condition.WhereCondition[T]) condition.WhereCondition[T] { + return condition.Not(pie.Unshift(conditions, firstCondition)...) } // True represents a condition that is always true. diff --git a/mysql/logical.go b/mysql/logical.go index 926c67c..2e5c0a7 100644 --- a/mysql/logical.go +++ b/mysql/logical.go @@ -1,11 +1,16 @@ package mysql import ( + "github.com/elliotchance/pie/v2" + "github.com/FrancoLiberali/cql/condition" "github.com/FrancoLiberali/cql/model" "github.com/FrancoLiberali/cql/sql" ) -func Xor[T model.Model](conditions ...condition.WhereCondition[T]) condition.WhereCondition[T] { - return condition.NewConnectionCondition(sql.MySQLXor, conditions...) +func Xor[T model.Model](firstCondition condition.WhereCondition[T], conditions ...condition.WhereCondition[T]) condition.WhereCondition[T] { + return condition.NewConnectionCondition( + sql.MySQLXor, + pie.Unshift(conditions, firstCondition), + ) } diff --git a/test/join_conditions_test.go b/test/join_conditions_test.go index 4eee50d..6cf75fe 100644 --- a/test/join_conditions_test.go +++ b/test/join_conditions_test.go @@ -375,35 +375,6 @@ func (ts *JoinConditionsIntTestSuite) TestJoinWithUnsafeCondition() { EqualList(&ts.Suite, []*models.Sale{match}, entities) } -func (ts *JoinConditionsIntTestSuite) TestJoinWithEmptyConnectionConditionMakesNothing() { - product1 := ts.createProduct("", 1, 0.0, false, nil) - product2 := ts.createProduct("", 2, 0.0, false, nil) - - match1 := ts.createSale(0, product1, nil) - match2 := ts.createSale(0, product2, nil) - - entities, err := cql.Query[models.Sale]( - ts.db, - conditions.Sale.Product( - cql.And[models.Product](), - ), - ).Find() - ts.Require().NoError(err) - - EqualList(&ts.Suite, []*models.Sale{match1, match2}, entities) -} - -func (ts *JoinConditionsIntTestSuite) TestJoinWithEmptyContainerConditionReturnsError() { - _, err := cql.Query[models.Sale]( - ts.db, - conditions.Sale.Product( - cql.Not[models.Product](), - ), - ).Find() - ts.ErrorIs(err, cql.ErrEmptyConditions) - ts.ErrorContains(err, "connector: Not; model: models.Product") -} - func (ts *JoinConditionsIntTestSuite) TestDynamicOperatorOver2Tables() { company1 := ts.createCompany("ditrit") company2 := ts.createCompany("orness") diff --git a/test/where_conditions_test.go b/test/where_conditions_test.go index 6df29c4..5a74be9 100644 --- a/test/where_conditions_test.go +++ b/test/where_conditions_test.go @@ -554,24 +554,3 @@ func (ts *WhereConditionsIntTestSuite) TestUnsafeCondition() { EqualList(&ts.Suite, []*models.Product{match1, match2}, entities) } - -func (ts *WhereConditionsIntTestSuite) TestEmptyConnectionConditionMakesNothing() { - match1 := ts.createProduct("match", 1, 0.0, true, nil) - match2 := ts.createProduct("match", 1, 0.0, true, nil) - - entities, err := cql.Query[models.Product]( - ts.db, - cql.And[models.Product](), - ).Find() - ts.Require().NoError(err) - - EqualList(&ts.Suite, []*models.Product{match1, match2}, entities) -} - -func (ts *WhereConditionsIntTestSuite) TestEmptyContainerConditionReturnsError() { - _, err := cql.Query[models.Product]( - ts.db, - cql.Not[models.Product](), - ).Find() - ts.ErrorIs(err, cql.ErrEmptyConditions) -} diff --git a/update.go b/update.go index cecd4d4..bd90701 100644 --- a/update.go +++ b/update.go @@ -1,6 +1,7 @@ package cql import ( + "github.com/elliotchance/pie/v2" "gorm.io/gorm" "github.com/FrancoLiberali/cql/condition" @@ -16,6 +17,6 @@ import ( func Update[T model.Model](tx *gorm.DB, firstCondition condition.Condition[T], conditions ...condition.Condition[T]) *condition.Update[T] { return condition.NewUpdate( tx, - append(conditions, firstCondition)..., + pie.Unshift(conditions, firstCondition), ) }