forked from fenos/dqlx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
schema.go
224 lines (172 loc) · 5.23 KB
/
schema.go
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
package dqlx
import (
"bytes"
"context"
"fmt"
"strings"
"github.com/dgraph-io/dgo/v200"
)
// SchemaBuilder used to compose a Dgraph schema in a fluent manner
type SchemaBuilder struct {
Predicates []*DGraphPredicate
Types []*dGraphType
client *dgo.Dgraph
}
// NewSchema creates a new SchemaBuilder
func NewSchema() *SchemaBuilder {
return &SchemaBuilder{
Predicates: nil,
Types: nil,
}
}
// WithClient sets the dgraph client
func (schema *SchemaBuilder) WithClient(client *dgo.Dgraph) *SchemaBuilder {
schema.client = client
return schema
}
// ToDQL returns the schema in a DQL format
func (schema *SchemaBuilder) ToDQL() (string, error) {
writer := bytes.Buffer{}
predicates, err := schema.PredicatesToString()
if err != nil {
return "", err
}
types, err := schema.TypesToString()
if err != nil {
return "", err
}
writer.WriteString(predicates)
if types != "" {
writer.WriteString("\n\n")
writer.WriteString(types)
}
return writer.String(), nil
}
// PredicatesToString returns predicates to a DQL string
func (schema *SchemaBuilder) PredicatesToString() (string, error) {
writer := bytes.Buffer{}
registeredPredicates := map[string]*DGraphPredicate{}
var predicates []string
for _, predicate := range schema.Predicates {
if registeredPredicate, ok := registeredPredicates[predicate.Name]; ok {
if registeredPredicate.ScalarType != predicate.ScalarType {
return "", fmt.Errorf("Predicate '%s' already registered with a different scalar type '%s'", predicate.Name, registeredPredicate.ScalarType)
}
continue
}
predicates = append(predicates, predicate.ToString())
registeredPredicates[predicate.Name] = predicate
}
writer.WriteString(strings.Join(predicates, "\n"))
return writer.String(), nil
}
// TypesToString returns type definitions to a DQL string
func (schema *SchemaBuilder) TypesToString() (string, error) {
writer := bytes.Buffer{}
types := make([]string, len(schema.Types))
for index, dType := range schema.Types {
dqlExpression, err := dType.ToString()
if err != nil {
return "", err
}
types[index] = dqlExpression
}
writer.WriteString(strings.Join(types, "\n"))
return writer.String(), nil
}
// HasType determines if a type has been already registered
func (schema *SchemaBuilder) HasType(name string) bool {
for _, schemaType := range schema.Types {
if schemaType.name == name {
return true
}
}
return false
}
// HasPredicate determines if a predicate has been already registered
func (schema *SchemaBuilder) HasPredicate(name string) bool {
for _, predicate := range schema.Predicates {
if predicate.Name == name {
return true
}
}
return false
}
// TypeBuilderFn represents the closure function for the type builder
type TypeBuilderFn func(builder *TypeBuilder)
// Type registers a type definition to the schema
func (schema *SchemaBuilder) Type(name string, builderFn TypeBuilderFn, options ...TypeBuilderOptionModifier) *TypeBuilder {
if schema.HasType(name) {
panic(fmt.Errorf("type '%s' already registered", name))
}
builder := &TypeBuilder{
prefixFields: true,
dGraphType: &dGraphType{
name: name,
predicates: nil,
},
schema: schema,
}
for _, modifier := range options {
modifier(builder)
}
builderFn(builder)
schema.Types = append(schema.Types, builder.dGraphType)
return builder
}
// Predicate registers a predicate to the schema
func (schema *SchemaBuilder) Predicate(name string, scalar DGraphScalar) *PredicateBuilder {
builder := &PredicateBuilder{
predicate: &DGraphPredicate{
Name: name,
ScalarType: scalar,
},
}
schema.Predicates = append(schema.Predicates, builder.predicate)
return builder
}
// PredicateString registers a predicate string type
func (schema *SchemaBuilder) PredicateString(name string) *PredicateStringBuilder {
builder := &PredicateStringBuilder{
PredicateBuilder: &PredicateBuilder{
predicate: &DGraphPredicate{
Name: name,
ScalarType: ScalarString,
},
},
}
schema.Predicates = append(schema.Predicates, builder.predicate)
return builder
}
// PredicateDatetime registers a predicate datetime
func (schema *SchemaBuilder) PredicateDatetime(name string) *PredicateDateBuilder {
builder := &PredicateDateBuilder{
PredicateBuilder: &PredicateBuilder{
predicate: &DGraphPredicate{
Name: name,
ScalarType: ScalarDateTime,
},
},
}
schema.Predicates = append(schema.Predicates, builder.predicate)
return builder
}
// Alter alters the schema with the current state. No drop operation will happen
// if DropAll is not explicitly set
func (schema *SchemaBuilder) Alter(ctx context.Context, options ...SchemaExecutorOptionFn) error {
schemaExecutor := NewSchemaExecutor(schema.client)
for _, option := range options {
option(schemaExecutor)
}
return schemaExecutor.AlterSchema(ctx, schema)
}
// DropType drops a type
func (schema *SchemaBuilder) DropType(ctx context.Context, typeName string) error {
schemaExecutor := NewSchemaExecutor(schema.client)
return schemaExecutor.DropType(ctx, typeName)
}
// DropPredicate drops a predicate
func (schema *SchemaBuilder) DropPredicate(ctx context.Context, predicateName string) error {
schemaExecutor := NewSchemaExecutor(schema.client)
return schemaExecutor.DropPredicate(ctx, predicateName)
}