Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander Simmerl committed Mar 28, 2017
1 parent 3abd66b commit a02b0d9
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 0 deletions.
73 changes: 73 additions & 0 deletions service/invite/helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package invite

import (
"math/rand"
"reflect"
"testing"

"github.com/tapglue/snaas/platform/generate"
)

type prepareFunc func(t *testing.T, namespace string) Service

func testServicePut(t *testing.T, p prepareFunc) {
var (
invite = testInvite()
namespace = "service_put"
service = p(t, namespace)
)

created, err := service.Put(namespace, invite)
if err != nil {
t.Fatal(err)
}

list, err := service.Query(namespace, QueryOptions{
IDs: []uint64{
created.ID,
},
})
if err != nil {
t.Fatal(err)
}

if have, want := len(list), 1; have != want {
t.Fatalf("have %v, want %v", have, want)
}
if have, want := list[0], created; !reflect.DeepEqual(have, want) {
t.Errorf("have %v, want %v", have, want)
}

created.Deleted = true

updated, err := service.Put(namespace, created)
if err != nil {
t.Fatal(err)
}

list, err = service.Query(namespace, QueryOptions{
IDs: []uint64{
updated.ID,
},
})
if err != nil {
t.Fatal(err)
}

if have, want := list[0], updated; !reflect.DeepEqual(have, want) {
t.Errorf("have %v, want %v", have, want)
}
}

func testServiceQuery(t *testing.T, p prepareFunc) {
t.Errorf("testServiceQuery not implementd")
}

func testInvite() *Invite {
return &Invite{
Deleted: false,
Key: generate.RandomStringSafe(24),
UserID: uint64(rand.Int63()),
Value: generate.RandomStringSafe(24),
}
}
42 changes: 42 additions & 0 deletions service/invite/invite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package invite

import (
"time"

"github.com/tapglue/snaas/platform/service"
)

// Invite is a loose promise to create a conection if the person assoicated with
// the social id key-value signs up.
type Invite struct {
Deleted bool
ID uint64
Key string
UserID uint64
Value string
CreatedAt time.Time
UpdatedAt time.Time
}

// List is a collection of Invite.
type List []*Invite

// QueryOptions to narrow-down Invite queries.
type QueryOptions struct {
Deleted *bool
IDs []uint64
Keys []string
UserIDs []uint64
Values []string
}

// Service for Invite interactions.
type Service interface {
service.Lifecycle

Put(namespace string, i *Invite) (*Invite, error)
Query(namespace string, opts QueryOptions) (List, error)
}

// ServiceMiddleware is a chainable behaviour modifier for Service.
type ServiceMiddleware func(Service) Service
123 changes: 123 additions & 0 deletions service/invite/postgres.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package invite

import (
"fmt"
"time"

"github.com/jmoiron/sqlx"
"github.com/tapglue/snaas/platform/flake"
"github.com/tapglue/snaas/platform/pg"
)

const (
pgInsertInvite = `INSERT INTO
%s.invites(deleted, id, key, user_id, value, created_at, updated_at)
VALUES($1, $2, $3, $4, $5, $6, $7)`
pgUpdateInvite = `
UPDATE
%s.invites
SET
deleted = $2
updated_at = $3
WHERE
id = $1`

pgClauseDeleted = `deleted = ?`
pgClauseKeys = `key IN (?)`
pgClauseUserIDs = `user_id IN (?)`
pgClauseValues = `value IN (?)`

pgListInvites = `
SELECT
deleted, id, key, user_id, value, created_at, updated_at
FROM
%s.invites
%s`

pgOrderCreatedAt = `ORDER BY created_at DESC`

pgCreateScheme = `CREATE SCHEMA IF NOT EXISTS %s`
pgCreateTable = `CREATE TABLE IF NOT EXISTS %s.invites(
deleted BOOL DEFAULT false,
id BIGINT NOT NULL UNIQUE,
key TEXT NOT NULL,
uesr_id BIGINT NOT NULL,
value TEXT NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL
)`
pgDropTable = `DROP TABLE IF EXISTS %s.invites`
)

type pgService struct {
db *sqlx.DB
}

// PostgresService returns a Postgres based Service implementation.
func PostgresService(db *sqlx.DB) Service {
return &pgService{
db: db,
}
}

func (s *pgService) Put(ns string, i *Invite) (*Invite, error) {
if i.ID == 0 {
return s.insert(ns, i)
}

return nil, fmt.Errorf("invite.Put/update not implemented")
}

func (s *pgService) Query(ns string, opts QueryOptions) (List, error) {
return nil, fmt.Errorf("invite.Query not implemented")
}

func (s *pgService) Setup(ns string) error {
qs := []string{
fmt.Sprintf(pgCreateScheme, ns),
fmt.Sprintf(pgCreateTable, ns),
}

for _, q := range qs {
_, err := s.db.Exec(q)
if err != nil {
return fmt.Errorf("setup '%s': %s", q, err)
}
}

return nil
}

func (s *pgService) Teardown(ns string) error {
qs := []string{
fmt.Sprintf(pgDropTable, ns),
}

for _, q := range qs {
_, err := s.db.Exec(q)
if err != nil {
return fmt.Errorf("teardown '%s': %s", q, err)
}
}

return nil
}

func (s *pgService) insert(ns string, i *Invite) (*Invite, error) {
if i.CreatedAt.IsZero() {
i.CreatedAt = time.Now().UTC()
}

ts, err := time.Parse(pg.TimeFormat, i.CreatedAt.UTC().Format(pg.TimeFormat))
if err != nil {
return nil, err
}

i.CreatedAt = ts
i.UpdatedAt = ts

id, err := flake.NextID(flakeNamespace(ns))
if err != nil {
return nil, err
}
}
52 changes: 52 additions & 0 deletions service/invite/postgres_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// +build integration

package invite

import (
"flag"
"fmt"
"os/user"
"testing"

"github.com/jmoiron/sqlx"
"github.com/tapglue/snaas/platform/pg"
)

var pgTestURL string

func TestPostgresPut(t *testing.T) {
testServicePut(t, preparePostgres)
}

func TestPostgresQuery(t *testing.T) {
testServiceQuery(t, preparePostgres)
}

func preparePostgres(t *testing.T, namespace string) Service {
db, err := sqlx.Connect("postgres", pgTestURL)
if err != nil {
t.Fatal(err)
}

s := PostgresService(db)

if err := s.Teardown(namespace); err != nil {
t.Fatal(err)
}

return s
}

func init() {
u, err := user.Current()
if err != nil {
panic(err)
}

d := fmt.Sprintf(pg.URLTest, u.Username)

url := flag.String("postgres.url", d, "Postgres test connection URL")
flag.Parse()

pgTestURL = *url
}

0 comments on commit a02b0d9

Please sign in to comment.