sqlite3

package module
v0.0.0-...-66da8e5 Latest Latest
Warning

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

Go to latest
Published: Dec 6, 2015 License: MIT Imports: 8 Imported by: 0

README

REST Layer SQLite3 Backend

godoc license build

This REST Layer resource storage backend stores data in a SQLite3 database using database/sql and go-sqlite3.

Usage

This backend assumes that you have created the database schema in SQLite3 to match your REST API schema. For a reasonably complete example, look at example_test.go. To run the example, copy it to a new location, rename it to example.go, change the package name to main, and change the name of the Example function to main, finally, go run example.go.

Caveats

This backend does not currently implement the following features of the interface:

  • array fields
  • dict fields
  • $exists filter (not applicable to a DB with predefined schema)
  • field selection
  • field aliasing
  • embedding
  • field parameters

Documentation

Overview

Package sql is a REST Layer resource storage handler for databases supported via drivers for database/sql. It implements the Storer interface defined in rest-layer/resource/storage.go.

Example
package main

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

	"github.com/jxstanford/rest-layer-sqlite3"
	_ "github.com/mattn/go-sqlite3"
	"github.com/rs/cors"
	"github.com/rs/rest-layer/resource"
	"github.com/rs/rest-layer/rest"
	"github.com/rs/rest-layer/schema"
)

const (
	DB_DRIVER    = "sqlite3"
	DB_FILE      = "./example.db"
	USER_TABLE   = "users"
	POST_TABLE   = "posts"
	ENABLE_FK    = "PRAGMA foreign_keys = ON;"
	USERS_UP_DDL = "CREATE TABLE `" + USER_TABLE + "` (`id` VARCHAR(128) PRIMARY KEY,`etag` VARCHAR(128),`updated` VARCHAR(128),`created` VARCHAR(128), `name` VARCHAR(150));"
	POSTS_UP_DDL = "CREATE TABLE `" + POST_TABLE + "` (`id` VARCHAR(128) PRIMARY KEY,`etag` VARCHAR(128),`updated` VARCHAR(128), `created` VARCHAR(128), `user` VARCHAR(128) REFERENCES users(id) ON DELETE CASCADE, `public` INTEGER, `title` VARCHAR(150), `body` VARCHAR(100000));"
	USERS_DN_DDL = "DROP TABLE `" + USER_TABLE + "`;"
	POSTS_DN_DDL = "DROP TABLE `" + POST_TABLE + "`;"
)

var (
	user = schema.Schema{
		"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{
		"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,
			},
		},
	}
)

// handler returns a new handler with the database and table information,
// or an error.

func main() {
	dbDn()
	// get a database connection and set up the tables.
	db, err := sql.Open(DB_DRIVER, DB_FILE)
	if err != nil {
		log.Fatal(err)
	}
	dbUp(db)
	//defer dbDn(db)

	index := resource.NewIndex()

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

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

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

	http.Handle("/", cors.New(cors.Options{OptionsPassthrough: true}).Handler(api))

	log.Print("Serving API on http://localhost:8080")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}

func dbDn() {
	err := os.Remove(DB_FILE)
	if err != nil {
		//log.Warn(err)
	}
}

func dbUp(db *sql.DB) {
	var err error
	_, err = db.Exec(ENABLE_FK)
	if err != nil {
		log.Fatal(err)
	}
	_, err = db.Exec(USERS_UP_DDL)
	if err != nil {
		log.Fatal(err)
	}
	_, err = db.Exec(POSTS_UP_DDL)
	if err != nil {
		log.Fatal(err)
	}
}
Output:

Index

Examples

Constants

View Source
const (
	SQL_NOTFOUND_ERR = "sql: no rows in result set"
)

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, lookup *resource.Lookup) (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, lookup *resource.Lookup, page, perPage int) (*resource.ItemList, error)

Find searches for items in the backend store matching the lookup argument. If no items are found, an empty list is returned with no error. If a query operation is not implemented, a resource.ErrNotImplemented is returned.

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 atomically.

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