Project: NomsDB (App Definition and Development / Database)
File: go-tour.md

&nbsp; | &nbsp;&nbsp; | &nbsp;&nbsp; | &nbsp;Go bindings Tour | &nbsp;&nbsp; | &nbsp;&nbsp; <br><br> This is a short introduction to using Noms from Go. It should only take a few minutes if you have some familiarity with Go. During the tour, you can refer to the complete for more information on anything you see. Ensure your is configured Let's create a local database to play with: ```sh mkdir /tmp/noms-go-tour noms serve /tmp/noms-go-tour ``` Leave the server running, and in a separate terminal: ```sh mkdir noms-tour cd noms-tour ``` Then use your favorite editor so that we can start to play with code. To get started with Noms, first create a Database: ```go package main import ( "fmt" "os" "github.com/attic-labs/noms/go/spec" ) func main() { sp, err := spec.ForDatabase("http://localhost:8000") if err != nil { fmt.Fprintf(os.Stderr, "Could not access database: %s\n", err) return } defer sp.Close() } ``` Now let's run it: ```sh go run noms-tour.go ``` If you did not leave the server running you would see output of ```Could not access database``` here, otherwise your program should exit cleanly. See for more information on database spec strings. Datasets are the main interface you'll use to work with Noms. Let's update our example to use a Dataset spec string: ```go package main import ( "fmt" "os" "github.com/attic-labs/noms/go/spec" ) func main() { sp, err := spec.ForDataset("http://localhost:8000::people") if err != nil { fmt.Fprintf(os.Stderr, "Could not create dataset: %s\n", err) return } defer sp.Close() if _, ok := sp.GetDataset().MaybeHeadValue(); !ok { fmt.Fprintf(os.Stdout, "head is empty\n") } } ``` Now let's run it: ```sh go run noms-tour.go head is empty ``` Since the dataset does not yet have any values you see ```head is empty```. Let's add some data to make it more interesting: ```go package main import ( "fmt" "os" "github.com/attic-labs/noms/go/spec" "github.com/attic-labs/noms/go/types" ) func newPerson(givenName string, male bool) types.Struct { return types.NewStruct("Person", types.StructData{ "given": types.String(givenName), "male": types.Bool(male), }) } func main() { sp, err := spec.ForDataset("http://localhost:8000::people") if err != nil { fmt.Fprintf(os.Stderr, "Could not create dataset: %s\n", err) return } defer sp.Close() db := sp.GetDatabase() data := types.NewList(db, newPerson("Rickon", true), newPerson("Bran", true), newPerson("Arya", false), newPerson("Sansa", false), ) fmt.Fprintf(os.Stdout, "data type: %v\n", types.TypeOf(data).Describe()) _, err = db.CommitValue(sp.GetDataset(), data) if err != nil { fmt.Fprint(os.Stderr, "Error commiting: %s\n", err) } } ``` Now you will get output of the data type of our Dataset value: ```shell go run

data type: List<struct { given: String male: Bool }> ``` Now you can access the data via your program: ```go package main import ( "fmt" "os" "github.com/attic-labs/noms/go/spec" "github.com/attic-labs/noms/go/types" ) func main() { sp, err := spec.ForDataset("http://localhost:8000::people") if err != nil { fmt.Fprintf(os.Stderr, "Could not create dataset: %s\n", err) return } defer sp.Close() if headValue, ok := sp.GetDataset().MaybeHeadValue(); !ok { fmt.Fprintf(os.Stdout, "head is empty\n") } else { // type assertion to convert Head to List personList := headValue.(types.List) // type assertion to convert List Value to Struct personStruct := personList.Get(0).(types.Struct) // prints: Rickon fmt.Fprintf(os.Stdout, "given: %v\n", personStruct.Get("given")) } } ``` Running it now: ```sh go run noms-tour.go given: Rickon ``` You can see this data using the command-line too: ```sh noms ds http://localhost:8000 people noms show http://localhost:8000::people struct Commit { meta: struct {}, parents: set {}, value: [ // 4 items struct Person { given: "Rickon", male: true, }, struct Person { given: "Bran", male: true, }, struct Person { given: "Arya", male: false, }, struct Person { given: "Sansa", male: false, }, ], } ``` Let's add some more data. ```go package main import ( "fmt" "os" "github.com/attic-labs/noms/go/spec" "github.com/attic-labs/noms/go/types" ) func main() { sp, err := spec.ForDataset("http://localhost:8000::people") if err != nil { fmt.Fprintf(os.Stderr, "Could not create dataset: %s\n", err) return } defer sp.Close() if headValue, ok := sp.GetDataset().MaybeHeadValue(); !ok { fmt.Fprintf(os.Stdout, "head is empty\n") } else { // type assertion to convert Head to List personList := headValue.(types.List) personEditor := personList.Edit() data := personEditor.Append( types.NewStruct("Person", types.StructData{ "given": types.String("Jon"), "family": types.String("Snow"), "male": types.Bool(true), }), ).List() fmt.Fprintf(os.Stdout, "data type: %v\n", types.TypeOf(data).Describe()) _, err = sp.GetDatabase().CommitValue(sp.GetDataset(), data) if err != nil { fmt.Fprint(os.Stderr, "Error commiting: %s\n", err) } } } ``` Running this: ```sh go run noms-tour.go data type: List<Struct Person { family?: String, given: String, male: Bool, }> ``` Datasets are versioned. When you commit a new value, you aren't overwriting the old value, but adding to a historical log of values: ```sh noms log http://localhost:8000::people commit ba3lvopbgcqqnofm3qk7sk4j2doroj1l Parent: f0b1befu9jp82r1vcd4gmuhdno27uobi (root) { struct Person { family: "Snow", given: "Jon", male: true, } } commit f0b1befu9jp82r1vcd4gmuhdno27uobi Parent: hshltip9kss28uu910qadq04mhk9kuko commit hshltip9kss28uu910qadq04mhk9kuko Parent: None ``` Noms supports a beyond List, Struct, String, and Bool we used above. You can continue learning more about the Noms Go SDK by looking at the documentation and by reviewing the . The is a more complete implementation of our example above and will help you to see further usage of the other datatypes.