Skip to content

Instantly share code, notes, and snippets.

@iampeter
Last active December 13, 2019 07:37
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save iampeter/fe98029d193e0bba421a3c18bbd45e4c to your computer and use it in GitHub Desktop.
Save iampeter/fe98029d193e0bba421a3c18bbd45e4c to your computer and use it in GitHub Desktop.
Implementing tagging in Golang with Postgres JSONB type and SQLX

When you need to handle text tags in Golang, eg. a Document can be tagged with software engineering, important and golang, you could do it with the Postgres text[] array type.

But with the jsonb type, you have all the marshalling and unmarshalling already there, so all you need to do is have a []string type, like below:

type JSONTags []string

func (tags *JSONTags) Scan(src interface{}) error {
	var jt types.JSONText

	if err := jt.Scan(src); err != nil {
		return err
	}

	if err := jt.Unmarshal(tags); err != nil {
		return err
	}

	return nil
}

func (tags *JSONTags) Value() (driver.Value, error) {
	var jt types.JSONText

	data, err := json.Marshal((*[]string)(tags))
	if err != nil {
		return nil, err
	}

	if err := jt.UnmarshalJSON(data); err != nil {
		return nil, err
	}

	return jt.Value()
}

func (tags *JSONTags) MarshalJSON() ([]byte, error) {
	return json.Marshal((*[]string)(tags))
}

func (tags *JSONTags) UnmarshalJSON(data []byte) error {
	if err := json.Unmarshal(data, (*[]string)(tags)); err != nil {
		return err
	}

	return nil
}

Then you can use it in your struct like this:

type Document struct {
  Title  string    `json:"title" db:"title"`
  Tags   *JSONTags `json:"tags" db:"tags"` // Note the pointer here
}

and you can unmarshal JSON like this into such a struct:

{
  "title": "Go in Action",
  "tags": ["software engineering", "important", "golang"]
}

and use the Document with Get() and Select() in SQLX, and you can still use it in Golang like a regular slice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment