feat: add subscriptions and rework interfaces

This commit is contained in:
Jon Lundy
2022-08-09 16:23:33 -06:00
parent 82f23ae323
commit 0642879c07
16 changed files with 1368 additions and 627 deletions

View File

@@ -1,6 +1,5 @@
extend type Query {
events(streamID: String! paging: PageInput): Connection!
}
scalar Time
scalar Map
type Connection {
paging: PageInfo!
@@ -21,26 +20,24 @@ interface Edge {
id: ID!
}
type Event implements Edge {
id: ID!
payload: String!
tags: [String!]!
meta: Meta!
}
type Meta {
id: String!
eventID: String! @goField(name: "getEventID")
streamID: String!
created: Time!
position: Int!
}
scalar Time
directive @goModel(
model: String
models: [String!]
) on OBJECT | INPUT_OBJECT | SCALAR | ENUM | INTERFACE | UNION
directive @goField(
forceResolver: Boolean
name: String
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
directive @goTag(
key: String!
value: String
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION

View File

@@ -1,6 +1,11 @@
package gql_ev
import "github.com/sour-is/ev/pkg/es/event"
import (
"context"
"encoding/json"
"github.com/sour-is/ev/pkg/es/event"
)
type Edge interface {
IsEdge()
@@ -11,14 +16,19 @@ type Connection struct {
Edges []Edge `json:"edges"`
}
type Event struct {
type PostEvent struct {
ID string `json:"id"`
Payload string `json:"payload"`
Tags []string `json:"tags"`
Meta *event.Meta `json:"meta"`
}
func (Event) IsEdge() {}
func (PostEvent) IsEdge() {}
func (e *PostEvent) PayloadJSON(ctx context.Context) (m map[string]interface{}, err error) {
err = json.Unmarshal([]byte(e.Payload), &m)
return
}
type PageInfo struct {
Next bool `json:"next"`

View File

@@ -0,0 +1,15 @@
extend type Query {
posts(streamID: String! paging: PageInput): Connection!
}
extend type Subscription {
postAdded(streamID: String!): PostEvent
}
type PostEvent implements Edge {
id: ID!
payload: String!
payloadJSON: Map!
tags: [String!]!
meta: Meta!
}

View File

@@ -2,9 +2,12 @@ package gql_ev
import (
"context"
"fmt"
"log"
"time"
"github.com/sour-is/ev/pkg/es/driver"
"github.com/sour-is/ev/pkg/es/service"
"github.com/sour-is/ev/pkg/es"
"github.com/sour-is/ev/pkg/msgbus"
)
// This file will not be regenerated automatically.
@@ -12,15 +15,15 @@ import (
// It serves as dependency injection for your app, add any dependencies you require here.
type Resolver struct {
es driver.EventStore
es *es.EventStore
}
func New(es driver.EventStore) *Resolver {
func New(es *es.EventStore) *Resolver {
return &Resolver{es}
}
// Events is the resolver for the events field.
func (r *Resolver) Events(ctx context.Context, streamID string, paging *PageInput) (*Connection, error) {
// Posts is the resolver for the events field.
func (r *Resolver) Posts(ctx context.Context, streamID string, paging *PageInput) (*Connection, error) {
lis, err := r.es.Read(ctx, streamID, paging.GetIdx(0), paging.GetCount(30))
if err != nil {
return nil, err
@@ -31,12 +34,12 @@ func (r *Resolver) Events(ctx context.Context, streamID string, paging *PageInpu
e := lis[i]
m := e.EventMeta()
post, ok := e.(*service.PostEvent)
post, ok := e.(*msgbus.PostEvent)
if !ok {
continue
}
edges = append(edges, Event{
edges = append(edges, PostEvent{
ID: lis[i].EventMeta().EventID.String(),
Payload: string(post.Payload),
Tags: post.Tags,
@@ -62,3 +65,50 @@ func (r *Resolver) Events(ctx context.Context, streamID string, paging *PageInpu
Edges: edges,
}, nil
}
func (r *Resolver) PostAdded(ctx context.Context, streamID string) (<-chan *PostEvent, error) {
es := r.es.EventStream()
if es == nil {
return nil, fmt.Errorf("EventStore does not implement streaming")
}
sub, err := es.Subscribe(ctx, streamID)
if err != nil {
return nil, err
}
ch := make(chan *PostEvent)
go func() {
defer func() {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
log.Print(sub.Close(ctx))
}()
for sub.Recv(ctx) {
events, err := sub.Events(ctx)
if err != nil {
break
}
for _, e := range events {
m := e.EventMeta()
if p, ok := e.(*msgbus.PostEvent); ok {
select {
case ch <- &PostEvent{
ID: m.EventID.String(),
Payload: string(p.Payload),
Tags: p.Tags,
Meta: &m,
}:
continue
case <-ctx.Done():
return
}
}
}
}
}()
return ch, nil
}