Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
ef0a863
Experimental RTDB code
hiranya911 Oct 21, 2017
becb82f
Added ref.Set()
hiranya911 Oct 22, 2017
2d4e342
Added Push(), Update(), Remove() and tests
hiranya911 Oct 22, 2017
6bf42cf
Adding Transaction() support
hiranya911 Oct 22, 2017
0a21f4e
Fixed Transaction() API
hiranya911 Oct 22, 2017
0fcbbce
Code cleanup
hiranya911 Oct 22, 2017
65870f7
Implemented Query() API
hiranya911 Oct 22, 2017
cad2bfe
Added GetIfChanged() and integration tests
hiranya911 Oct 23, 2017
40c0691
More integration tests
hiranya911 Oct 23, 2017
0e85fa2
Updated unit test
hiranya911 Oct 23, 2017
20fdbf3
More integration tests
hiranya911 Oct 23, 2017
ef547a6
Integration tests for queries
hiranya911 Oct 23, 2017
b4e127d
Auth override support and more tests
hiranya911 Oct 24, 2017
6af57b0
More test cases; AuthOverride support in App
hiranya911 Oct 25, 2017
da6fc75
Implemented AuthOverride support; Added tests
hiranya911 Oct 25, 2017
641dbaa
Implementing the new API
hiranya911 Oct 27, 2017
f82a3e0
More code cleanup
hiranya911 Oct 27, 2017
6ecb8de
Code clean up
hiranya911 Oct 27, 2017
deb4eac
Refactored the http client code
hiranya911 Oct 27, 2017
caeaafe
More tests
hiranya911 Oct 27, 2017
bf092a2
Boosted test coverage to 97%
hiranya911 Oct 27, 2017
8450363
Better error messages in tests; Added license headers
hiranya911 Oct 28, 2017
993f639
Added documentatioon and cleaned up tests
hiranya911 Oct 28, 2017
63a5ace
Fixing a build break
hiranya911 Oct 28, 2017
835adaa
Finishing up documentation
hiranya911 Oct 28, 2017
57263ad
More test cases
hiranya911 Oct 28, 2017
e557b9a
Implemented a reusable HTTP client API
hiranya911 Oct 30, 2017
2c30329
Merge branch 'hkj-http-client' into hkj-rtdb
hiranya911 Oct 30, 2017
f69b5ad
Added test cases
hiranya911 Oct 30, 2017
d5a5fae
Comment clean up
hiranya911 Oct 30, 2017
591e216
Merge branch 'hkj-http-client' into hkj-rtdb
hiranya911 Oct 30, 2017
73bfd8f
Using the shared http client API
hiranya911 Oct 30, 2017
11455d8
Simplified the usage by adding HTTPClient
hiranya911 Oct 31, 2017
31fe147
Merge branch 'hkj-http-client' into hkj-rtdb
hiranya911 Oct 31, 2017
d2f90f2
using the new client API
hiranya911 Oct 31, 2017
6c1d6ee
Using the old ctx import
hiranya911 Oct 31, 2017
6ddf0f6
Using the old context import
hiranya911 Oct 31, 2017
e6d8e9e
Merge branch 'hkj-http-client' into hkj-rtdb
hiranya911 Oct 31, 2017
6bcb489
Refactored db code
hiranya911 Oct 31, 2017
9c5dc02
More refactoring
hiranya911 Oct 31, 2017
98a2e3c
Support for arbitrary entity types in the request
hiranya911 Oct 31, 2017
9cc76cb
Renamed fields; Added documentation
hiranya911 Oct 31, 2017
f96fc12
Removing a redundant else case
hiranya911 Oct 31, 2017
24cdb6b
Merge branch 'hkj-http-client' into hkj-rtdb
hiranya911 Oct 31, 2017
be94fad
Code readability improvements
hiranya911 Oct 31, 2017
f08b191
Cleaned up the RTDB HTTP client code
hiranya911 Nov 1, 2017
d68a2e1
Merged with dev
hiranya911 Nov 1, 2017
e008fc1
Merged with dev
hiranya911 Feb 12, 2018
d0090e6
Merge branch 'dev' into hkj-rtdb
hiranya911 Feb 13, 2018
681a529
Added shallow reads support; Added the new txn API
hiranya911 Feb 13, 2018
0dac62f
Implementing GetOrdered() for queries
hiranya911 Feb 14, 2018
01ad198
Adding more sorting tests
hiranya911 Feb 14, 2018
3cd8ea5
Added Query ordering tests
hiranya911 Feb 14, 2018
b8b9a84
Fixing some lint errors and compilation errors
hiranya911 Feb 14, 2018
5fe7d33
Removing unused function
hiranya911 Feb 14, 2018
a65e3e4
Cleaned up unit tests for db
hiranya911 Feb 14, 2018
d734308
Updated query impl and tests
hiranya911 Feb 14, 2018
0007b6b
Added integration tests for ordered queries
hiranya911 Feb 15, 2018
f0f2063
Removed With*() from query functions
hiranya911 Feb 15, 2018
acf4fbd
Merge branch 'dev' into hkj-rtdb
hiranya911 Feb 15, 2018
0e095a0
Updated change log; Added more tests
hiranya911 Feb 15, 2018
0bbe372
Support for database url in auto init
hiranya911 Feb 15, 2018
f4cf85a
Support for loading auth overrides from env
hiranya911 Feb 15, 2018
14b3591
Removed db.AuthOverride type
hiranya911 Feb 15, 2018
c38f24e
Renamed ao to authOverride everywhere; Other code review nits
hiranya911 Feb 16, 2018
6365187
Merge branch 'dev' into hkj-rtdb
hiranya911 Feb 21, 2018
db9249e
Introducing the QueryNode interface to handle ordered query results (…
hiranya911 Feb 27, 2018
7bc0e2a
Merged with dev
hiranya911 Feb 27, 2018
bbcdae2
Database Sample Snippets (#102)
hiranya911 Feb 27, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Unreleased

-
- [added] Added the `db` package for interacting with the Firebase database.

# v2.5.0

Expand Down
2 changes: 1 addition & 1 deletion auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ type signer interface {
// NewClient creates a new instance of the Firebase Auth Client.
//
// This function can only be invoked from within the SDK. Client applications should access the
// the Auth service through firebase.App.
// Auth service through firebase.App.
func NewClient(ctx context.Context, c *internal.AuthConfig) (*Client, error) {
var (
err error
Expand Down
107 changes: 107 additions & 0 deletions db/auth_override_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package db

import (
"testing"

"golang.org/x/net/context"
)

func TestAuthOverrideGet(t *testing.T) {
mock := &mockServer{Resp: "data"}
srv := mock.Start(aoClient)
defer srv.Close()

ref := aoClient.NewRef("peter")
var got string
if err := ref.Get(context.Background(), &got); err != nil {
t.Fatal(err)
}
if got != "data" {
t.Errorf("Ref(AuthOverride).Get() = %q; want = %q", got, "data")
}
checkOnlyRequest(t, mock.Reqs, &testReq{
Method: "GET",
Path: "/peter.json",
Query: map[string]string{"auth_variable_override": testAuthOverrides},
})
}

func TestAuthOverrideSet(t *testing.T) {
mock := &mockServer{}
srv := mock.Start(aoClient)
defer srv.Close()

ref := aoClient.NewRef("peter")
want := map[string]interface{}{"name": "Peter Parker", "age": float64(17)}
if err := ref.Set(context.Background(), want); err != nil {
t.Fatal(err)
}
checkOnlyRequest(t, mock.Reqs, &testReq{
Method: "PUT",
Body: serialize(want),
Path: "/peter.json",
Query: map[string]string{"auth_variable_override": testAuthOverrides, "print": "silent"},
})
}

func TestAuthOverrideQuery(t *testing.T) {
mock := &mockServer{Resp: "data"}
srv := mock.Start(aoClient)
defer srv.Close()

ref := aoClient.NewRef("peter")
var got string
if err := ref.OrderByChild("foo").Get(context.Background(), &got); err != nil {
t.Fatal(err)
}
if got != "data" {
t.Errorf("Ref(AuthOverride).OrderByChild() = %q; want = %q", got, "data")
}
checkOnlyRequest(t, mock.Reqs, &testReq{
Method: "GET",
Path: "/peter.json",
Query: map[string]string{
"auth_variable_override": testAuthOverrides,
"orderBy": "\"foo\"",
},
})
}

func TestAuthOverrideRangeQuery(t *testing.T) {
mock := &mockServer{Resp: "data"}
srv := mock.Start(aoClient)
defer srv.Close()

ref := aoClient.NewRef("peter")
var got string
if err := ref.OrderByChild("foo").StartAt(1).EndAt(10).Get(context.Background(), &got); err != nil {
t.Fatal(err)
}
if got != "data" {
t.Errorf("Ref(AuthOverride).OrderByChild() = %q; want = %q", got, "data")
}
checkOnlyRequest(t, mock.Reqs, &testReq{
Method: "GET",
Path: "/peter.json",
Query: map[string]string{
"auth_variable_override": testAuthOverrides,
"orderBy": "\"foo\"",
"startAt": "1",
"endAt": "10",
},
})
}
134 changes: 134 additions & 0 deletions db/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package db contains functions for accessing the Firebase Realtime Database.
package db

import (
"encoding/json"
"fmt"
"runtime"
"strings"

"firebase.google.com/go/internal"

"net/url"

"golang.org/x/net/context"
"google.golang.org/api/option"
"google.golang.org/api/transport"
)

const userAgentFormat = "Firebase/HTTP/%s/%s/AdminGo"
const invalidChars = "[].#$"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For such a small set, this is the right way to do this. But I want to bring unicode.RangeTable to your attention, as it would be the right way to do this if the set were much more complicated.

https://golang.org/pkg/unicode/#Is

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

const authVarOverride = "auth_variable_override"

// Client is the interface for the Firebase Realtime Database service.
type Client struct {
hc *internal.HTTPClient
url string
authOverride string
}

// NewClient creates a new instance of the Firebase Database Client.
//
// This function can only be invoked from within the SDK. Client applications should access the
// Database service through firebase.App.
func NewClient(ctx context.Context, c *internal.DatabaseConfig) (*Client, error) {
opts := append([]option.ClientOption{}, c.Opts...)
ua := fmt.Sprintf(userAgentFormat, c.Version, runtime.Version())
opts = append(opts, option.WithUserAgent(ua))
hc, _, err := transport.NewHTTPClient(ctx, opts...)
if err != nil {
return nil, err
}

p, err := url.ParseRequestURI(c.URL)
if err != nil {
return nil, err
} else if p.Scheme != "https" {
return nil, fmt.Errorf("invalid database URL: %q; want scheme: %q", c.URL, "https")
} else if !strings.HasSuffix(p.Host, ".firebaseio.com") {
return nil, fmt.Errorf("invalid database URL: %q; want host: %q", c.URL, "firebaseio.com")
}

var ao []byte
if c.AuthOverride == nil || len(c.AuthOverride) > 0 {
ao, err = json.Marshal(c.AuthOverride)
if err != nil {
return nil, err
}
}

ep := func(b []byte) string {
var p struct {
Error string `json:"error"`
}
if err := json.Unmarshal(b, &p); err != nil {
return ""
}
return p.Error
}
return &Client{
hc: &internal.HTTPClient{Client: hc, ErrParser: ep},
url: fmt.Sprintf("https://%s", p.Host),
authOverride: string(ao),
}, nil
}

// NewRef returns a new database reference representing the node at the specified path.
func (c *Client) NewRef(path string) *Ref {
segs := parsePath(path)
key := ""
if len(segs) > 0 {
key = segs[len(segs)-1]
}

return &Ref{
Key: key,
Path: "/" + strings.Join(segs, "/"),
client: c,
segs: segs,
}
}

func (c *Client) send(
ctx context.Context,
method, path string,
body internal.HTTPEntity,
opts ...internal.HTTPOption) (*internal.Response, error) {

if strings.ContainsAny(path, invalidChars) {
return nil, fmt.Errorf("invalid path with illegal characters: %q", path)
}
if c.authOverride != "" {
opts = append(opts, internal.WithQueryParam(authVarOverride, c.authOverride))
}
return c.hc.Do(ctx, &internal.Request{
Method: method,
URL: fmt.Sprintf("%s%s.json", c.url, path),
Body: body,
Opts: opts,
})
}

func parsePath(path string) []string {
var segs []string
for _, s := range strings.Split(path, "/") {
if s != "" {
segs = append(segs, s)
}
}
return segs
}
Loading