Browse Source

graph2: Added Log type and queries, moved loader out of old graphql pkg.

1.0
Gisle Aune 6 years ago
parent
commit
2b05d90f4a
  1. 23
      cmd/rpdata-server/main.go
  2. 4
      graph2/gqlgen.yml
  3. 34
      graph2/queries/log.go
  4. 8
      graph2/schema/root.gql
  5. 97
      graph2/schema/types/Log.gql
  6. 0
      internal/loader/channel.go
  7. 0
      internal/loader/character.go
  8. 0
      internal/loader/loader.go
  9. 23
      model/log/filter.go
  10. 80
      model/log/log.go

23
cmd/rpdata-server/main.go

@ -8,6 +8,8 @@ import (
"runtime/debug"
"git.aiterp.net/rpdata/api/graph2"
"git.aiterp.net/rpdata/api/internal/auth"
"git.aiterp.net/rpdata/api/internal/loader"
"git.aiterp.net/rpdata/api/internal/store"
logModel "git.aiterp.net/rpdata/api/model/log"
"github.com/99designs/gqlgen/handler"
@ -20,7 +22,15 @@ func main() {
}
http.Handle("/", handler.Playground("RPData API", "/query"))
http.Handle("/query", handler.GraphQL(
http.Handle("/query", queryHandler())
go updateCharacters()
log.Fatal(http.ListenAndServe(":8081", nil))
}
func queryHandler() http.HandlerFunc {
handler := handler.GraphQL(
graph2.New(),
handler.RecoverFunc(func(ctx context.Context, err interface{}) error {
// send this panic somewhere
@ -29,11 +39,16 @@ func main() {
return fmt.Errorf("shit")
}),
))
)
go updateCharacters()
return func(w http.ResponseWriter, r *http.Request) {
l := loader.New()
r = r.WithContext(l.ToContext(r.Context()))
log.Fatal(http.ListenAndServe(":8081", nil))
r = auth.RequestWithToken(r)
handler.ServeHTTP(w, r)
}
}
func updateCharacters() {

4
graph2/gqlgen.yml

@ -23,5 +23,9 @@ models:
model: git.aiterp.net/rpdata/api/model/channel.Filter
Post:
model: git.aiterp.net/rpdata/api/model/log.Post
Log:
model: git.aiterp.net/rpdata/api/model/log.Log
LogsFilter:
model: git.aiterp.net/rpdata/api/model/log.Filter
Date:
model: git.aiterp.net/rpdata/api/model/scalars.Date

34
graph2/queries/log.go

@ -0,0 +1,34 @@
package queries
import (
"context"
"errors"
"git.aiterp.net/rpdata/api/internal/loader"
"git.aiterp.net/rpdata/api/model/log"
)
func (r *resolver) Log(ctx context.Context, id string) (log.Log, error) {
return log.FindID(id)
}
func (r *resolver) Logs(ctx context.Context, filter *log.Filter) ([]log.Log, error) {
logs, err := log.List(filter)
if err != nil {
return nil, err
}
if len(logs) >= 100 {
loader := loader.FromContext(ctx)
if loader == nil {
return nil, errors.New("no loader")
}
for _, log := range logs {
loader.PrimeCharacters("id", log.CharacterIDs...)
loader.PrimeChannels("name", log.ChannelName)
}
}
return logs, nil
}

8
graph2/schema/root.gql

@ -25,9 +25,17 @@ type Query {
posts(ids: [String!]!): [Post!]!
# Find log by ID
log(id: String!): Log!
# Find logs
logs(filter: LogsFilter): [Log!]!
# Find all distinct tags used in stories
tags: [Tag!]!
}
# A Date represents a RFC3339 encoded date with up to millisecond precision.
scalar Date

97
graph2/schema/types/Log.gql

@ -0,0 +1,97 @@
# A Log is the "file" of an RP session
type Log {
# A unique identifier for the log.
id: String!
# A secondary unique identifier for the log. This is a lot shorter and more suitable for storage when
# the link doesn't need to be as expressive.
shortId: String!
# The date for a log.
date: Date!
# The channel of a log.
channelName: String!
# Information about the channel this log is in.
channel: Channel!
# The session's title.
title: String!
# The log's event, which is the same as the tags in the previous logbot site.
# Empty string means that it's no event.
event: String!
# The description of a session, which is empty if unset.
description: String!
# Whether the log session is open.
open: Boolean!
# The characters involved in the log file.
characters: [Character!]!
# The posts of the logfile, which can be filtered by kinds.
posts(kinds:[String!]): [Post!]!
}
# Filter for logs query
input LogsFilter {
# Channels to limit results to (inclusive)
channels: [String!]
# Events to limit results to (inclusive)
events: [String!]
# Characters to limit results to (exclusive)
characters: [String!]
# Search post content
search: String
# Limit by whether it's open or not
open: Boolean
# Limit the amount of results you get back
limit: Int
}
# Input for addLog mutation
input LogAddInput {
# The date of the log.
date: Date!
# The channel where the log is set
channel: String!
# Optional: The log title
title: String
# Optional: Whether the log is open
open: Boolean
# Optional: The log event name
event: String
# Optional: A short description of the log
description: String
}
# Input for addLog mutation
input LogEditInput {
# The id of the log
id: String!
# The log title
title: String
# The log event name
event: String
# A short description of the log
description: String
# Open/close the log
open: Boolean
}

0
graphql/loader/channel.go → internal/loader/channel.go

0
graphql/loader/character.go → internal/loader/character.go

0
graphql/loader/loader.go → internal/loader/loader.go

23
model/log/filter.go

@ -7,26 +7,5 @@ type Filter struct {
Channels *[]string
Events *[]string
Open *bool
Limit *int32
}
// NewFilter makes a new filter
func NewFilter() *Filter {
return &Filter{}
}
// WithLimit adds a max amount of results to be returned.
func (filter *Filter) WithLimit(limit int) *Filter {
limitPtr := int32(limit)
filter.Limit = &limitPtr
return filter
}
// WithOpen filters on whether a log is open.
func (filter *Filter) WithOpen(limit int) *Filter {
limitPtr := int32(limit)
filter.Limit = &limitPtr
return filter
Limit int
}

80
model/log/log.go

@ -31,7 +31,7 @@ type Log struct {
ID string `bson:"_id"`
ShortID string `bson:"shortId"`
Date time.Time `bson:"date"`
Channel string `bson:"channel"`
ChannelName string `bson:"channel"`
Title string `bson:"title,omitempty"`
Event string `bson:"event,omitempty"`
Description string `bson:"description,omitempty"`
@ -55,7 +55,7 @@ func New(date time.Time, channelName, title, event, description string, open boo
ID: MakeLogID(date, channelName),
ShortID: "L" + strconv.Itoa(nextID),
Date: date,
Channel: channelName,
ChannelName: channelName,
Title: title,
Event: event,
Description: description,
@ -84,43 +84,44 @@ func FindID(id string) (Log, error) {
// List lists all logs
func List(filter *Filter) ([]Log, error) {
query := bson.M{}
limit := 0
// Run a text search
if filter.Search != nil {
searchResults := make([]string, 0, 32)
if filter != nil {
// Run a text search
if filter.Search != nil {
searchResults := make([]string, 0, 32)
postMutex.RLock()
err := postCollection.Find(bson.M{"$text": bson.M{"$search": *filter.Search}}).Distinct("logId", &searchResults)
if err != nil {
return nil, err
}
postMutex.RUnlock()
postMutex.RLock()
err := postCollection.Find(bson.M{"$text": bson.M{"$search": *filter.Search}}).Distinct("logId", &searchResults)
if err != nil {
return nil, err
}
postMutex.RUnlock()
// Posts always use shortId to refer to the log
query["shortId"] = bson.M{"$in": searchResults}
}
// Posts always use shortId to refer to the log
query["shortId"] = bson.M{"$in": searchResults}
}
// Find logs including any of the specified events and channels
if filter.Channels != nil {
query["channel"] = bson.M{"$in": *filter.Channels}
}
if filter.Events != nil {
query["event"] = bson.M{"$in": *filter.Events}
}
// Find logs including any of the specified events and channels
if filter.Channels != nil {
query["channel"] = bson.M{"$in": *filter.Channels}
}
if filter.Events != nil {
query["event"] = bson.M{"$in": *filter.Events}
}
// Find logs including all of the specified character IDs.
if filter.Characters != nil {
query["characterIds"] = bson.M{"$all": *filter.Characters}
}
// Find logs including all of the specified character IDs.
if filter.Characters != nil {
query["characterIds"] = bson.M{"$all": *filter.Characters}
}
// Limit to only open logs
if filter.Open != nil {
query["open"] = *filter.Open
}
// Limit to only open logs
if filter.Open != nil {
query["open"] = *filter.Open
}
limit := 0
if filter.Limit != nil {
limit = int(*filter.Limit)
// Set the limit from the filter
limit = filter.Limit
}
return listLog(query, limit)
@ -168,9 +169,20 @@ func (log *Log) Edit(title *string, event *string, description *string, open *bo
return nil
}
// Characters get all the characters for the character IDs stored in the
// log file.
func (log *Log) Characters() ([]character.Character, error) {
return character.ListIDs(log.CharacterIDs...)
}
// Channel gets the channel.
func (log *Log) Channel() (channel.Channel, error) {
return channel.FindName(log.ChannelName)
}
// Posts gets all the posts under the log. If no kinds are specified, it
// will get all posts
func (log *Log) Posts(kinds ...string) ([]Post, error) {
func (log *Log) Posts(kinds []string) ([]Post, error) {
postMutex.RLock()
defer postMutex.RUnlock()
@ -238,7 +250,7 @@ func (log *Log) UpdateCharacters() error {
characterUpdateMutex.Lock()
defer characterUpdateMutex.Unlock()
posts, err := log.Posts()
posts, err := log.Posts([]string{"action", "text", "chars"})
if err != nil {
return err
}

Loading…
Cancel
Save