github.com/attic-labs/noms@v0.0.0-20210827224422-e5fa29d95e8b/doc/go-tour.md (about)

     1  [Home](../README.md) ยป
     2  
     3  [Technical Overview](intro.md)  |  [Use Cases](../README.md#use-cases)  |  [Command-Line Interface](cli-tour.md)  |  **Go bindings Tour** |  [Path Syntax](spelling.md)  |  [FAQ](faq.md) 
     4  <br><br>
     5  # A Short Tour of Noms for Go
     6  
     7  This is a short introduction to using Noms from Go. It should only take a few minutes if you have some familiarity with Go.
     8  
     9  During the tour, you can refer to the complete [Go SDK Reference](https://godoc.org/github.com/attic-labs/noms) for more information on anything you see.
    10  
    11  
    12  
    13  ## Requirements
    14  
    15  * [Noms command-line tools](https://github.com/attic-labs/noms#setup)
    16  * [Go v1.6+](https://golang.org/dl/)
    17  * Ensure your [$GOPATH](https://github.com/golang/go/wiki/GOPATH) is configured
    18  
    19  ## Start a Local Database
    20  
    21  Let's create a local database to play with:
    22  
    23  ```sh
    24  > mkdir /tmp/noms-go-tour
    25  > noms serve /tmp/noms-go-tour
    26  ```
    27  
    28  ## [Database](https://github.com/attic-labs/noms/blob/master/go/datas/database.go)
    29  Leave the server running, and in a separate terminal:
    30  
    31  ```sh
    32  > mkdir noms-tour
    33  > cd noms-tour
    34  ```
    35  
    36  Then use your favorite editor so that we can start to play with code. To get started with Noms, first create a Database:
    37  
    38  ```go
    39  package main
    40  
    41  import (
    42    "fmt"
    43    "os"
    44  
    45    "github.com/attic-labs/noms/go/spec"
    46  )
    47  
    48  func main() {
    49    sp, err := spec.ForDatabase("http://localhost:8000")
    50    if err != nil {
    51      fmt.Fprintf(os.Stderr, "Could not access database: %s\n", err)
    52      return
    53    }
    54    defer sp.Close()
    55  }
    56  ```
    57  
    58  Now let's run it:
    59  
    60  ```sh
    61  > go run noms-tour.go
    62  ```
    63  
    64  If you did not leave the server running you would see output of ```Could not access database``` here, otherwise your program should exit cleanly.
    65  
    66  See [Spelling in Noms](https://github.com/attic-labs/noms/blob/master/doc/spelling.md) for more information on database spec strings.
    67  
    68  
    69  ## [Dataset](https://github.com/attic-labs/noms/blob/master/go/dataset/dataset.go)
    70  
    71  Datasets are the main interface you'll use to work with Noms. Let's update our example to use a Dataset spec string:
    72  
    73  ```go
    74  package main
    75  
    76  import (
    77    "fmt"
    78    "os"
    79  
    80    "github.com/attic-labs/noms/go/spec"
    81  )
    82  
    83  func main() {
    84    sp, err := spec.ForDataset("http://localhost:8000::people")
    85    if err != nil {
    86      fmt.Fprintf(os.Stderr, "Could not create dataset: %s\n", err)
    87      return
    88    }
    89    defer sp.Close()
    90  
    91    if _, ok := sp.GetDataset().MaybeHeadValue(); !ok {
    92      fmt.Fprintf(os.Stdout, "head is empty\n")
    93    }
    94  }
    95  ```
    96  
    97  Now let's run it:
    98  
    99  ```sh
   100  > go run noms-tour.go
   101  head is empty
   102  ```
   103  
   104  Since the dataset does not yet have any values you see ```head is empty```. Let's add some data to make it more interesting:
   105  
   106  ```go
   107  package main
   108  
   109  import (
   110    "fmt"
   111    "os"
   112  
   113    "github.com/attic-labs/noms/go/spec"
   114    "github.com/attic-labs/noms/go/types"
   115  )
   116  
   117  func newPerson(givenName string, male bool) types.Struct {
   118    return types.NewStruct("Person", types.StructData{
   119      "given": types.String(givenName),
   120      "male":  types.Bool(male),
   121    })
   122  }
   123  
   124  func main() {
   125    sp, err := spec.ForDataset("http://localhost:8000::people")
   126    if err != nil {
   127      fmt.Fprintf(os.Stderr, "Could not create dataset: %s\n", err)
   128      return
   129    }
   130    defer sp.Close()
   131  
   132    db := sp.GetDatabase()
   133  
   134    data := types.NewList(db,
   135      newPerson("Rickon", true),
   136      newPerson("Bran", true),
   137      newPerson("Arya", false),
   138      newPerson("Sansa", false),
   139    )
   140  
   141    fmt.Fprintf(os.Stdout, "data type: %v\n", types.TypeOf(data).Describe())
   142  
   143    _, err = db.CommitValue(sp.GetDataset(), data)
   144    if err != nil {
   145      fmt.Fprint(os.Stderr, "Error commiting: %s\n", err)
   146    }
   147  }
   148  ```
   149  
   150  Now you will get output of the data type of our Dataset value:
   151  
   152  ```shell
   153  > go run noms-tour.go
   154  data type: List<struct  {
   155    given: String
   156    male: Bool
   157  }>
   158  ```
   159  
   160  Now you can access the data via your program:
   161  
   162  ```go
   163  package main
   164  
   165  import (
   166    "fmt"
   167    "os"
   168  
   169    "github.com/attic-labs/noms/go/spec"
   170    "github.com/attic-labs/noms/go/types"
   171  )
   172  
   173  func main() {
   174    sp, err := spec.ForDataset("http://localhost:8000::people")
   175    if err != nil {
   176      fmt.Fprintf(os.Stderr, "Could not create dataset: %s\n", err)
   177      return
   178    }
   179    defer sp.Close()
   180  
   181    if headValue, ok := sp.GetDataset().MaybeHeadValue(); !ok {
   182      fmt.Fprintf(os.Stdout, "head is empty\n")
   183    } else {
   184      // type assertion to convert Head to List
   185      personList := headValue.(types.List)
   186      // type assertion to convert List Value to Struct
   187      personStruct := personList.Get(0).(types.Struct)
   188      // prints: Rickon
   189      fmt.Fprintf(os.Stdout, "given: %v\n", personStruct.Get("given"))
   190    }
   191  }
   192  ```
   193  
   194  Running it now:
   195  
   196  ```sh
   197  > go run noms-tour.go
   198  given: Rickon
   199  ```
   200  
   201  You can see this data using the command-line too:
   202  
   203  ```sh
   204  > noms ds http://localhost:8000
   205  people
   206  
   207  > noms show http://localhost:8000::people
   208  struct Commit {
   209    meta: struct {},
   210    parents: set {},
   211    value: [  // 4 items
   212      struct Person {
   213        given: "Rickon",
   214        male: true,
   215      },
   216      struct Person {
   217        given: "Bran",
   218        male: true,
   219      },
   220      struct Person {
   221        given: "Arya",
   222        male: false,
   223      },
   224      struct Person {
   225        given: "Sansa",
   226        male: false,
   227      },
   228    ],
   229  }
   230  ```
   231  
   232  Let's add some more data.
   233  
   234  ```go
   235  package main
   236  
   237  import (
   238    "fmt"
   239    "os"
   240  
   241    "github.com/attic-labs/noms/go/spec"
   242    "github.com/attic-labs/noms/go/types"
   243  )
   244  
   245  func main() {
   246    sp, err := spec.ForDataset("http://localhost:8000::people")
   247    if err != nil {
   248      fmt.Fprintf(os.Stderr, "Could not create dataset: %s\n", err)
   249      return
   250    }
   251    defer sp.Close()
   252  
   253    if headValue, ok := sp.GetDataset().MaybeHeadValue(); !ok {
   254      fmt.Fprintf(os.Stdout, "head is empty\n")
   255    } else {
   256      // type assertion to convert Head to List
   257      personList := headValue.(types.List)
   258      personEditor := personList.Edit()
   259      data := personEditor.Append(
   260        types.NewStruct("Person", types.StructData{
   261          "given":  types.String("Jon"),
   262          "family": types.String("Snow"),
   263          "male":   types.Bool(true),
   264        }),
   265      ).List()
   266  
   267      fmt.Fprintf(os.Stdout, "data type: %v\n", types.TypeOf(data).Describe())
   268  
   269      _, err = sp.GetDatabase().CommitValue(sp.GetDataset(), data)
   270      if err != nil {
   271        fmt.Fprint(os.Stderr, "Error commiting: %s\n", err)
   272      }
   273    }
   274  }
   275  ```
   276  
   277  Running this:
   278  
   279  ```sh
   280  > go run noms-tour.go
   281  data type: List<Struct Person {
   282    family?: String,
   283    given: String,
   284    male: Bool,
   285  }>
   286  ```
   287  
   288  Datasets are versioned. When you *commit* a new value, you aren't overwriting the old value, but adding to a historical log of values:
   289  
   290  ```sh
   291  > noms log http://localhost:8000::people
   292  commit ba3lvopbgcqqnofm3qk7sk4j2doroj1l
   293  Parent: f0b1befu9jp82r1vcd4gmuhdno27uobi
   294  (root) {
   295  +   struct Person {
   296  +     family: "Snow",
   297  +     given: "Jon",
   298  +     male: true,
   299  +   }
   300    }
   301  
   302  commit f0b1befu9jp82r1vcd4gmuhdno27uobi
   303  Parent: hshltip9kss28uu910qadq04mhk9kuko
   304  
   305  commit hshltip9kss28uu910qadq04mhk9kuko
   306  Parent: None
   307  ```
   308  
   309  ## Values
   310  
   311  Noms supports a [variety of datatypes](https://github.com/attic-labs/noms/blob/master/doc/intro.md#types) beyond List, Struct, String, and Bool we used above.
   312  
   313  ## Samples
   314  
   315  You can continue learning more about the Noms Go SDK by looking at the documentation and by reviewing the [samples](https://github.com/attic-labs/noms/blob/master/samples/go). The [hr sample](https://github.com/attic-labs/noms/blob/master/samples/go/hr) is a more complete implementation of our example above and will help you to see further usage of the other datatypes.