Home »
Technical Overview | Use Cases | Command-Line Interface | Go bindings Tour | Path Syntax | FAQ
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 Go SDK Reference for more information on anything you see.
- Noms command-line tools
- Go v1.6+
- Ensure your $GOPATH is configured
Let's create a local database to play with:
> mkdir /tmp/noms-go-tour
> noms serve /tmp/noms-go-tour
Leave the server running, and in a separate terminal:
> 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:
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:
> 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 Spelling in Noms 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:
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:
> 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:
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:
> go run noms-tour.go
data type: List<struct {
given: String
male: Bool
}>
Now you can access the data via your program:
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:
> go run noms-tour.go
given: Rickon
You can see this data using the command-line too:
> 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.
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:
> 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:
> 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 variety of datatypes 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 samples. The hr sample is a more complete implementation of our example above and will help you to see further usage of the other datatypes.