GraphQL query field post and list return all data except created_at. It always null. I check GetPostBySlug
and GetPostList
variables and it contain data from Postgres. Where is my mistake?
model.go
package post
type Post struct {
Slug string `db:"slug"`
Title string `db:"title"`
Content string `db:"content"`
Author string `db:"author"`
Category string `db:"category"`
CreatedAt string `db:"created_at"`
Published bool `db:"published"`
}
resolver.go
package post
import (
"context"
"github.com/graphql-go/graphql"
)
var postType = graphql.NewObject(
graphql.ObjectConfig{
Name: "Post",
Fields: graphql.Fields{
"slug": &graphql.Field{
Type: graphql.String,
},
"title": &graphql.Field{
Type: graphql.String,
},
"content": &graphql.Field{
Type: graphql.String,
},
"category": &graphql.Field{
Type: graphql.String,
},
"author": &graphql.Field{
Type: graphql.String,
},
"created_at": &graphql.Field{
Type: graphql.String,
},
"published": &graphql.Field{
Type: graphql.Boolean,
},
},
},
)
var queryType = graphql.NewObject(
graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"post": &graphql.Field{
Type: postType,
Description: "Get post by slug",
Args: graphql.FieldConfigArgument{
"slug": &graphql.ArgumentConfig{
Type: graphql.String,
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
var result interface{}
slug, _ := p.Args["slug"].(string)
result = GetPostBySlug(context.Background(), slug)
return result, nil
},
},
"list": &graphql.Field{
Type: graphql.NewList(postType),
Description: "Get post list",
Args: graphql.FieldConfigArgument{
"limit": &graphql.ArgumentConfig{
Type: graphql.Int,
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
var result interface{}
limit, _ := params.Args["limit"].(int)
result = GetPostList(context.Background(), limit)
return result, nil
},
},
},
})
var mutationType = graphql.NewObject(graphql.ObjectConfig{
Name: "Mutation",
Fields: graphql.Fields{
"create": &graphql.Field{
Type: postType,
Description: "Create new post",
Args: graphql.FieldConfigArgument{
"slug": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"title": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"content": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"category": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"author": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"published": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.Boolean),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
post := Post{
Slug: params.Args["slug"].(string),
Title: params.Args["title"].(string),
Content: params.Args["content"].(string),
Category: params.Args["category"].(string),
Author: params.Args["author"].(string),
Published: params.Args["published"].(bool),
}
if err := InsertPost(context.Background(), post); err != nil {
return nil, err
}
return nil, nil
},
},
"update": &graphql.Field{
Type: postType,
Description: "Update post",
Args: graphql.FieldConfigArgument{
"slug": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"title": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"content": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"category": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"author": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"published": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.Boolean),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
post := Post{}
if slug, slugOk := params.Args["slug"].(string); slugOk {
post.Slug = slug
}
if title, titleOk := params.Args["title"].(string); titleOk {
post.Title = title
}
if content, contentOk := params.Args["content"].(string); contentOk {
post.Content = content
}
if category, categoryOk := params.Args["category"].(string); categoryOk {
post.Category = category
}
if published, publishedOk := params.Args["published"].(bool); publishedOk {
post.Published = published
}
if old_slug, old_slugOk := params.Args["old-slug"].(string); old_slugOk {
if err := UpdatePost(context.Background(), post, old_slug); err != nil {
return nil, err
}
}
return nil, nil
},
},
"delete": &graphql.Field{
Type: postType,
Description: "Delete post by slug",
Args: graphql.FieldConfigArgument{
"slug": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
slug, _ := params.Args["slug"].(string)
if err := DeletePost(context.Background(), slug); err != nil {
return nil, err
}
return nil, nil
},
},
},
})
var Schema, _ = graphql.NewSchema(
graphql.SchemaConfig{
Query: queryType,
Mutation: mutationType,
},
)
repository.go
package post
import (
"context"
"errors"
"fmt"
"log"
"os"
"time"
"github.com/jackc/pgx/v4"
"github.com/joho/godotenv"
)
var (
db *pgx.Conn
Info *log.Logger
Warning *log.Logger
Error *log.Logger
)
func init() {
err := godotenv.Load("environment/.env")
if err != nil {
Error.Fatalf("Can't read \".env\" file: %s\n", err.Error())
}
Info = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
Warning = log.New(os.Stdout, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile)
Error = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
db, err = pgx.Connect(
context.Background(),
fmt.Sprintf(
"postgres://%s:%s@%s:%s/%s",
os.Getenv("POSTGRES_USER"),
os.Getenv("POSTGRES_PASSWORD"),
os.Getenv("POSTGRES_HOST"),
os.Getenv("POSTGRES_PORT"),
os.Getenv("POSTGRES_DB"),
),
)
if err != nil {
Error.Fatalf("Can't connect to database: %s\n", err.Error())
}
}
func GetPostBySlug(ctx context.Context, slug string) (result interface{}) {
row, err := db.Query(ctx, "SELECT slug, title, content, author, category, created_at, published FROM posts WHERE slug=$1 LIMIT 1", slug)
if err != nil {
Warning.Printf("GetPostBySlug query: %v\n", err.Error())
return err
}
var post Post
for row.Next() {
var dateTime time.Time
err = row.Scan(&post.Slug, &post.Title, &post.Content, &post.Author, &post.Category, &dateTime, &post.Published)
if err != nil {
Warning.Printf("Row scan: %v\n", err.Error())
return nil
}
post.CreatedAt = dateTime.Format("02.01.2006")
}
return post
}
func GetPostList(ctx context.Context, limit int) (result interface{}) {
var post Post
var posts []Post
var dateTime time.Time
rows, err := db.Query(ctx, "SELECT slug, title, content, author, category, created_at, published FROM posts LIMIT $1", limit)
if err != nil {
Warning.Printf("GetPostList query: %v\n", err.Error())
return err
}
for rows.Next() {
err = rows.Scan(&post.Slug, &post.Title, &post.Content, &post.Author, &post.Category, &dateTime, &post.Published)
if err != nil {
Warning.Printf("Row scan: %v\n", err.Error())
return nil
}
post.CreatedAt = dateTime.Format("02.01.2006")
posts = append(posts, post)
}
return posts
}
func InsertPost(ctx context.Context, post Post) error {
if SlugExists(ctx, post.Slug) {
Warning.Printf("Slug \"%s\" already exists!\n", post.Slug)
return errors.New("slug already exists")
}
_, err := db.Exec(
ctx,
"INSERT INTO posts (slug, title, content, author, category, created_at, published) VALUES ($1, $2, $3, $4, $5, CURRENT_TIMESTAMP, $6)",
post.Slug, post.Title, post.Content, post.Author, post.Category, post.Published,
)
if err != nil {
Warning.Printf("InsertPost exec query: %v\n", err.Error())
return err
}
return nil
}
func SlugExists(ctx context.Context, slug string) bool {
row, err := db.Query(ctx, "SELECT slug FROM posts WHERE slug=$1 LIMIT 1", slug)
if err != nil {
Error.Fatalf("SlugExists query: %v\n", err.Error())
}
var slug_exists string
for row.Next() {
err = row.Scan(&slug_exists)
if err != nil {
Error.Fatalf("Row scan: %v\n", err.Error())
}
}
return slug_exists != ""
}
func UpdatePost(ctx context.Context, post Post, old_slug string) error {
_, err := db.Exec(
ctx,
"UPDATE posts SET slug=$1, title=$2, content=$3, author=$4, category=$5, published=$6 WHERE slug=$7",
post.Slug, post.Title, post.Content, post.Author, post.Category, post.Published, old_slug,
)
if err != nil {
Warning.Printf("UpdatePost exec query: %v\n", err.Error())
return err
}
return nil
}
func DeletePost(ctx context.Context, slug string) error {
_, err := db.Exec(ctx, "DELETE FROM posts WHERE slug=$1", slug)
if err != nil {
Warning.Printf("DeletePost exec query: %v\n", err.Error())
return err
}
return nil
}
To sum up what we found in the comments
Rename GraphQL object created_at to createdAt