Enforce new linting rules: errname, errorlint, lll, stylecheck (#32)
This commit is contained in:
parent
ec08a5a918
commit
482dd095a6
16 changed files with 891 additions and 336 deletions
|
@ -129,27 +129,50 @@ type UserRepository interface {
|
|||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||
code.ArrayType{
|
||||
ContainedType: code.PointerType{
|
||||
ContainedType: code.SimpleType("UserModel"),
|
||||
},
|
||||
},
|
||||
code.TypeError,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "FindByAgeBetween",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "fromAge", Type: code.TypeInt},
|
||||
{Name: "toAge", Type: code.TypeInt},
|
||||
{
|
||||
Name: "ctx",
|
||||
Type: code.ExternalType{PackageAlias: "context", Name: "Context"},
|
||||
},
|
||||
{
|
||||
Name: "fromAge",
|
||||
Type: code.TypeInt,
|
||||
},
|
||||
{
|
||||
Name: "toAge",
|
||||
Type: code.TypeInt,
|
||||
},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||
code.ArrayType{
|
||||
ContainedType: code.PointerType{
|
||||
ContainedType: code.SimpleType("UserModel"),
|
||||
},
|
||||
},
|
||||
code.TypeError,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "InsertOne",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "user", Type: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||
{
|
||||
Name: "ctx",
|
||||
Type: code.ExternalType{PackageAlias: "context", Name: "Context"},
|
||||
},
|
||||
{
|
||||
Name: "user",
|
||||
Type: code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
||||
},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.InterfaceType{},
|
||||
|
@ -159,9 +182,18 @@ type UserRepository interface {
|
|||
{
|
||||
Name: "UpdateAgreementByID",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "agreement", Type: code.MapType{KeyType: code.TypeString, ValueType: code.TypeBool}},
|
||||
{Name: "id", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||||
{
|
||||
Name: "ctx",
|
||||
Type: code.ExternalType{PackageAlias: "context", Name: "Context"},
|
||||
},
|
||||
{
|
||||
Name: "agreement",
|
||||
Type: code.MapType{KeyType: code.TypeString, ValueType: code.TypeBool},
|
||||
},
|
||||
{
|
||||
Name: "id",
|
||||
Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"},
|
||||
},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.TypeBool,
|
||||
|
@ -273,7 +305,9 @@ type UserRepository interface {
|
|||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||
code.ArrayType{
|
||||
ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
||||
},
|
||||
code.TypeError,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -24,7 +24,7 @@ func ParsePackage(pkgs map[string]*ast.Package) (Package, error) {
|
|||
}
|
||||
|
||||
// Package stores package name, struct and interface implementations as a result
|
||||
// from ParsePackage
|
||||
// from ParsePackage.
|
||||
type Package struct {
|
||||
Name string
|
||||
Structs map[string]Struct
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package generator_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/sunboyy/repogen/internal/code"
|
||||
"github.com/sunboyy/repogen/internal/generator"
|
||||
"github.com/sunboyy/repogen/internal/spec"
|
||||
"github.com/sunboyy/repogen/internal/testutils"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -76,8 +77,16 @@ func TestGenerateMongoRepository(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorAnd,
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorNot, ParamIndex: 1},
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorLessThan, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorNot,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorLessThan,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -96,7 +105,11 @@ func TestGenerateMongoRepository(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorLessThanEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorLessThanEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
Sorts: []spec.Sort{
|
||||
|
@ -118,7 +131,11 @@ func TestGenerateMongoRepository(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorGreaterThan, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorGreaterThan,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
Sorts: []spec.Sort{
|
||||
|
@ -140,7 +157,11 @@ func TestGenerateMongoRepository(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorGreaterThanEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorGreaterThanEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
Sorts: []spec.Sort{
|
||||
|
@ -163,7 +184,11 @@ func TestGenerateMongoRepository(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorBetween, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorBetween,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -184,153 +209,33 @@ func TestGenerateMongoRepository(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorOr,
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
expectedBytes, err := os.ReadFile("../../test/generator_test_expected.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedCode := string(expectedBytes)
|
||||
|
||||
code, err := generator.GenerateRepository("user", userModel, "UserRepository", methods)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := testutils.ExpectMultiLineString(expectedCode, code); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
expectedCode := `// Code generated by repogen. DO NOT EDIT.
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
func NewUserRepository(collection *mongo.Collection) UserRepository {
|
||||
return &UserRepositoryMongo{
|
||||
collection: collection,
|
||||
}
|
||||
}
|
||||
|
||||
type UserRepositoryMongo struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
|
||||
func (r *UserRepositoryMongo) FindByID(arg0 context.Context, arg1 primitive.ObjectID) (*UserModel, error) {
|
||||
var entity UserModel
|
||||
if err := r.collection.FindOne(arg0, bson.M{
|
||||
"_id": arg1,
|
||||
}, options.FindOne().SetSort(bson.M{})).Decode(&entity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &entity, nil
|
||||
}
|
||||
|
||||
func (r *UserRepositoryMongo) FindByGenderNotAndAgeLessThan(arg0 context.Context, arg1 Gender, arg2 int) (*UserModel, error) {
|
||||
cursor, err := r.collection.Find(arg0, bson.M{
|
||||
"$and": []bson.M{
|
||||
{"gender": bson.M{"$ne": arg1}},
|
||||
{"age": bson.M{"$lt": arg2}},
|
||||
},
|
||||
}, options.Find().SetSort(bson.M{}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var entities []*UserModel
|
||||
if err := cursor.All(arg0, &entities); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entities, nil
|
||||
}
|
||||
|
||||
func (r *UserRepositoryMongo) FindByAgeLessThanEqualOrderByAge(arg0 context.Context, arg1 int) ([]*UserModel, error) {
|
||||
cursor, err := r.collection.Find(arg0, bson.M{
|
||||
"age": bson.M{"$lte": arg1},
|
||||
}, options.Find().SetSort(bson.M{
|
||||
"age": 1,
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var entities []*UserModel
|
||||
if err := cursor.All(arg0, &entities); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entities, nil
|
||||
}
|
||||
|
||||
func (r *UserRepositoryMongo) FindByAgeGreaterThanOrderByAgeAsc(arg0 context.Context, arg1 int) ([]*UserModel, error) {
|
||||
cursor, err := r.collection.Find(arg0, bson.M{
|
||||
"age": bson.M{"$gt": arg1},
|
||||
}, options.Find().SetSort(bson.M{
|
||||
"age": 1,
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var entities []*UserModel
|
||||
if err := cursor.All(arg0, &entities); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entities, nil
|
||||
}
|
||||
|
||||
func (r *UserRepositoryMongo) FindByAgeGreaterThanEqualOrderByAgeDesc(arg0 context.Context, arg1 int) ([]*UserModel, error) {
|
||||
cursor, err := r.collection.Find(arg0, bson.M{
|
||||
"age": bson.M{"$gte": arg1},
|
||||
}, options.Find().SetSort(bson.M{
|
||||
"age": -1,
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var entities []*UserModel
|
||||
if err := cursor.All(arg0, &entities); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entities, nil
|
||||
}
|
||||
|
||||
func (r *UserRepositoryMongo) FindByAgeBetween(arg0 context.Context, arg1 int, arg2 int) ([]*UserModel, error) {
|
||||
cursor, err := r.collection.Find(arg0, bson.M{
|
||||
"age": bson.M{"$gte": arg1, "$lte": arg2},
|
||||
}, options.Find().SetSort(bson.M{}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var entities []*UserModel
|
||||
if err := cursor.All(arg0, &entities); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entities, nil
|
||||
}
|
||||
|
||||
func (r *UserRepositoryMongo) FindByGenderOrAge(arg0 context.Context, arg1 Gender, arg2 int) ([]*UserModel, error) {
|
||||
cursor, err := r.collection.Find(arg0, bson.M{
|
||||
"$or": []bson.M{
|
||||
{"gender": arg1},
|
||||
{"age": arg2},
|
||||
},
|
||||
}, options.Find().SetSort(bson.M{}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var entities []*UserModel
|
||||
if err := cursor.All(arg0, &entities); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entities, nil
|
||||
}
|
||||
`
|
||||
expectedCodeLines := strings.Split(expectedCode, "\n")
|
||||
actualCodeLines := strings.Split(code, "\n")
|
||||
|
||||
for i, line := range expectedCodeLines {
|
||||
if line != actualCodeLines[i] {
|
||||
t.Errorf("On line %d\nExpected = %v\nActual = %v", i, line, actualCodeLines[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ func NewGenerator(structModel code.Struct, interfaceName string) RepositoryGener
|
|||
}
|
||||
}
|
||||
|
||||
// RepositoryGenerator provides repository constructor and method generation from provided specification
|
||||
// RepositoryGenerator is a MongoDB repository generator that provides
|
||||
// necessary information required to construct an implementation.
|
||||
type RepositoryGenerator struct {
|
||||
StructModel code.Struct
|
||||
InterfaceName string
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package mongo_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
@ -318,7 +319,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{idField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -348,7 +353,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -418,8 +427,16 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorAnd,
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{ageField}, ParamIndex: 2},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -458,8 +475,16 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorOr,
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{ageField}, ParamIndex: 2},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -496,7 +521,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorNot, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorNot,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -530,7 +559,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorLessThan, FieldReference: spec.FieldReference{ageField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorLessThan,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -564,7 +597,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorLessThanEqual, FieldReference: spec.FieldReference{ageField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorLessThanEqual,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -598,7 +635,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorGreaterThan, FieldReference: spec.FieldReference{ageField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorGreaterThan,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -632,7 +673,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorGreaterThanEqual, FieldReference: spec.FieldReference{ageField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorGreaterThanEqual,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -667,7 +712,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorBetween, FieldReference: spec.FieldReference{ageField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorBetween,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -701,7 +750,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorIn, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorIn,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -735,7 +788,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorNotIn, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorNotIn,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -768,7 +825,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorTrue, FieldReference: spec.FieldReference{enabledField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorTrue,
|
||||
FieldReference: spec.FieldReference{enabledField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -801,7 +862,11 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorFalse, FieldReference: spec.FieldReference{enabledField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorFalse,
|
||||
FieldReference: spec.FieldReference{enabledField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -897,7 +962,10 @@ func TestGenerateMethod_Find(t *testing.T) {
|
|||
Operation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Sorts: []spec.Sort{
|
||||
{FieldReference: spec.FieldReference{nameField, firstNameField}, Ordering: spec.OrderingAscending},
|
||||
{
|
||||
FieldReference: spec.FieldReference{nameField, firstNameField},
|
||||
Ordering: spec.OrderingAscending,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1033,7 +1101,11 @@ func TestGenerateMethod_Update(t *testing.T) {
|
|||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1063,12 +1135,20 @@ func TestGenerateMethod_Update(t *testing.T) {
|
|||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{ageField}, ParamIndex: 1, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1100,12 +1180,20 @@ func TestGenerateMethod_Update(t *testing.T) {
|
|||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{ageField}, ParamIndex: 1, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1137,12 +1225,20 @@ func TestGenerateMethod_Update(t *testing.T) {
|
|||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{consentHistoryField}, ParamIndex: 1, Operator: spec.UpdateOperatorPush},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{consentHistoryField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorPush,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1174,12 +1270,20 @@ func TestGenerateMethod_Update(t *testing.T) {
|
|||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{ageField}, ParamIndex: 1, Operator: spec.UpdateOperatorInc},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorInc,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1212,13 +1316,25 @@ func TestGenerateMethod_Update(t *testing.T) {
|
|||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{enabledField}, ParamIndex: 1, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{consentHistoryField}, ParamIndex: 2, Operator: spec.UpdateOperatorPush},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{enabledField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{consentHistoryField},
|
||||
ParamIndex: 2,
|
||||
Operator: spec.UpdateOperatorPush,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 3},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1253,12 +1369,20 @@ func TestGenerateMethod_Update(t *testing.T) {
|
|||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{nameField, firstNameField}, ParamIndex: 1, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{nameField, firstNameField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1354,7 +1478,11 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{idField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1383,7 +1511,11 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1414,8 +1546,16 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorAnd,
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{ageField}, ParamIndex: 2},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1449,8 +1589,16 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorOr,
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{Comparator: spec.ComparatorEqual, FieldReference: spec.FieldReference{ageField}, ParamIndex: 2},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
Comparator: spec.ComparatorEqual,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1482,7 +1630,11 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorNot, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorNot,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1511,7 +1663,11 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorLessThan, FieldReference: spec.FieldReference{ageField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorLessThan,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1540,7 +1696,11 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorLessThanEqual, FieldReference: spec.FieldReference{ageField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorLessThanEqual,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1569,7 +1729,11 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorGreaterThan, FieldReference: spec.FieldReference{ageField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorGreaterThan,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1598,7 +1762,11 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorGreaterThanEqual, FieldReference: spec.FieldReference{ageField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorGreaterThanEqual,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1628,7 +1796,11 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorBetween, FieldReference: spec.FieldReference{ageField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorBetween,
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1657,7 +1829,11 @@ func TestGenerateMethod_Delete(t *testing.T) {
|
|||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorIn, FieldReference: spec.FieldReference{genderField}, ParamIndex: 1},
|
||||
{
|
||||
Comparator: spec.ComparatorIn,
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1751,7 +1927,11 @@ func TestGenerateMethod_Count(t *testing.T) {
|
|||
Operation: spec.CountOperation{
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1781,8 +1961,16 @@ func TestGenerateMethod_Count(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorAnd,
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1815,8 +2003,16 @@ func TestGenerateMethod_Count(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorOr,
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1847,7 +2043,11 @@ func TestGenerateMethod_Count(t *testing.T) {
|
|||
Operation: spec.CountOperation{
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorNot, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorNot,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1875,7 +2075,11 @@ func TestGenerateMethod_Count(t *testing.T) {
|
|||
Operation: spec.CountOperation{
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorLessThan, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorLessThan,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1903,7 +2107,11 @@ func TestGenerateMethod_Count(t *testing.T) {
|
|||
Operation: spec.CountOperation{
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorLessThanEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorLessThanEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1931,7 +2139,11 @@ func TestGenerateMethod_Count(t *testing.T) {
|
|||
Operation: spec.CountOperation{
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorGreaterThan, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorGreaterThan,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1959,7 +2171,11 @@ func TestGenerateMethod_Count(t *testing.T) {
|
|||
Operation: spec.CountOperation{
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorGreaterThanEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorGreaterThanEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1988,7 +2204,11 @@ func TestGenerateMethod_Count(t *testing.T) {
|
|||
Operation: spec.CountOperation{
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorBetween, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorBetween,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -2016,7 +2236,11 @@ func TestGenerateMethod_Count(t *testing.T) {
|
|||
Operation: spec.CountOperation{
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorIn, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorIn,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -2140,7 +2364,11 @@ func TestGenerateMethod_Invalid(t *testing.T) {
|
|||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{accessTokenField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{accessTokenField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -2182,12 +2410,20 @@ func TestGenerateMethod_Invalid(t *testing.T) {
|
|||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{accessTokenField}, ParamIndex: 1, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{accessTokenField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -2212,7 +2448,11 @@ func TestGenerateMethod_Invalid(t *testing.T) {
|
|||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -2234,12 +2474,20 @@ func TestGenerateMethod_Invalid(t *testing.T) {
|
|||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{consentHistoryField}, ParamIndex: 1, Operator: "APPEND"},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{consentHistoryField},
|
||||
ParamIndex: 1,
|
||||
Operator: "APPEND",
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -2254,7 +2502,7 @@ func TestGenerateMethod_Invalid(t *testing.T) {
|
|||
|
||||
_, err := generator.GenerateMethod(testCase.Method)
|
||||
|
||||
if err != testCase.ExpectedError {
|
||||
if !errors.Is(err, testCase.ExpectedError) {
|
||||
t.Errorf("\nExpected = %+v\nReceived = %+v", testCase.ExpectedError, err)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,35 +1,19 @@
|
|||
package spec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/sunboyy/repogen/internal/code"
|
||||
)
|
||||
|
||||
// ParsingError is an error from parsing interface methods
|
||||
type ParsingError string
|
||||
|
||||
func (err ParsingError) Error() string {
|
||||
switch err {
|
||||
case QueryRequiredError:
|
||||
return "query is required"
|
||||
case InvalidParamError:
|
||||
return "parameters do not match the query"
|
||||
case InvalidUpdateFieldsError:
|
||||
return "update fields are invalid"
|
||||
case ContextParamRequiredError:
|
||||
return "context parameter is required"
|
||||
}
|
||||
return string(err)
|
||||
}
|
||||
|
||||
// parsing error constants
|
||||
const (
|
||||
QueryRequiredError ParsingError = "ERROR_QUERY_REQUIRED"
|
||||
InvalidParamError ParsingError = "ERROR_INVALID_PARAM"
|
||||
InvalidUpdateFieldsError ParsingError = "ERROR_INVALID_UPDATE_FIELDS"
|
||||
ContextParamRequiredError ParsingError = "ERROR_CONTEXT_PARAM_REQUIRED"
|
||||
var (
|
||||
ErrQueryRequired = errors.New("spec: query is required")
|
||||
ErrInvalidParam = errors.New("spec: parameters do not match the query")
|
||||
ErrInvalidUpdateFields = errors.New("spec: update fields are invalid")
|
||||
ErrContextParamRequired = errors.New("spec: context parameter is required")
|
||||
)
|
||||
|
||||
// NewUnsupportedReturnError creates unsupportedReturnError
|
||||
|
@ -49,7 +33,8 @@ func (err unsupportedReturnError) Error() string {
|
|||
return fmt.Sprintf("return type '%s' at index %d is not supported", err.GivenType.Code(), err.Index)
|
||||
}
|
||||
|
||||
// NewOperationReturnCountUnmatchedError creates operationReturnCountUnmatchedError
|
||||
// NewOperationReturnCountUnmatchedError creates
|
||||
// operationReturnCountUnmatchedError.
|
||||
func NewOperationReturnCountUnmatchedError(returnCount int) error {
|
||||
return operationReturnCountUnmatchedError{
|
||||
ReturnCount: returnCount,
|
||||
|
|
|
@ -14,7 +14,8 @@ func (r FieldReference) ReferencedField() code.StructField {
|
|||
return r[len(r)-1]
|
||||
}
|
||||
|
||||
// ReferencingCode returns a string containing name of the referenced fields concatenating with period (.).
|
||||
// ReferencingCode returns a string containing name of the referenced fields
|
||||
// concatenating with period (.).
|
||||
func (r FieldReference) ReferencingCode() string {
|
||||
var fieldNames []string
|
||||
for _, field := range r {
|
||||
|
|
|
@ -5,8 +5,11 @@ import (
|
|||
"github.com/sunboyy/repogen/internal/code"
|
||||
)
|
||||
|
||||
// ParseInterfaceMethod returns repository method spec from declared interface method
|
||||
func ParseInterfaceMethod(structs map[string]code.Struct, structModel code.Struct, method code.Method) (MethodSpec, error) {
|
||||
// ParseInterfaceMethod returns repository method spec from declared interface
|
||||
// method.
|
||||
func ParseInterfaceMethod(structs map[string]code.Struct, structModel code.Struct,
|
||||
method code.Method) (MethodSpec, error) {
|
||||
|
||||
parser := interfaceMethodParser{
|
||||
fieldResolver: fieldResolver{
|
||||
Structs: structs,
|
||||
|
@ -67,12 +70,12 @@ func (p interfaceMethodParser) parseInsertOperation(tokens []string) (Operation,
|
|||
|
||||
pointerType := code.PointerType{ContainedType: p.StructModel.ReferencedType()}
|
||||
if mode == QueryModeOne && p.Method.Params[1].Type != pointerType {
|
||||
return nil, InvalidParamError
|
||||
return nil, ErrInvalidParam
|
||||
}
|
||||
|
||||
arrayType := code.ArrayType{ContainedType: pointerType}
|
||||
if mode == QueryModeMany && p.Method.Params[1].Type != arrayType {
|
||||
return nil, InvalidParamError
|
||||
return nil, ErrInvalidParam
|
||||
}
|
||||
|
||||
return InsertOperation{
|
||||
|
@ -354,14 +357,14 @@ func (p interfaceMethodParser) extractIntOrBoolReturns(returns []code.Type) (Que
|
|||
func (p interfaceMethodParser) validateContextParam() error {
|
||||
contextType := code.ExternalType{PackageAlias: "context", Name: "Context"}
|
||||
if len(p.Method.Params) == 0 || p.Method.Params[0].Type != contextType {
|
||||
return ContextParamRequiredError
|
||||
return ErrContextParamRequired
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p interfaceMethodParser) validateQueryFromParams(params []code.Param, querySpec QuerySpec) error {
|
||||
if querySpec.NumberOfArguments() != len(params) {
|
||||
return InvalidParamError
|
||||
return ErrInvalidParam
|
||||
}
|
||||
|
||||
var currentParamIndex int
|
||||
|
@ -373,7 +376,9 @@ func (p interfaceMethodParser) validateQueryFromParams(params []code.Param, quer
|
|||
}
|
||||
|
||||
for i := 0; i < predicate.Comparator.NumberOfArguments(); i++ {
|
||||
requiredType := predicate.Comparator.ArgumentTypeFromFieldType(predicate.FieldReference.ReferencedField().Type)
|
||||
requiredType := predicate.Comparator.ArgumentTypeFromFieldType(
|
||||
predicate.FieldReference.ReferencedField().Type,
|
||||
)
|
||||
|
||||
if params[currentParamIndex].Type != requiredType {
|
||||
return NewArgumentTypeNotMatchedError(predicate.FieldReference.ReferencingCode(), requiredType,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package spec_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
|
@ -126,8 +127,19 @@ func TestParseInterfaceMethod_Insert(t *testing.T) {
|
|||
Method: code.Method{
|
||||
Name: "InsertMany",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}}},
|
||||
{
|
||||
Type: code.ExternalType{
|
||||
PackageAlias: "context",
|
||||
Name: "Context",
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: code.ArrayType{
|
||||
ContainedType: code.PointerType{
|
||||
ContainedType: code.SimpleType("UserModel"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.ArrayType{ContainedType: code.InterfaceType{}},
|
||||
|
@ -198,7 +210,11 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
|
|||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{phoneNumberField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{phoneNumberField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -238,7 +254,11 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
|
|||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{nameField, firstNameField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{nameField, firstNameField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -258,7 +278,11 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
|
|||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{referrerField, idField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{referrerField, idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -297,8 +321,16 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorAnd,
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{cityField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{cityField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -322,8 +354,16 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorOr,
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{cityField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{cityField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -384,7 +424,11 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
|
|||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorLessThanEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorLessThanEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -404,7 +448,11 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
|
|||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorGreaterThan, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorGreaterThan,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -424,7 +472,11 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
|
|||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorGreaterThanEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorGreaterThanEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -523,7 +575,11 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
|
|||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{enabledField}, Comparator: spec.ComparatorFalse, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{enabledField},
|
||||
Comparator: spec.ComparatorFalse,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -705,11 +761,19 @@ func TestParseInterfaceMethod_Update(t *testing.T) {
|
|||
},
|
||||
ExpectedOperation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{genderField}, ParamIndex: 1, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -729,11 +793,19 @@ func TestParseInterfaceMethod_Update(t *testing.T) {
|
|||
},
|
||||
ExpectedOperation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{genderField}, ParamIndex: 1, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -753,11 +825,19 @@ func TestParseInterfaceMethod_Update(t *testing.T) {
|
|||
},
|
||||
ExpectedOperation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{nameField, firstNameField}, ParamIndex: 1, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{nameField, firstNameField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -778,8 +858,16 @@ func TestParseInterfaceMethod_Update(t *testing.T) {
|
|||
},
|
||||
ExpectedOperation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{genderField}, ParamIndex: 1, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{cityField}, ParamIndex: 2, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{cityField},
|
||||
ParamIndex: 2,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
|
@ -803,11 +891,19 @@ func TestParseInterfaceMethod_Update(t *testing.T) {
|
|||
},
|
||||
ExpectedOperation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{consentHistoryField}, ParamIndex: 1, Operator: spec.UpdateOperatorPush},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{consentHistoryField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorPush,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -827,11 +923,19 @@ func TestParseInterfaceMethod_Update(t *testing.T) {
|
|||
},
|
||||
ExpectedOperation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{ageField}, ParamIndex: 1, Operator: spec.UpdateOperatorInc},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorInc,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{idField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{idField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -852,8 +956,16 @@ func TestParseInterfaceMethod_Update(t *testing.T) {
|
|||
},
|
||||
ExpectedOperation: spec.UpdateOperation{
|
||||
Update: spec.UpdateFields{
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{enabledField}, ParamIndex: 1, Operator: spec.UpdateOperatorSet},
|
||||
spec.UpdateField{FieldReference: spec.FieldReference{consentHistoryField}, ParamIndex: 2, Operator: spec.UpdateOperatorPush},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{enabledField},
|
||||
ParamIndex: 1,
|
||||
Operator: spec.UpdateOperatorSet,
|
||||
},
|
||||
spec.UpdateField{
|
||||
FieldReference: spec.FieldReference{consentHistoryField},
|
||||
ParamIndex: 2,
|
||||
Operator: spec.UpdateOperatorPush,
|
||||
},
|
||||
},
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
|
@ -921,7 +1033,11 @@ func TestParseInterfaceMethod_Delete(t *testing.T) {
|
|||
ExpectedOperation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{phoneNumberField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{phoneNumberField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -980,8 +1096,16 @@ func TestParseInterfaceMethod_Delete(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorAnd,
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{cityField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{cityField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1005,8 +1129,16 @@ func TestParseInterfaceMethod_Delete(t *testing.T) {
|
|||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorOr,
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{cityField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
{
|
||||
FieldReference: spec.FieldReference{cityField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1067,7 +1199,11 @@ func TestParseInterfaceMethod_Delete(t *testing.T) {
|
|||
ExpectedOperation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorLessThanEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorLessThanEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -1087,7 +1223,11 @@ func TestParseInterfaceMethod_Delete(t *testing.T) {
|
|||
ExpectedOperation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorGreaterThan, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorGreaterThan,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -1107,7 +1247,11 @@ func TestParseInterfaceMethod_Delete(t *testing.T) {
|
|||
ExpectedOperation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{ageField}, Comparator: spec.ComparatorGreaterThanEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{ageField},
|
||||
Comparator: spec.ComparatorGreaterThanEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
@ -1208,7 +1352,11 @@ func TestParseInterfaceMethod_Count(t *testing.T) {
|
|||
ExpectedOperation: spec.CountOperation{
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
{
|
||||
FieldReference: spec.FieldReference{genderField},
|
||||
Comparator: spec.ComparatorEqual,
|
||||
ParamIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1247,7 +1395,7 @@ func TestParseInterfaceMethod_Invalid(t *testing.T) {
|
|||
})
|
||||
|
||||
expectedError := spec.NewUnknownOperationError("Search")
|
||||
if err != expectedError {
|
||||
if !errors.Is(err, expectedError) {
|
||||
t.Errorf("\nExpected = %+v\nReceived = %+v", expectedError, err)
|
||||
}
|
||||
}
|
||||
|
@ -1275,7 +1423,10 @@ func TestParseInterfaceMethod_Insert_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.NewUnsupportedReturnError(code.PointerType{ContainedType: code.SimpleType("UserModel")}, 0),
|
||||
ExpectedError: spec.NewUnsupportedReturnError(
|
||||
code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
||||
0,
|
||||
),
|
||||
},
|
||||
{
|
||||
Name: "unempty interface return from insert method",
|
||||
|
@ -1315,22 +1466,32 @@ func TestParseInterfaceMethod_Insert_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.ContextParamRequiredError,
|
||||
ExpectedError: spec.ErrContextParamRequired,
|
||||
},
|
||||
{
|
||||
Name: "mismatched model parameter for one mode",
|
||||
Method: code.Method{
|
||||
Name: "Insert",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "userModel", Type: code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}}},
|
||||
{
|
||||
Name: "ctx",
|
||||
Type: code.ExternalType{PackageAlias: "context", Name: "Context"},
|
||||
},
|
||||
{
|
||||
Name: "userModel",
|
||||
Type: code.ArrayType{
|
||||
ContainedType: code.PointerType{
|
||||
ContainedType: code.SimpleType("UserModel"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.InterfaceType{},
|
||||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidParamError,
|
||||
ExpectedError: spec.ErrInvalidParam,
|
||||
},
|
||||
{
|
||||
Name: "mismatched model parameter for many mode",
|
||||
|
@ -1345,7 +1506,7 @@ func TestParseInterfaceMethod_Insert_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidParamError,
|
||||
ExpectedError: spec.ErrInvalidParam,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1405,7 +1566,7 @@ func TestParseInterfaceMethod_Find_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.QueryRequiredError,
|
||||
ExpectedError: spec.ErrQueryRequired,
|
||||
},
|
||||
{
|
||||
Name: "misplaced operator token (leftmost)",
|
||||
|
@ -1463,7 +1624,7 @@ func TestParseInterfaceMethod_Find_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.ContextParamRequiredError,
|
||||
ExpectedError: spec.ErrContextParamRequired,
|
||||
},
|
||||
{
|
||||
Name: "mismatched number of parameters",
|
||||
|
@ -1479,7 +1640,7 @@ func TestParseInterfaceMethod_Find_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidParamError,
|
||||
ExpectedError: spec.ErrInvalidParam,
|
||||
},
|
||||
{
|
||||
Name: "struct field not found",
|
||||
|
@ -1711,7 +1872,7 @@ func TestParseInterfaceMethod_Update_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidUpdateFieldsError,
|
||||
ExpectedError: spec.ErrInvalidUpdateFields,
|
||||
},
|
||||
{
|
||||
Name: "misplaced And token in update fields",
|
||||
|
@ -1725,7 +1886,7 @@ func TestParseInterfaceMethod_Update_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidUpdateFieldsError,
|
||||
ExpectedError: spec.ErrInvalidUpdateFields,
|
||||
},
|
||||
{
|
||||
Name: "push operator in non-array field",
|
||||
|
@ -1782,7 +1943,7 @@ func TestParseInterfaceMethod_Update_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.QueryRequiredError,
|
||||
ExpectedError: spec.ErrQueryRequired,
|
||||
},
|
||||
{
|
||||
Name: "ambiguous query",
|
||||
|
@ -1813,8 +1974,13 @@ func TestParseInterfaceMethod_Update_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.NewArgumentTypeNotMatchedError(consentHistoryField.Name, code.SimpleType("ConsentHistoryItem"),
|
||||
code.ArrayType{ContainedType: code.SimpleType("ConsentHistoryItem")}),
|
||||
ExpectedError: spec.NewArgumentTypeNotMatchedError(
|
||||
consentHistoryField.Name,
|
||||
code.SimpleType("ConsentHistoryItem"),
|
||||
code.ArrayType{
|
||||
ContainedType: code.SimpleType("ConsentHistoryItem"),
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
Name: "insufficient function parameters",
|
||||
|
@ -1829,7 +1995,7 @@ func TestParseInterfaceMethod_Update_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidUpdateFieldsError,
|
||||
ExpectedError: spec.ErrInvalidUpdateFields,
|
||||
},
|
||||
{
|
||||
Name: "update model with invalid parameter",
|
||||
|
@ -1844,7 +2010,7 @@ func TestParseInterfaceMethod_Update_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidUpdateFieldsError,
|
||||
ExpectedError: spec.ErrInvalidUpdateFields,
|
||||
},
|
||||
{
|
||||
Name: "no context parameter",
|
||||
|
@ -1859,7 +2025,7 @@ func TestParseInterfaceMethod_Update_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.ContextParamRequiredError,
|
||||
ExpectedError: spec.ErrContextParamRequired,
|
||||
},
|
||||
{
|
||||
Name: "struct field not found in update fields",
|
||||
|
@ -1967,7 +2133,7 @@ func TestParseInterfaceMethod_Delete_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.QueryRequiredError,
|
||||
ExpectedError: spec.ErrQueryRequired,
|
||||
},
|
||||
{
|
||||
Name: "misplaced operator token (leftmost)",
|
||||
|
@ -2025,7 +2191,7 @@ func TestParseInterfaceMethod_Delete_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.ContextParamRequiredError,
|
||||
ExpectedError: spec.ErrContextParamRequired,
|
||||
},
|
||||
{
|
||||
Name: "mismatched number of parameters",
|
||||
|
@ -2041,7 +2207,7 @@ func TestParseInterfaceMethod_Delete_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidParamError,
|
||||
ExpectedError: spec.ErrInvalidParam,
|
||||
},
|
||||
{
|
||||
Name: "struct field not found",
|
||||
|
@ -2147,7 +2313,7 @@ func TestParseInterfaceMethod_Count_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.QueryRequiredError,
|
||||
ExpectedError: spec.ErrQueryRequired,
|
||||
},
|
||||
{
|
||||
Name: "invalid query",
|
||||
|
@ -2172,7 +2338,7 @@ func TestParseInterfaceMethod_Count_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.ContextParamRequiredError,
|
||||
ExpectedError: spec.ErrContextParamRequired,
|
||||
},
|
||||
{
|
||||
Name: "mismatched number of parameter",
|
||||
|
@ -2188,7 +2354,7 @@ func TestParseInterfaceMethod_Count_Invalid(t *testing.T) {
|
|||
code.TypeError,
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidParamError,
|
||||
ExpectedError: spec.ErrInvalidParam,
|
||||
},
|
||||
{
|
||||
Name: "mismatched method parameter type",
|
||||
|
|
|
@ -46,7 +46,8 @@ const (
|
|||
ComparatorFalse Comparator = "EQUAL_FALSE"
|
||||
)
|
||||
|
||||
// ArgumentTypeFromFieldType returns a type of required argument from the given struct field type
|
||||
// ArgumentTypeFromFieldType returns a type of required argument from the given
|
||||
// struct field type.
|
||||
func (c Comparator) ArgumentTypeFromFieldType(t code.Type) code.Type {
|
||||
switch c {
|
||||
case ComparatorIn, ComparatorNotIn:
|
||||
|
@ -56,7 +57,8 @@ func (c Comparator) ArgumentTypeFromFieldType(t code.Type) code.Type {
|
|||
}
|
||||
}
|
||||
|
||||
// NumberOfArguments returns the number of arguments required to perform the comparison
|
||||
// NumberOfArguments returns the number of arguments required to perform the
|
||||
// comparison.
|
||||
func (c Comparator) NumberOfArguments() int {
|
||||
switch c {
|
||||
case ComparatorBetween:
|
||||
|
@ -82,7 +84,7 @@ type queryParser struct {
|
|||
|
||||
func (p queryParser) parseQuery(rawTokens []string, paramIndex int) (QuerySpec, error) {
|
||||
if len(rawTokens) == 0 {
|
||||
return QuerySpec{}, QueryRequiredError
|
||||
return QuerySpec{}, ErrQueryRequired
|
||||
}
|
||||
|
||||
tokens := rawTokens
|
||||
|
|
|
@ -47,14 +47,16 @@ func (u UpdateFields) NumberOfArguments() int {
|
|||
return len(u)
|
||||
}
|
||||
|
||||
// UpdateField stores mapping between field name in the model and the parameter index
|
||||
// UpdateField stores mapping between field name in the model and the parameter
|
||||
// index.
|
||||
type UpdateField struct {
|
||||
FieldReference FieldReference
|
||||
ParamIndex int
|
||||
Operator UpdateOperator
|
||||
}
|
||||
|
||||
// UpdateOperator is a custom type that declares update operator to be used in an update operation
|
||||
// UpdateOperator is a custom type that declares update operator to be used in
|
||||
// an update operation
|
||||
type UpdateOperator string
|
||||
|
||||
// UpdateOperator constants
|
||||
|
@ -117,14 +119,14 @@ func (p interfaceMethodParser) parseUpdate(tokens []string) (Update, error) {
|
|||
if len(tokens) == 0 {
|
||||
requiredType := code.PointerType{ContainedType: p.StructModel.ReferencedType()}
|
||||
if len(p.Method.Params) <= 1 || p.Method.Params[1].Type != requiredType {
|
||||
return nil, InvalidUpdateFieldsError
|
||||
return nil, ErrInvalidUpdateFields
|
||||
}
|
||||
return UpdateModel{}, nil
|
||||
}
|
||||
|
||||
updateFieldTokens, ok := splitByAnd(tokens)
|
||||
if !ok {
|
||||
return nil, InvalidUpdateFieldsError
|
||||
return nil, ErrInvalidUpdateFields
|
||||
}
|
||||
|
||||
var updateFields UpdateFields
|
||||
|
@ -142,7 +144,7 @@ func (p interfaceMethodParser) parseUpdate(tokens []string) (Update, error) {
|
|||
|
||||
for _, field := range updateFields {
|
||||
if len(p.Method.Params) < field.ParamIndex+field.Operator.NumberOfArguments() {
|
||||
return nil, InvalidUpdateFieldsError
|
||||
return nil, ErrInvalidUpdateFields
|
||||
}
|
||||
|
||||
requiredType := field.Operator.ArgumentType(field.FieldReference.ReferencedField().Type)
|
||||
|
@ -158,7 +160,9 @@ func (p interfaceMethodParser) parseUpdate(tokens []string) (Update, error) {
|
|||
return updateFields, nil
|
||||
}
|
||||
|
||||
func (p interfaceMethodParser) parseUpdateField(t []string, paramIndex int) (UpdateField, error) {
|
||||
func (p interfaceMethodParser) parseUpdateField(t []string,
|
||||
paramIndex int) (UpdateField, error) {
|
||||
|
||||
if len(t) > 1 && t[len(t)-1] == "Push" {
|
||||
return p.createUpdateField(t[:len(t)-1], UpdateOperatorPush, paramIndex)
|
||||
}
|
||||
|
@ -168,7 +172,9 @@ func (p interfaceMethodParser) parseUpdateField(t []string, paramIndex int) (Upd
|
|||
return p.createUpdateField(t, UpdateOperatorSet, paramIndex)
|
||||
}
|
||||
|
||||
func (p interfaceMethodParser) createUpdateField(t []string, operator UpdateOperator, paramIndex int) (UpdateField, error) {
|
||||
func (p interfaceMethodParser) createUpdateField(t []string,
|
||||
operator UpdateOperator, paramIndex int) (UpdateField, error) {
|
||||
|
||||
fieldReference, ok := p.fieldResolver.ResolveStructField(p.StructModel, t)
|
||||
if !ok {
|
||||
return UpdateField{}, NewStructFieldNotFoundError(t)
|
||||
|
|
|
@ -5,7 +5,8 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// ExpectMultiLineString compares two multi-line strings and report the difference
|
||||
// ExpectMultiLineString compares two multi-line strings and report the
|
||||
// difference.
|
||||
func ExpectMultiLineString(expected, actual string) error {
|
||||
expectedLines := strings.Split(expected, "\n")
|
||||
actualLines := strings.Split(actual, "\n")
|
||||
|
@ -17,14 +18,14 @@ func ExpectMultiLineString(expected, actual string) error {
|
|||
|
||||
for i := 0; i < numberOfComparableLines; i++ {
|
||||
if expectedLines[i] != actualLines[i] {
|
||||
return fmt.Errorf("On line %d\nExpected: %v\nReceived: %v", i+1, expectedLines[i], actualLines[i])
|
||||
return fmt.Errorf("at line %d\nexpected: %v\nreceived: %v", i+1, expectedLines[i], actualLines[i])
|
||||
}
|
||||
}
|
||||
|
||||
if len(expectedLines) < len(actualLines) {
|
||||
return fmt.Errorf("Unexpected lines:\n%s", strings.Join(actualLines[len(expectedLines):], "\n"))
|
||||
return fmt.Errorf("unexpected lines:\n%s", strings.Join(actualLines[len(expectedLines):], "\n"))
|
||||
} else if len(expectedLines) > len(actualLines) {
|
||||
return fmt.Errorf("Missing lines:\n%s", strings.Join(expectedLines[len(actualLines):], "\n"))
|
||||
return fmt.Errorf("missing lines:\n%s", strings.Join(expectedLines[len(actualLines):], "\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -28,9 +28,9 @@ How are you?`
|
|||
|
||||
err := testutils.ExpectMultiLineString(expectedText, actualText)
|
||||
|
||||
expectedError := "On line 2\nExpected: this is an expected text\nReceived: this is a real text"
|
||||
expectedError := "at line 2\nexpected: this is an expected text\nreceived: this is a real text"
|
||||
if err == nil || err.Error() != expectedError {
|
||||
t.Errorf("Expected = %s\nReceived = %s", expectedError, err.Error())
|
||||
t.Errorf("expected = %s\nreceived = %s", expectedError, err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -46,9 +46,9 @@ how are you?`
|
|||
|
||||
err := testutils.ExpectMultiLineString(expectedText, actualText)
|
||||
|
||||
expectedError := "Missing lines:\nI'm fine...\nThank you..."
|
||||
expectedError := "missing lines:\nI'm fine...\nThank you..."
|
||||
if err == nil || err.Error() != expectedError {
|
||||
t.Errorf("Expected = %s\nReceived = %s", expectedError, err.Error())
|
||||
t.Errorf("expected = %s\nreceived = %s", expectedError, err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -64,9 +64,9 @@ Thank you...`
|
|||
|
||||
err := testutils.ExpectMultiLineString(expectedText, actualText)
|
||||
|
||||
expectedError := "Unexpected lines:\nI'm fine...\nThank you..."
|
||||
expectedError := "unexpected lines:\nI'm fine...\nThank you..."
|
||||
if err == nil || err.Error() != expectedError {
|
||||
t.Errorf("Expected = %s\nReceived = %s", expectedError, err.Error())
|
||||
t.Errorf("expected = %s\nreceived = %s", expectedError, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue