GitHub - FreeLeh/GoFreeDB: GoFreeDB is a Golang library that provides common and simple database abstractions on top of Google Sheets. (original) (raw)
GoFreeDB
Ship Faster with Google Sheets as a Database!
GoFreeDB is a Golang library that provides common and simple database abstractions on top of Google Sheets.
Features
- Provide a straightforward key-value and row based database interfaces on top of Google Sheets.
- Serve your data without any server setup (by leveraging Google Sheets infrastructure).
- Support flexible enough query language to perform various data queries.
- Manually manipulate data via the familiar Google Sheets UI (no admin page required).
For more details, please read our analysison other alternatives and how it compares with
FreeDB.
Table of Contents
Protocols
Clients are strongly encouraged to read through the protocols document to see how things work under the hood and the limitations.
Getting Started
Installation
go get github.com/FreeLeh/GoFreeDB
Pre-requisites
- Obtain a Google OAuth2 or Service Account credentials.
- Prepare a Google Sheets spreadsheet where the data will be stored.
Row Store
Let's assume each row in the table is represented by the Person struct.
type Person struct {
Name string db:"name"
Age int db:"age"
}
Please read the struct field to column mapping section to understand the purpose of the db struct field tag.
import ( "github.com/FreeLeh/GoFreeDB" "github.com/FreeLeh/GoFreeDB/google/auth" )
// If using Google Service Account. auth, err := auth.NewServiceFromFile( "", freedb.FreeDBGoogleAuthScopes, auth.ServiceConfig{}, )
// If using Google OAuth2 Flow. auth, err := auth.NewOAuth2FromFile( "", "", freedb.FreeDBGoogleAuthScopes, auth.OAuth2Config{}, )
store := freedb.NewGoogleSheetRowStore( auth, "", "", freedb.GoogleSheetRowStoreConfig{Columns: []string{"name", "age"}}, ) defer store.Close(context.Background())
Querying Rows
// Output variable var output []Person
// Select all columns for all rows err := store. Select(&output). Exec(context.Background())
// Select a few columns for all rows (non-selected struct fields will have default value) err := store. Select(&output, "name"). Exec(context.Background())
// Select rows with conditions err := store. Select(&output). Where("name = ? OR age >= ?", "freedb", 10). Exec(context.Background())
// Select rows with sorting/order by ordering := []freedb.ColumnOrderBy{ {Column: "name", OrderBy: freedb.OrderByAsc}, {Column: "age", OrderBy: freedb.OrderByDesc}, } err := store. Select(&output). OrderBy(ordering). Exec(context.Background())
// Select rows with offset and limit err := store. Select(&output). Offset(10). Limit(20). Exec(context.Background())
Counting Rows
// Count all rows count, err := store. Count(). Exec(context.Background())
// Count rows with conditions count, err := store. Count(). Where("name = ? OR age >= ?", "freedb", 10). Exec(context.Background())
Inserting Rows
err := store.Insert( Person{Name: "no_pointer", Age: 10}, &Person{Name: "with_pointer", Age: 20}, ).Exec(context.Background())
Updating Rows
colToUpdate := make(map[string]interface{}) colToUpdate["name"] = "new_name" colToUpdate["age"] = 12
// Update all rows err := store. Update(colToUpdate). Exec(context.Background())
// Update rows with conditions err := store. Update(colToUpdate). Where("name = ? OR age >= ?", "freedb", 10). Exec(context.Background())
Deleting Rows
// Delete all rows err := store. Delete(). Exec(context.Background())
// Delete rows with conditions err := store. Delete(). Where("name = ? OR age >= ?", "freedb", 10). Exec(context.Background())
Struct Field to Column Mapping
The struct field tag db can be used for defining the mapping between the struct field and the column name. This works just like the json tag from encoding/json.
Without db tag, the library will use the field name directly (case-sensitive).
// This will map to the exact column name of "Name" and "Age". type NoTagPerson struct { Name string Age int }
// This will map to the exact column name of "name" and "age"
type WithTagPerson struct {
Name string db:"name"
Age int db:"age"
}
KV Store
Please use
KV Store V2as much as possible, especially if you are creating a new storage.
import ( "github.com/FreeLeh/GoFreeDB" "github.com/FreeLeh/GoFreeDB/google/auth" )
// If using Google Service Account. auth, err := auth.NewServiceFromFile( "", freedb.FreeDBGoogleAuthScopes, auth.ServiceConfig{}, )
// If using Google OAuth2 Flow. auth, err := auth.NewOAuth2FromFile( "", "", freedb.FreeDBGoogleAuthScopes, auth.OAuth2Config{}, )
kv := freedb.NewGoogleSheetKVStore( auth, "", "", freedb.GoogleSheetKVStoreConfig{Mode: freedb.KVSetModeAppendOnly}, ) defer kv.Close(context.Background())
Get Value
If the key is not found, freedb.ErrKeyNotFound will be returned.
value, err := kv.Get(context.Background(), "k1")
Set Key
err := kv.Set(context.Background(), "k1", []byte("some_value"))
Delete Key
err := kv.Delete(context.Background(), "k1")
Supported Modes
For more details on how the two modes are different, please read the protocol document.
There are 2 different modes supported:
- Default mode.
- Append only mode.
// Default mode kv := freedb.NewGoogleSheetKVStore( auth, "", "", freedb.GoogleSheetKVStoreConfig{Mode: freedb.KVModeDefault}, )
// Append only mode kv := freedb.NewGoogleSheetKVStore( auth, "", "", freedb.GoogleSheetKVStoreConfig{Mode: freedb.KVModeAppendOnly}, )
KV Store V2
The KV Store V2 is implemented internally using the row store.
The original
KV Storewas created using more complicated formulas, making it less maintainable. You can still use the originalKV Storeimplementation, but we strongly suggest using this newKV Store V2.
You cannot use an existing sheet based on KV Store with KV Store V2 as the sheet structure is different.
- If you want to convert an existing sheet, just add an
_ridcolumn and insert the first key-value row with1and increase it by 1 until the last row. - Remove the timestamp column as
KV Store V2does not depend on it anymore.
import ( "github.com/FreeLeh/GoFreeDB" "github.com/FreeLeh/GoFreeDB/google/auth" )
// If using Google Service Account. auth, err := auth.NewServiceFromFile( "", freedb.FreeDBGoogleAuthScopes, auth.ServiceConfig{}, )
// If using Google OAuth2 Flow. auth, err := auth.NewOAuth2FromFile( "", "", freedb.FreeDBGoogleAuthScopes, auth.OAuth2Config{}, )
kv := freedb.NewGoogleSheetKVStoreV2( auth, "", "", freedb.GoogleSheetKVStoreV2Config{Mode: freedb.KVSetModeAppendOnly}, ) defer kv.Close(context.Background())
Get Value V2
If the key is not found, freedb.ErrKeyNotFound will be returned.
value, err := kv.Get(context.Background(), "k1")
Set Key V2
err := kv.Set(context.Background(), "k1", []byte("some_value"))
Delete Key V2
err := kv.Delete(context.Background(), "k1")
Supported Modes V2
For more details on how the two modes are different, please read the protocol document.
There are 2 different modes supported:
- Default mode.
- Append only mode.
// Default mode kv := freedb.NewGoogleSheetKVStoreV2( auth, "", "", freedb.GoogleSheetKVStoreV2Config{Mode: freedb.KVModeDefault}, )
// Append only mode kv := freedb.NewGoogleSheetKVStoreV2( auth, "", "", freedb.GoogleSheetKVStoreV2Config{Mode: freedb.KVModeAppendOnly}, )
License
This project is MIT licensed.