Skip to content

Instantly share code, notes, and snippets.

@ronoaldo
Created April 17, 2024 13:32
Show Gist options
  • Save ronoaldo/b565bdcb8521c5c1e1fc67430c8f9ab9 to your computer and use it in GitHub Desktop.
Save ronoaldo/b565bdcb8521c5c1e1fc67430c8f9ab9 to your computer and use it in GitHub Desktop.
Demo - Cloud Bigtable from Go - Basic CRUD/Filter operations!
package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"strings"
"cloud.google.com/go/bigtable"
)
var (
operation string
allVersions bool
customerName string
customerEmail string
customerDomain string
ProjectID = ""
Instance = "bt-instance-us"
)
const (
Table = "Customer"
CustomerColumnFamily = "personalData"
)
func init() {
flag.StringVar(&ProjectID, "project", os.Getenv("GOOGLE_CLOUD_PROJECT"), "The Google Cloud Project ID where the instance is located.")
flag.StringVar(&Instance, "instance", "bt-instance-us", "The Bigtable instance id.")
flag.StringVar(&operation, "operation", "list", "The opration to be executed: list, insert, delete")
flag.BoolVar(&allVersions, "all-versions", false, "If the List operation shows all versions")
flag.StringVar(&customerEmail, "email", "", "The email address of the customer")
flag.StringVar(&customerDomain, "domain", "", "The domain of the customer")
flag.StringVar(&customerName, "name", "", "The name of the customer")
}
func main() {
flag.Parse()
app := Connect()
fmt.Println("Successfully created a connection to a Cloud Bigtable instance")
switch operation {
case "list":
app.ListCustomers(customerDomain)
case "insert":
if customerEmail == "" {
log.Println("Setting up sample customers")
checkError(app.InsertCustomer("Ronoaldo Pereira", "ronoaldo@ronoaldo.com"))
checkError(app.InsertCustomer("Albert Eistain", "albert@gmail.com"))
checkError(app.InsertCustomer("Isaac Newton", "newton@yahoo.com"))
checkError(app.InsertCustomer("Marie Curie", "marie@mariecurie.com"))
checkError(app.InsertCustomer("Nelson Mandela", "nelson.mandela@google.com"))
return
}
checkError(app.InsertCustomer(customerName, customerEmail))
case "delete":
if customerEmail == "all" {
app.RemoveAll()
return
}
checkError(app.RemoveCustomer(customerEmail))
}
}
type App struct {
ctx context.Context
bigtable *bigtable.Client
}
func Connect() *App {
ctx := context.Background()
bt, err := bigtable.NewClient(ctx, ProjectID, Instance)
if err != nil {
panic(fmt.Errorf("bigtable.NewAdminClient: %v", err))
}
return &App{
ctx: ctx,
bigtable: bt,
}
}
func NewCustomerKey(email string) string {
if strings.Count(email, "@") != 1 {
panic(fmt.Errorf("invalid email: %s", email))
}
parts := strings.Split(email, "@")
_, domain := parts[0], parts[1]
switch domain {
case "gmail.com", "yahoo.com", "outlook.com":
domain = "public"
}
return fmt.Sprintf("customer#%s#%s", domain, email)
}
// InsertCustomer adds a new customer to the database
func (app *App) InsertCustomer(name string, email string) error {
tbl := app.bigtable.Open(Table)
timestamp := bigtable.Now()
mut := bigtable.NewMutation()
mut.Set(CustomerColumnFamily, "name", timestamp, []byte(name))
mut.Set(CustomerColumnFamily, "email", timestamp, []byte(email))
rowKey := NewCustomerKey(email)
log.Printf("Writing row: %s\n", rowKey)
if err := tbl.Apply(app.ctx, rowKey, mut); err != nil {
log.Printf("Apply: %v", err)
return err
}
log.Printf("Successfully wrote row: %s\n", rowKey)
return nil
}
func (app *App) RemoveCustomer(email string) error {
tbl := app.bigtable.Open(Table)
rowKey := NewCustomerKey(email)
mut := bigtable.NewMutation()
mut.DeleteRow()
if err := tbl.Apply(app.ctx, rowKey, mut); err != nil {
log.Printf("DeleteRow: %v", err)
return err
}
log.Printf("Successfully deleted row: %s\n", rowKey)
return nil
}
func (app *App) RemoveAll() {
keys := app.CustomerKeys()
muts := []*bigtable.Mutation{}
tbl := app.bigtable.Open(Table)
for i := 0; i < len(keys); i++ {
mut := bigtable.NewMutation()
mut.DeleteRow()
muts = append(muts, mut)
}
if _, err := tbl.ApplyBulk(app.ctx, keys, muts); err != nil {
log.Printf("ApplyBulk: %v", err)
}
log.Printf("Successfully deleted all rows\n")
}
func (app *App) ListCustomers(domain string) {
count := 0
tbl := app.bigtable.Open(Table)
var filters []bigtable.ReadOption
if !allVersions {
filters = append(filters, bigtable.RowFilter(bigtable.LatestNFilter(1)))
}
prefix := bigtable.PrefixRange(fmt.Sprintf("customer#%s", domain))
callback := func(row bigtable.Row) bool {
count++
return printRow(row)
}
err := tbl.ReadRows(app.ctx, prefix, callback, filters...)
if err != nil {
log.Fatalf("tbl.ReadRows: %v", err)
}
fmt.Printf("Found %d customers\n", count)
}
func (app *App) CustomerKeys() (keys []string) {
tbl := app.bigtable.Open(Table)
tbl.ReadRows(app.ctx, bigtable.PrefixRange("customer#"), func(row bigtable.Row) bool {
keys = append(keys, row.Key())
return true
}, bigtable.RowFilter(bigtable.StripValueFilter()))
return keys
}
func printRow(row bigtable.Row) bool {
fmt.Printf("%s:\n", row.Key())
for _, cols := range row {
for _, col := range cols {
fmt.Printf(" %s=%s@%v\n", col.Column, string(col.Value), col.Timestamp.Time())
}
}
return true
}
func checkError(err error) {
if err != nil {
panic(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment