feat: add subscriptions and rework interfaces
This commit is contained in:
@@ -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
|
||||
@@ -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"`
|
||||
|
||||
15
api/gql_ev/msgbus.graphqls
Normal file
15
api/gql_ev/msgbus.graphqls
Normal 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!
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user