Intro
Here we are once again! If you missed the last couple of posts I suggest reading them first to get a feeling for how our little prototype has evolved. This time around we’re going to be doing some refactoring to clean up a bit. The majority of what we’ll be doing is adding methods to our “database” struct.
The Method
What is a method? Well, you can think of it as a function that is attached to a struct. Or as A Tour of Go puts it
A method is a function with a special receiver argument.
In our code we have a struct GhostDatabase
. We can add methods with the following signature where the receiver is our struct.
func (gd *GhostDatabase) getLength() int
We could then call the method with the following
var db GhostDatabase
...load JSON code here...
length := db.getLength()
OK so what’s our complete method look like? In the case of most of the methods we’ll be putting in place is pretty easy to reason about.
func (gd *GhostDatabase) getLength() int {
return len(gd.Db[0].Data.Posts)
}
Many Methods
Now lets quickly knock out some useful methods. For the most part they do what they say on the tin, so I won’t go into detail on each one.
func (gd *GhostDatabase) getMobiledoc(i int) string {
return gd.Db[0].Data.Posts[i].Mobiledoc
}
func (gd *GhostDatabase) getPostId(i int) string {
return gd.Db[0].Data.Posts[i].ID
}
func (gd *GhostDatabase) getPostTitle(i int) string {
return gd.Db[0].Data.Posts[i].Title
}
func (gd *GhostDatabase) getPostSlug(i int) string {
return gd.Db[0].Data.Posts[i].Slug
}
func (gd *GhostDatabase) getPostStatus(i int) string {
return gd.Db[0].Data.Posts[i].Status
}
func (gd *GhostDatabase) getPostCreatedAt(i int) time.Time {
return gd.Db[0].Data.Posts[i].CreatedAt
}
func (gd *GhostDatabase) getPostUpdatedAt(i int) time.Time {
return gd.Db[0].Data.Posts[i].UpdatedAt
}
func (gd *GhostDatabase) getPostPublishedAt(i int) time.Time {
return gd.Db[0].Data.Posts[i].PublishedAt
}
func (gd *GhostDatabase) getPostFeatureImage(i int) string {
return gd.Db[0].Data.Posts[i].FeatureImage
}
Tags
One thing that we haven’t looked into so far is retrieving the tags associated with a post. Since we’re working on adding methods now is a great time to work that out. Let’s talk through what we need to do.
First we need to loop through the “database” of post tags. From here we check to see if the PostID
field matches with the post ID, pid
, we pass into the function. We then assign the tag ID to a variable, tagId
.
Next we’ll loop our way though the Tags
“database” and check to see if the current tag id matches with tagId
. If there is a match we append the tag name to a slice r
. Once we’re done we return r
.
Let’s see what that looks like in practice.
func (gd *GhostDatabase) getTags(pid string) []string {
var r []string
for i := 0; i < len(gd.Db[0].Data.PostsTags); i++ {
if gd.Db[0].Data.PostsTags[i].PostID == pid {
tagId := gd.Db[0].Data.PostsTags[i].TagID
for j := 0; j < len(gd.Db[0].Data.Tags); j++ {
if gd.Db[0].Data.Tags[j].ID == tagId {
r = append(r, gd.Db[0].Data.Tags[j].Name)
}
}
}
}
return r
}
Not to shabby.
Next Time
That’s all of our methods for now. With them out of the way I believe we have all the parts need to actually start writing our Markdown files!
Enjoy this post? |
---|
How about buying me a coffee? |
Code Listing
package main
import (
"encoding/json"
"fmt"
"io"
"os"
"reflect"
"strconv"
"strings"
"time"
)
type GhostDatabase struct {
Db []struct {
Meta struct {
ExportedOn int64 `json:"exported_on"`
Version string `json:"version"`
} `json:"meta"`
Data struct {
Posts []struct {
ID string `json:"id"`
UUID string `json:"uuid"`
Title string `json:"title"`
Slug string `json:"slug"`
Mobiledoc string `json:"mobiledoc"`
HTML string `json:"html"`
CommentID string `json:"comment_id"`
Plaintext string `json:"plaintext"`
FeatureImage string `json:"feature_image"`
Featured int `json:"featured"`
Type string `json:"type"`
Status string `json:"status"`
Locale interface{} `json:"locale"`
Visibility string `json:"visibility"`
EmailRecipientFilter string `json:"email_recipient_filter"`
AuthorID string `json:"author_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
PublishedAt time.Time `json:"published_at"`
CustomExcerpt interface{} `json:"custom_excerpt"`
CodeinjectionHead interface{} `json:"codeinjection_head"`
CodeinjectionFoot interface{} `json:"codeinjection_foot"`
CustomTemplate interface{} `json:"custom_template"`
CanonicalURL interface{} `json:"canonical_url"`
} `json:"posts"`
PostsAuthors []struct {
ID string `json:"id"`
PostID string `json:"post_id"`
AuthorID string `json:"author_id"`
SortOrder int `json:"sort_order"`
} `json:"posts_authors"`
PostsMeta []interface{} `json:"posts_meta"`
PostsTags []struct {
ID string `json:"id"`
PostID string `json:"post_id"`
TagID string `json:"tag_id"`
SortOrder int `json:"sort_order"`
} `json:"posts_tags"`
Roles []struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"roles"`
RolesUsers []struct {
ID string `json:"id"`
RoleID string `json:"role_id"`
UserID string `json:"user_id"`
} `json:"roles_users"`
Settings []struct {
ID string `json:"id"`
Group string `json:"group"`
Key string `json:"key"`
Value string `json:"value"`
Type string `json:"type"`
Flags interface{} `json:"flags"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"settings"`
Tags []struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description interface{} `json:"description"`
FeatureImage interface{} `json:"feature_image"`
ParentID interface{} `json:"parent_id"`
Visibility string `json:"visibility"`
OgImage interface{} `json:"og_image"`
OgTitle interface{} `json:"og_title"`
OgDescription interface{} `json:"og_description"`
TwitterImage interface{} `json:"twitter_image"`
TwitterTitle interface{} `json:"twitter_title"`
TwitterDescription interface{} `json:"twitter_description"`
MetaTitle interface{} `json:"meta_title"`
MetaDescription interface{} `json:"meta_description"`
CodeinjectionHead interface{} `json:"codeinjection_head"`
CodeinjectionFoot interface{} `json:"codeinjection_foot"`
CanonicalURL interface{} `json:"canonical_url"`
AccentColor interface{} `json:"accent_color"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"tags"`
Users []struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Password string `json:"password"`
Email string `json:"email"`
ProfileImage string `json:"profile_image"`
CoverImage interface{} `json:"cover_image"`
Bio interface{} `json:"bio"`
Website interface{} `json:"website"`
Location interface{} `json:"location"`
Facebook interface{} `json:"facebook"`
Twitter interface{} `json:"twitter"`
Accessibility string `json:"accessibility"`
Status string `json:"status"`
Locale interface{} `json:"locale"`
Visibility string `json:"visibility"`
MetaTitle interface{} `json:"meta_title"`
MetaDescription interface{} `json:"meta_description"`
Tour interface{} `json:"tour"`
LastSeen time.Time `json:"last_seen"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"users"`
} `json:"data"`
} `json:"db"`
}
type Mobiledoc struct {
Version string `json:"version"`
Markups []interface{} `json:"markups"`
Atoms []interface{} `json:"atoms"`
Cards [][]interface{} `json:"cards"`
Sections [][]interface{} `json:"sections"`
GhostVersion string `json:"ghostVersion"`
}
func (gd *GhostDatabase) getLength() int {
return len(gd.Db[0].Data.Posts)
}
func (gd *GhostDatabase) getMobiledoc(i int) string {
return gd.Db[0].Data.Posts[i].Mobiledoc
}
func (gd *GhostDatabase) getPostId(i int) string {
return gd.Db[0].Data.Posts[i].ID
}
func (gd *GhostDatabase) getPostTitle(i int) string {
return gd.Db[0].Data.Posts[i].Title
}
func (gd *GhostDatabase) getPostSlug(i int) string {
return gd.Db[0].Data.Posts[i].Slug
}
func (gd *GhostDatabase) getPostStatus(i int) string {
return gd.Db[0].Data.Posts[i].Status
}
func (gd *GhostDatabase) getPostCreatedAt(i int) time.Time {
return gd.Db[0].Data.Posts[i].CreatedAt
}
func (gd *GhostDatabase) getPostUpdatedAt(i int) time.Time {
return gd.Db[0].Data.Posts[i].UpdatedAt
}
func (gd *GhostDatabase) getPostPublishedAt(i int) time.Time {
return gd.Db[0].Data.Posts[i].PublishedAt
}
func (gd *GhostDatabase) getPostFeatureImage(i int) string {
return gd.Db[0].Data.Posts[i].FeatureImage
}
func (gd *GhostDatabase) getTags(pid string) []string {
var r []string
for i := 0; i < len(gd.Db[0].Data.PostsTags); i++ {
if gd.Db[0].Data.PostsTags[i].PostID == pid {
tagId := gd.Db[0].Data.PostsTags[i].TagID
for j := 0; j < len(gd.Db[0].Data.Tags); j++ {
if gd.Db[0].Data.Tags[j].ID == tagId {
r = append(r, gd.Db[0].Data.Tags[j].Name)
}
}
}
}
return r
}
func main() {
fmt.Println("ghost2hugo")
file, err := os.Open("shindakun-dot-net.ghost.2022-03-18-22-02-58.json")
if err != nil {
fmt.Println(err)
}
defer file.Close()
b, err := io.ReadAll(file)
if err != nil {
fmt.Println(err)
}
var db GhostDatabase
err = json.Unmarshal(b, &db)
if err != nil {
fmt.Println(err)
}
for i := 0; i < db.getLength(); i++ {
fmt.Println(db.getPostTitle(i))
fmt.Println(db.getPostSlug(i))
fmt.Println(db.getPostStatus(i))
fmt.Println(db.getPostCreatedAt(i))
fmt.Println(db.getPostUpdatedAt(i))
fmt.Println(db.getPostPublishedAt(i))
fmt.Println(db.getPostFeatureImage(i))
id := db.getPostId(i)
tags := db.getTags(id)
fmt.Println(tags)
c := strings.ReplaceAll(db.getMobiledoc(i), "`", "%'")
cc := "`" + c + "`"
ucn, err := strconv.Unquote(cc)
if err != nil {
fmt.Println(err, ucn)
}
ucn = strings.ReplaceAll(ucn, "%'", "`")
var md Mobiledoc
err = json.Unmarshal([]byte(ucn), &md)
if err != nil {
fmt.Println(err)
}
if reflect.ValueOf(md.Cards).Len() > 0 {
card := md.Cards[0][1]
bbb := card.(map[string]interface{})
fmt.Println(bbb["markdown"])
}
fmt.Println("---")
}
}