Add datastore functionality
diff --git a/rackspace/db/v1/datastores/doc.go b/rackspace/db/v1/datastores/doc.go
new file mode 100644
index 0000000..f36997a
--- /dev/null
+++ b/rackspace/db/v1/datastores/doc.go
@@ -0,0 +1 @@
+package datastores
diff --git a/rackspace/db/v1/datastores/fixtures.go b/rackspace/db/v1/datastores/fixtures.go
new file mode 100644
index 0000000..842aa77
--- /dev/null
+++ b/rackspace/db/v1/datastores/fixtures.go
@@ -0,0 +1,100 @@
+package datastores
+
+import (
+	"fmt"
+
+	"github.com/rackspace/gophercloud"
+)
+
+const version1JSON = `
+{
+	"id": "b00000b0-00b0-0b00-00b0-000b000000bb",
+	"links": [
+		{
+			"href": "https://api.staging.ord1.clouddb.rackspace.net/v1.0/1234/datastores/versions/b00000b0-00b0-0b00-00b0-000b000000bb",
+			"rel": "self"
+		},
+		{
+			"href": "https://api.staging.ord1.clouddb.rackspace.net/datastores/versions/b00000b0-00b0-0b00-00b0-000b000000bb",
+			"rel": "bookmark"
+		}
+	],
+	"name": "5.1"
+}
+`
+
+const version2JSON = `
+{
+	"id": "c00000b0-00c0-0c00-00c0-000b000000cc",
+	"links": [
+		{
+			"href": "https://api.staging.ord1.clouddb.rackspace.net/v1.0/1234/datastores/versions/c00000b0-00c0-0c00-00c0-000b000000cc",
+			"rel": "self"
+		},
+		{
+			"href": "https://api.staging.ord1.clouddb.rackspace.net/datastores/versions/c00000b0-00c0-0c00-00c0-000b000000cc",
+			"rel": "bookmark"
+		}
+	],
+	"name": "5.2"
+}
+`
+
+var versionsJSON = fmt.Sprintf(`"versions": [%s, %s]`, version1JSON, version2JSON)
+
+var singleDSJSON = fmt.Sprintf(`
+{
+  "default_version": "c00000b0-00c0-0c00-00c0-000b000000cc",
+  "id": "10000000-0000-0000-0000-000000000001",
+  "links": [
+    {
+      "href": "https://api.staging.ord1.clouddb.rackspace.net/v1.0/1234/datastores/10000000-0000-0000-0000-000000000001",
+      "rel": "self"
+    },
+    {
+      "href": "https://api.staging.ord1.clouddb.rackspace.net/datastores/10000000-0000-0000-0000-000000000001",
+      "rel": "bookmark"
+    }
+  ],
+  "name": "mysql",
+  %s
+}
+`, versionsJSON)
+
+var (
+	listDSResp       = fmt.Sprintf(`{"datastores":[%s]}`, singleDSJSON)
+	getDSResp        = fmt.Sprintf(`{"datastore":%s}`, singleDSJSON)
+	listVersionsResp = fmt.Sprintf(`{%s}`, versionsJSON)
+	getVersionResp   = fmt.Sprintf(`{"version":%s}`, version1JSON)
+)
+
+var exampleVersion1 = Version{
+	ID: "b00000b0-00b0-0b00-00b0-000b000000bb",
+	Links: []gophercloud.Link{
+		gophercloud.Link{Rel: "self", Href: "https://api.staging.ord1.clouddb.rackspace.net/v1.0/1234/datastores/versions/b00000b0-00b0-0b00-00b0-000b000000bb"},
+		gophercloud.Link{Rel: "bookmark", Href: "https://api.staging.ord1.clouddb.rackspace.net/datastores/versions/b00000b0-00b0-0b00-00b0-000b000000bb"},
+	},
+	Name: "5.1",
+}
+
+var exampleVersion2 = Version{
+	ID: "c00000b0-00c0-0c00-00c0-000b000000cc",
+	Links: []gophercloud.Link{
+		gophercloud.Link{Rel: "self", Href: "https://api.staging.ord1.clouddb.rackspace.net/v1.0/1234/datastores/versions/c00000b0-00c0-0c00-00c0-000b000000cc"},
+		gophercloud.Link{Rel: "bookmark", Href: "https://api.staging.ord1.clouddb.rackspace.net/datastores/versions/c00000b0-00c0-0c00-00c0-000b000000cc"},
+	},
+	Name: "5.2",
+}
+
+var exampleVersions = []Version{exampleVersion1, exampleVersion2}
+
+var exampleDatastore = Datastore{
+	DefaultVersion: "c00000b0-00c0-0c00-00c0-000b000000cc",
+	ID:             "10000000-0000-0000-0000-000000000001",
+	Links: []gophercloud.Link{
+		gophercloud.Link{Rel: "self", Href: "https://api.staging.ord1.clouddb.rackspace.net/v1.0/1234/datastores/10000000-0000-0000-0000-000000000001"},
+		gophercloud.Link{Rel: "bookmark", Href: "https://api.staging.ord1.clouddb.rackspace.net/datastores/10000000-0000-0000-0000-000000000001"},
+	},
+	Name:     "mysql",
+	Versions: exampleVersions,
+}
diff --git a/rackspace/db/v1/datastores/requests.go b/rackspace/db/v1/datastores/requests.go
new file mode 100644
index 0000000..767bdc3
--- /dev/null
+++ b/rackspace/db/v1/datastores/requests.go
@@ -0,0 +1,42 @@
+package datastores
+
+import (
+	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/pagination"
+)
+
+func List(client *gophercloud.ServiceClient) pagination.Pager {
+	pageFn := func(r pagination.PageResult) pagination.Page {
+		return DatastorePage{pagination.SinglePageBase(r)}
+	}
+	return pagination.NewPager(client, baseURL(client), pageFn)
+}
+
+func Get(client *gophercloud.ServiceClient, datastoreID string) GetResult {
+	var res GetResult
+
+	_, res.Err = client.Request("GET", resourceURL(client, datastoreID), gophercloud.RequestOpts{
+		OkCodes:      []int{200},
+		JSONResponse: &res.Body,
+	})
+
+	return res
+}
+
+func ListVersions(client *gophercloud.ServiceClient, datastoreID string) pagination.Pager {
+	pageFn := func(r pagination.PageResult) pagination.Page {
+		return VersionPage{pagination.SinglePageBase(r)}
+	}
+	return pagination.NewPager(client, versionsURL(client, datastoreID), pageFn)
+}
+
+func GetVersion(client *gophercloud.ServiceClient, datastoreID, versionID string) GetVersionResult {
+	var res GetVersionResult
+
+	_, res.Err = client.Request("GET", versionURL(client, datastoreID, versionID), gophercloud.RequestOpts{
+		OkCodes:      []int{200},
+		JSONResponse: &res.Body,
+	})
+
+	return res
+}
diff --git a/rackspace/db/v1/datastores/requests_test.go b/rackspace/db/v1/datastores/requests_test.go
new file mode 100644
index 0000000..36e6b32
--- /dev/null
+++ b/rackspace/db/v1/datastores/requests_test.go
@@ -0,0 +1,82 @@
+package datastores
+
+import (
+	"testing"
+
+	"github.com/rackspace/gophercloud/pagination"
+	th "github.com/rackspace/gophercloud/testhelper"
+	fake "github.com/rackspace/gophercloud/testhelper/client"
+	"github.com/rackspace/gophercloud/testhelper/fixture"
+)
+
+func TestList(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	fixture.SetupHandler(t, "/datastores", "GET", "", listDSResp, 200)
+
+	pages := 0
+
+	err := List(fake.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
+		pages++
+
+		actual, err := ExtractDatastores(page)
+		if err != nil {
+			return false, err
+		}
+
+		th.CheckDeepEquals(t, []Datastore{exampleDatastore}, actual)
+
+		return true, nil
+	})
+
+	th.AssertNoErr(t, err)
+	th.AssertEquals(t, 1, pages)
+}
+
+func TestGet(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	fixture.SetupHandler(t, "/datastores/{dsID}", "GET", "", getDSResp, 200)
+
+	ds, err := Get(fake.ServiceClient(), "{dsID}").Extract()
+	th.AssertNoErr(t, err)
+	th.AssertDeepEquals(t, &exampleDatastore, ds)
+}
+
+func TestListVersions(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	fixture.SetupHandler(t, "/datastores/{dsID}/versions", "GET", "", listVersionsResp, 200)
+
+	pages := 0
+
+	err := ListVersions(fake.ServiceClient(), "{dsID}").EachPage(func(page pagination.Page) (bool, error) {
+		pages++
+
+		actual, err := ExtractVersions(page)
+		if err != nil {
+			return false, err
+		}
+
+		th.CheckDeepEquals(t, exampleVersions, actual)
+
+		return true, nil
+	})
+
+	th.AssertNoErr(t, err)
+	th.AssertEquals(t, 1, pages)
+}
+
+func TestGetVersion(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	fixture.SetupHandler(t, "/datastores/{dsID}/versions/{versionID}", "GET", "", getVersionResp, 200)
+
+	ds, err := GetVersion(fake.ServiceClient(), "{dsID}", "{versionID}").Extract()
+	th.AssertNoErr(t, err)
+	th.AssertDeepEquals(t, &exampleVersion1, ds)
+}
diff --git a/rackspace/db/v1/datastores/results.go b/rackspace/db/v1/datastores/results.go
new file mode 100644
index 0000000..fbfb2cf
--- /dev/null
+++ b/rackspace/db/v1/datastores/results.go
@@ -0,0 +1,101 @@
+package datastores
+
+import (
+	"github.com/mitchellh/mapstructure"
+	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/pagination"
+)
+
+type Version struct {
+	ID    string
+	Links []gophercloud.Link
+	Name  string
+}
+
+type Datastore struct {
+	DefaultVersion string `json:"default_version" mapstructure:"default_version"`
+	ID             string
+	Links          []gophercloud.Link
+	Name           string
+	Versions       []Version
+}
+
+type GetResult struct {
+	gophercloud.Result
+}
+
+type GetVersionResult struct {
+	gophercloud.Result
+}
+
+type DatastorePage struct {
+	pagination.SinglePageBase
+}
+
+func (r DatastorePage) IsEmpty() (bool, error) {
+	is, err := ExtractDatastores(r)
+	if err != nil {
+		return true, err
+	}
+	return len(is) == 0, nil
+}
+
+func ExtractDatastores(page pagination.Page) ([]Datastore, error) {
+	casted := page.(DatastorePage).Body
+
+	var resp struct {
+		Datastores []Datastore `mapstructure:"datastores" json:"datastores"`
+	}
+
+	err := mapstructure.Decode(casted, &resp)
+	return resp.Datastores, err
+}
+
+func (r GetResult) Extract() (*Datastore, error) {
+	if r.Err != nil {
+		return nil, r.Err
+	}
+
+	var response struct {
+		Datastore Datastore `mapstructure:"datastore"`
+	}
+
+	err := mapstructure.Decode(r.Body, &response)
+	return &response.Datastore, err
+}
+
+type VersionPage struct {
+	pagination.SinglePageBase
+}
+
+func (r VersionPage) IsEmpty() (bool, error) {
+	is, err := ExtractVersions(r)
+	if err != nil {
+		return true, err
+	}
+	return len(is) == 0, nil
+}
+
+func ExtractVersions(page pagination.Page) ([]Version, error) {
+	casted := page.(VersionPage).Body
+
+	var resp struct {
+		Versions []Version `mapstructure:"versions" json:"versions"`
+	}
+
+	err := mapstructure.Decode(casted, &resp)
+	return resp.Versions, err
+}
+
+func (r GetVersionResult) Extract() (*Version, error) {
+	if r.Err != nil {
+		return nil, r.Err
+	}
+
+	var response struct {
+		Version Version `mapstructure:"version"`
+	}
+
+	err := mapstructure.Decode(r.Body, &response)
+	return &response.Version, err
+}
diff --git a/rackspace/db/v1/datastores/urls.go b/rackspace/db/v1/datastores/urls.go
new file mode 100644
index 0000000..c4d5248
--- /dev/null
+++ b/rackspace/db/v1/datastores/urls.go
@@ -0,0 +1,19 @@
+package datastores
+
+import "github.com/rackspace/gophercloud"
+
+func baseURL(c *gophercloud.ServiceClient) string {
+	return c.ServiceURL("datastores")
+}
+
+func resourceURL(c *gophercloud.ServiceClient, dsID string) string {
+	return c.ServiceURL("datastores", dsID)
+}
+
+func versionsURL(c *gophercloud.ServiceClient, dsID string) string {
+	return c.ServiceURL("datastores", dsID, "versions")
+}
+
+func versionURL(c *gophercloud.ServiceClient, dsID, versionID string) string {
+	return c.ServiceURL("datastores", dsID, "versions", versionID)
+}