Skip to content

Commit

Permalink
Add specs package (#17)
Browse files Browse the repository at this point in the history
* Add specs package

* Remove unused param
  • Loading branch information
Fs02 authored Nov 14, 2021
1 parent 5abe41c commit 8f1eb15
Show file tree
Hide file tree
Showing 9 changed files with 1,696 additions and 0 deletions.
63 changes: 63 additions & 0 deletions specs/aggregate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package specs

import (
"testing"

"github.com/go-rel/rel"
"github.com/go-rel/rel/where"
"github.com/stretchr/testify/assert"
)

// Aggregate tests count specifications.
func Aggregate(t *testing.T, repo rel.Repository) {
// preparte tests data
var (
user = User{Name: "name1", Gender: "male", Age: 10}
)

repo.MustInsert(ctx, &user)

waitForReplication()

tests := []rel.Query{
rel.From("users").Where(where.Eq("id", user.ID)),
rel.From("users").Where(where.Eq("name", "name1")),
rel.From("users").Where(where.Eq("age", 10)),
rel.From("users").Where(where.Eq("id", user.ID), where.Eq("name", "name1")),
rel.From("users").Where(where.Eq("id", user.ID), where.Eq("name", "name1"), where.Eq("age", 10)),
rel.From("users").Where(where.Eq("id", user.ID)).OrWhere(where.Eq("name", "name1")),
rel.From("users").Where(where.Eq("id", user.ID)).OrWhere(where.Eq("name", "name1"), where.Eq("age", 10)),
rel.From("users").Where(where.Eq("id", user.ID)).OrWhere(where.Eq("name", "name1")).OrWhere(where.Eq("age", 10)),
rel.From("users").Where(where.Ne("gender", "male")),
rel.From("users").Where(where.Gt("age", 59)),
rel.From("users").Where(where.Gte("age", 60)),
rel.From("users").Where(where.Lt("age", 11)),
rel.From("users").Where(where.Lte("age", 10)),
rel.From("users").Where(where.Nil("note")),
rel.From("users").Where(where.NotNil("name")),
rel.From("users").Where(where.In("id", 1, 2, 3)),
rel.From("users").Where(where.Nin("id", 1, 2, 3)),
rel.From("users").Where(where.Like("name", "name%")),
rel.From("users").Where(where.NotLike("name", "noname%")),
rel.From("users").Where(where.Fragment("id > 0")),
rel.From("users").Where(where.Not(where.Eq("id", 1), where.Eq("name", "name1"), where.Eq("age", 10))),
// this query is not supported.
// group query is automatically removed.
// use all instead for complex aggregation.
rel.From("users").Limit(10),
rel.From("users").Group("gender"),
rel.From("users").Group("age").Having(where.Gt("age", 10)),
}

for _, query := range tests {
t.Run("Aggregate", func(t *testing.T) {
count, err := repo.Aggregate(ctx, query, "count", "id")
assert.Nil(t, err)
assert.NotZero(t, count)

sum, err := repo.Aggregate(ctx, query, "sum", "id")
assert.Nil(t, err)
assert.NotZero(t, sum)
})
}
}
78 changes: 78 additions & 0 deletions specs/constraint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package specs

import (
"testing"

"github.com/go-rel/rel"
)

func createExtra(repo rel.Repository, slug string) Extra {
var user User
repo.MustInsert(ctx, &user)

extra := Extra{Slug: &slug, UserID: user.ID}
repo.MustInsert(ctx, &extra)
return extra
}

// UniqueConstraintOnInsert tests unique constraint specifications on insert.
func UniqueConstraintOnInsert(t *testing.T, repo rel.Repository) {
var (
existing = createExtra(repo, "unique-insert")
err = repo.Insert(ctx, &Extra{Slug: existing.Slug})
)

assertConstraint(t, err, rel.UniqueConstraint, "slug")
}

// UniqueConstraintOnUpdate tests unique constraint specifications on insert.
func UniqueConstraintOnUpdate(t *testing.T, repo rel.Repository) {
var (
record = createExtra(repo, "unique-record")
existing = createExtra(repo, "unique-update-existing")
err = repo.Update(ctx, &Extra{ID: record.ID, Slug: existing.Slug})
)

assertConstraint(t, err, rel.UniqueConstraint, "slug")
}

// ForeignKeyConstraintOnInsert tests foreign key constraint specifications on insert.
func ForeignKeyConstraintOnInsert(t *testing.T, repo rel.Repository) {
var (
err = repo.Insert(ctx, &Extra{UserID: 1000})
)

assertConstraint(t, err, rel.ForeignKeyConstraint, "user_id")
}

// ForeignKeyConstraintOnUpdate tests foreign key constraint specifications on update.
func ForeignKeyConstraintOnUpdate(t *testing.T, repo rel.Repository) {
var (
record = createExtra(repo, "fk-slug")
)

record.UserID = 1000
err := repo.Update(ctx, &record)
assertConstraint(t, err, rel.ForeignKeyConstraint, "user_id")
}

// CheckConstraintOnInsert tests foreign key constraint specifications on insert.
func CheckConstraintOnInsert(t *testing.T, repo rel.Repository) {
var (
err = repo.Insert(ctx, &Extra{Score: 150})
)

assertConstraint(t, err, rel.CheckConstraint, "score")
}

// CheckConstraintOnUpdate tests foreign key constraint specifications.
func CheckConstraintOnUpdate(t *testing.T, repo rel.Repository) {
var (
record = createExtra(repo, "check-slug")
)

// updating
record.Score = 150
err := repo.Update(ctx, &record)
assertConstraint(t, err, rel.CheckConstraint, "score")
}
171 changes: 171 additions & 0 deletions specs/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package specs

import (
"testing"

"github.com/go-rel/rel"
"github.com/go-rel/rel/where"
"github.com/stretchr/testify/assert"
)

// Delete tests delete specifications.
func Delete(t *testing.T, repo rel.Repository) {
var (
address = Address{
Name: "address",
User: User{Name: "user", Age: 100},
}
)

repo.MustInsert(ctx, &address)
assert.NotEqual(t, 0, address.ID)
assert.NotEqual(t, 0, address.User.ID)

assert.Nil(t, repo.Delete(ctx, &address))

waitForReplication()

assert.Equal(t, rel.NotFoundError{}, repo.Find(ctx, &Address{}, where.Eq("id", address.ID)))
// not deleted because cascade disabled
assert.Nil(t, repo.Find(ctx, &User{}, where.Eq("id", address.User.ID)))
}

// DeleteAll tests delete specifications.
func DeleteAll(t *testing.T, repo rel.Repository) {
var (
addresses = []Address{
{Name: "address1"},
{Name: "address2"},
}
)

repo.MustInsertAll(ctx, &addresses)
assert.NotEqual(t, 0, addresses[0].ID)
assert.NotEqual(t, 0, addresses[1].ID)

assert.Nil(t, repo.DeleteAll(ctx, &addresses))

waitForReplication()
assert.Zero(t, repo.MustCount(ctx, "addresses", where.In("id", addresses[0].ID, addresses[1].ID)))
}

// DeleteBelongsTo tests delete specifications.
func DeleteBelongsTo(t *testing.T, repo rel.Repository) {
var (
address = Address{
Name: "address",
User: User{Name: "user", Age: 100},
}
)

repo.MustInsert(ctx, &address)
assert.NotEqual(t, 0, address.ID)
assert.NotEqual(t, 0, address.User.ID)

assert.Nil(t, repo.Delete(ctx, &address, rel.Cascade(true)))

waitForReplication()

assert.Equal(t, rel.NotFoundError{}, repo.Find(ctx, &Address{}, where.Eq("id", address.ID)))
assert.Equal(t, rel.NotFoundError{}, repo.Find(ctx, &User{}, where.Eq("id", address.User.ID)))
}

// DeleteHasOne tests delete specifications.
func DeleteHasOne(t *testing.T, repo rel.Repository) {
var (
user = User{
Name: "user",
Age: 100,
PrimaryAddress: &Address{Name: "primary address"},
}
)

repo.MustInsert(ctx, &user)
assert.NotEqual(t, 0, user.ID)
assert.NotEqual(t, 0, user.PrimaryAddress.ID)

assert.Nil(t, repo.Delete(ctx, &user, rel.Cascade(true)))

waitForReplication()

assert.Equal(t, rel.NotFoundError{}, repo.Find(ctx, &User{}, where.Eq("id", user.ID)))
assert.Equal(t, rel.NotFoundError{}, repo.Find(ctx, &Address{}, where.Eq("id", user.PrimaryAddress.ID)))
}

// DeleteHasMany tests delete specifications.
func DeleteHasMany(t *testing.T, repo rel.Repository) {
tests := []struct {
name string
user User
}{
{
name: "with empty has many",
user: User{
Name: "user",
Age: 100,
Addresses: []Address{},
},
},
{
name: "with non-empty has many",
user: User{
Name: "user",
Age: 100,
Addresses: []Address{
{Name: "address 1"},
{Name: "address 2"},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
repo.MustInsert(ctx, &tt.user)
assert.NotEqual(t, 0, tt.user.ID)
for _, addr := range tt.user.Addresses {
assert.NotEqual(t, 0, addr.ID)
}

assert.Nil(t, repo.Delete(ctx, &tt.user, rel.Cascade(true)))

waitForReplication()

assert.Equal(t, rel.NotFoundError{}, repo.Find(ctx, &User{}, where.Eq("id", tt.user.ID)))
for _, addr := range tt.user.Addresses {
assert.Equal(t, rel.NotFoundError{}, repo.Find(ctx, &Address{}, where.Eq("id", addr.ID)))
}
})
}
}

// DeleteAny tests delete all specifications.
func DeleteAny(t *testing.T, repo rel.Repository) {
repo.MustInsert(ctx, &User{Name: "delete", Age: 100})
repo.MustInsert(ctx, &User{Name: "delete", Age: 100})
repo.MustInsert(ctx, &User{Name: "other delete", Age: 110})

waitForReplication()

tests := []rel.Query{
rel.From("users").Where(where.Eq("name", "delete")),
rel.From("users").Where(where.Eq("name", "other delete"), where.Gt("age", 100)),
}

for _, query := range tests {
var result []User
t.Run("DeleteAny", func(t *testing.T) {
assert.Nil(t, repo.FindAll(ctx, &result, query))
assert.NotEqual(t, 0, len(result))

deletedCount, err := repo.DeleteAny(ctx, query)
assert.Nil(t, err)
assert.NotZero(t, deletedCount)

waitForReplication()

assert.Nil(t, repo.FindAll(ctx, &result, query))
assert.Zero(t, len(result))
})
}
}
Loading

0 comments on commit 8f1eb15

Please sign in to comment.