pgsql

package module
v0.0.0-...-992a108 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 15, 2018 License: MIT Imports: 9 Imported by: 0

README

REST Layer PostgreSQL Backend

godoc license build Go Report Card

This REST Layer resource storage backend stores data in a PostgreSQL Database using database/sql and pq.

UNDER HEAVY DEVELOPMENT BEWARE TO NOT BE USED ONLY UNDER HEAVY TESTING

Usage

import "github.com/safad/rest-layer-pgsql"

Open an SQL connection to PostgreSQL using database/sql:

const (
        DB_USER     = "postgres"
        DB_PASSWORD = "postgres"
        DB_NAME     = "test"
    )
dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable",
            DB_USER, DB_PASSWORD, DB_NAME)
        db, err := sql.Open("postgres", dbinfo)

Create a resource storage handler with a given DB/collection:

users_handler := pgsql.NewHandler(db, "users")

Use this handler with a resource:

index.Bind("users", users, users_handler, resource.DefaultConf)

Documentation

Overview

Package pgsql is a REST Layer resource storage handler for PostgreSQL using pgx

Example
package main

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"

	"github.com/rs/rest-layer/resource"
	"github.com/rs/rest-layer/rest"
	"github.com/rs/rest-layer/schema"
	"github.com/safad/rest-layer-pgsql"
)

var (
	user = schema.Schema{
		Fields: schema.Fields{
			"id":      schema.IDField,
			"created": schema.CreatedField,
			"updated": schema.UpdatedField,
			"name": schema.Field{
				Required:   true,
				Filterable: true,
				Sortable:   true,
				Validator: &schema.String{
					MaxLen: 150,
				},
			},
		},
	}

	// Define a post resource schema
	post = schema.Schema{
		Fields: schema.Fields{

			"id":      schema.IDField,
			"created": schema.CreatedField,
			"updated": schema.UpdatedField,
			"user": schema.Field{
				Required:   true,
				Filterable: true,
				Validator: &schema.Reference{
					Path: "users",
				},
			},
			"public": schema.Field{
				Filterable: true,
				Validator:  &schema.Bool{},
			},
			"title": schema.Field{
				Required: true,
				Validator: &schema.String{
					MaxLen: 150,
				},
			},
			"body": schema.Field{
				Validator: &schema.String{
					MaxLen: 100000,
				},
			},
		},
	}
)

func main() {
	const (
		DB_USER     = "postgres"
		DB_PASSWORD = ""
		DB_NAME     = "travis_ci_test"
	)
	dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable",
		DB_USER, DB_PASSWORD, DB_NAME)
	db, err := sql.Open("postgres", dbinfo)
	if err != nil {
		log.Fatalf("Can't connect to PostgreSQL: %s", err)
	}

	//time to set some tables up
	setupDB(db)

	index := resource.NewIndex()

	users := index.Bind("users", user, pgsql.NewHandler(db, "users"), resource.Conf{
		AllowedModes: resource.ReadWrite,
	})

	users.Bind("posts", "user", post, pgsql.NewHandler(db, "posts"), resource.Conf{
		AllowedModes: resource.ReadWrite,
	})

	api, err := rest.NewHandler(index)
	if err != nil {
		log.Fatalf("Invalid API configuration: %s", err)
	}

	// Bind the API under /api/ path
	http.Handle("/api/", http.StripPrefix("/api/", api))

	log.Print("Serving API on http://localhost:8080")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}
func setupDB(db *sql.DB) {
	var err error
	// create users table
	_, err = db.Exec("CREATE TABLE users (id character varying(128) NOT NULL, etag character varying(128), updated character varying(128), created character varying(128), name character varying(150), CONSTRAINT users_pkey PRIMARY KEY (id));")
	if err != nil {
		log.Fatal(err)
	}
	// create posts table
	_, err = db.Exec("CREATE TABLE posts (id character varying(128) NOT NULL, etag character varying(128), updated character varying(128), created character varying(128), \"user\" character varying(128), public integer title character varying(150), body character varying(100000), CONSTRAINT posts_pkey PRIMARY KEY (id), CONSTRAINT posts_user_fkey FOREIGN KEY (\"user\") REFERENCES users (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE);")
	if err != nil {
		log.Fatal(err)
	}
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler contains the session and table information for a SQL DB.

func NewHandler

func NewHandler(s *sql.DB, tableName string) *Handler

NewHandler creates an new SQL DB session handler.

func (Handler) Clear

func (h Handler) Clear(ctx context.Context, q *query.Query) (int, error)

Clear removes all items matching the lookup and returns the number of items removed as the first value. If a query operation is not implemented by the storage handler, a resource.ErrNotImplemented is returned.

func (*Handler) Delete

func (h *Handler) Delete(ctx context.Context, item *resource.Item) error

Delete deletes the provided item by its ID. The Etag of the item stored in the backend store must match the Etag of the provided item or a resource.ErrConflict must be returned. This check should be performed atomically.

If the provided item were not present in the backend store, a resource.ErrNotFound must be returned.

If the removal of the data is not immediate, the method must listen for cancellation on the passed ctx. If the operation is stopped due to context cancellation, the function must return the result of the ctx.Err() method.

func (Handler) Find

func (h Handler) Find(ctx context.Context, q *query.Query) (*resource.ItemList, error)

Find is the SELECT query in normal SQL life

func (*Handler) Insert

func (h *Handler) Insert(ctx context.Context, items []*resource.Item) error

Insert stores new items in the backend store. If any of the items already exist, no item should be inserted and a resource.ErrConflict must be returned. The insertion of the items is performed automatically. TODO: add checking for resource.ErrConflict error.

func (*Handler) Update

func (h *Handler) Update(ctx context.Context, item *resource.Item, original *resource.Item) error

Update replaces an item in the backend store with a new version. If the original item is not found, a resource.ErrNotFound is returned. If the etags don't match, a resource.ErrConflict is returned.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL