File: ddl.md

package info (click to toggle)
golang-ariga-atlas 0.7.2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 5,676 kB
  • sloc: javascript: 592; sql: 404; makefile: 10
file content (270 lines) | stat: -rw-r--r-- 6,333 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
---
id: ddl
slug: /guides/ddl
title: Data Definition Language
---

## Introduction

In the core of the Atlas project resides the Atlas Data Definition Language (DDL). The DDL is designed to capture an
organization's data topologies and other aspects of its data infrastructure.

In the design of the DDL, we put an emphasis on extensibility: As data topologies can contain a set of diverse
data technologies, the language is designed to be modular with different extensions extending the types of
resources and relationships that can be described using it.

## HCL

The Atlas DDL currently supports an HCL syntax we call Atlas HCL. It is similar to other HCL based languages such as
Terraform.

### Resources

Documents written in the Atlas DDL usually describe _resources_. Resources are described as HCL blocks and have a type,
and optionally a name. Consider this block:

```hcl
user "rotemtam" {
   // ...
}
```

This block describes a resource of type `user` with a name of `rotemtam`.

### Qualifiers

In some cases, a document may contain multiple resources with the same name. To differentiate between
the different resources, the Atlas DDL supports _qualifiers_, an additional label preceding the resource
name:

```hcl
person "dr" "jekyll" {

}
```

This block describes a resource of type `person`, with a name of "jekyll" which is qualified by
"dr".

### Attributes

Resources can have named attributes with primitive types (string, boolean, integer or float)
or lists of primitive values.

For example:

```hcl
user "rotemtam" {
  email = "rotem@atlasgo.io"
  active = true
  credits = 42
  tags = [
    "data",
    "infrastructure",
    "hcl"
  ]
}
```

### Children

Resources can have child resources. For example:

```hcl
user "rotemtam" {
   ..
  project "atlas" {
    started = 2021
    metadata {
      category = "data"
    }
  }
}
```

### References

Attributes can hold references to other resources. The address of any resource is
`<type>.<name>`, recursively. Suppose we have this block describing some HTTP service:

```hcl
service "todolist" {
  port "http" {
    number = 8080
  }
}
```

If we want to reference the child "port" resource of the service we can use
`service.todolist.port.http`:

```hcl
server "production" {
  endpoint "todo" {
    path = "/todo"
    service_port = service.todolist.port.http
  }
}
```

Attributes can hold references to other attributes. When a document is parsed the reference is replaced with the
referenced value. The address of any attribute is `<type>.<name>.<attr name>`.

```hcl
group "seinfeld" {
  id = 1
}
show "friends" {
  id = 2
}
playlist "comedy" {
  show_ids = [
    show.seinfeld.id
    // will equal 1
    show.friends.id,
    // will equal 2
  ]
}
```

### Reading with Go

To read an Atlas HCL document with Go use the `EvalBytes` ([doc](https://pkg.go.dev/ariga.io/atlas/schemahcl#EvalBytes)) function
from the `schemahcl` package:

```go
func ExampleUnmarshal() {
    f := `
show "seinfeld" {
	writer "jerry" {
		full_name = "Jerry Seinfeld"
	}
	writer "larry" {
		full_name = "Larry David"
	}
}`

  type (
      Writer struct {
        ID       string `spec:",name"`
        FullName string `spec:"full_name"`
      }
      Show struct {
        Name    string    `spec:",name"`
        Writers []*Writer `spec:"writer"`
      }
    )
  var test struct {
    Shows []*Show `spec:"show"`
  }
  err := EvalBytes([]byte(f), &test, nil)
  if err != nil {
    panic(err)
  }
  seinfeld := test.Shows[0]
  fmt.Printf("the show %q has %d writers.", seinfeld.Name, len(seinfeld.Writers))
  // Output: the show "seinfeld" has 2 writers.
}
```

This function takes a byte-slice, an empty interface as arguments and a map of strings as input.
The empty interface should be a  pointer to a struct into which the `EvalBytes` function will
read the values. The struct fields must be annotated with `spec` tags that define the mapping from HCL to the Go type.
This mapping is discussed in the section about [Extensions](#extensions). The final map argument may contain
[Input Values](/atlas-schema/input.md) to be passed as parameters of the evaluation.

### Writing with Go

To encode a Go struct back into HCL, use the `schemahcl.Marshal`
([doc](https://pkg.go.dev/ariga.io/atlas/schemahcl#Marshal)) function:

```go
func ExampleMarshal() {
  type (
    Point struct {
      ID string `spec:",name"`
      X  int    `spec:"x"`
      Y  int    `spec:"y"`
    }
  )
  var test = struct {
    Points []*Point `spec:"point"`
  }{
    Points: []*Point{
      {ID: "start", X: 0, Y: 0},
      {ID: "end", X: 1, Y: 1},
    },
  }
  b, err := Marshal(&test)
  if err != nil {
    panic(err)
  }
  fmt.Println(string(b))
  // Output: point "start" {
  //   x = 0
  //   y = 0
  // }
  // point "end" {
  //   x = 1
  //   y = 1
  // }
}
```

## Extensions

Applications working with the Atlas DDL are expected to extend the Atlas language by
defining their own type structs that objects can be handled in a type-safe way.

The mapping between the extension struct fields and the configuration syntax is done by placing tags on the
extension struct field using the `spec` key in the tag. To specify that a field should be mapped to
the corresponding resource's name specify ",name" to the tag value. For example,

```go
type Point struct {
    ID string `spec:",name"`
    X  int    `spec:"x"`
    Y  int    `spec:"y"`
}
```

Would be able to capture a Resource defined in Atlas HCL as:

```hcl
point "origin" {
  x = 100
  y = 200
}
```

To operate correctly, struct extensions should be registered using the `schemahcl.Register`
function:

```go
schemahcl.Register("point", &Point{})
```

Extension structs may implement the [Remainer](https://pkg.go.dev/ariga.io/atlas/schemahcl#Remainer)
interface if they wish to store any attributes and children that are not matched by their
tagged fields. As a convenience the `schemahcl` package exports a `DefaultExtension` type that
can be embedded to support this behavior.

### Qualifiers

In cases where resources may need to be qualified, a field of the target struct can be annotated
with the `,qualifier` tag. For instance this struct:

```go
type Person struct {
  Name  string `spec:",name"`
  Title string `spec:",qualifier"`
}
```

Can capture a qualified HCL resource such as:

```hcl
person "dr" "jekyll" {

}
```