Skip to content

Commit 45e1b69

Browse files
Merge pull request #11 from dipdup-io/hasura-relations
Hasura: add relationships
2 parents 4a3edbf + 9da33c9 commit 45e1b69

File tree

2 files changed

+127
-4
lines changed

2 files changed

+127
-4
lines changed

hasura/hasura.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,80 @@ func generateOne(hasura config.Hasura, schema string, model interface{}) (table,
199199

200200
t.HasuraSchema.SelectPermissions = append(t.HasuraSchema.SelectPermissions, formatSelectPermissions(hasura.RowsLimit, hasura.EnableAggregations, t.Columns...))
201201

202+
if err := getRelationships(&t.HasuraSchema, t.Name, typ); err != nil {
203+
return t, err
204+
}
205+
202206
return t, nil
203207
}
204208

209+
type rel struct {
210+
tableName string
211+
remoteField string
212+
field string
213+
name string
214+
typ string
215+
comment string
216+
}
217+
218+
func getRelationships(t *Table, name string, typ reflect.Type) error {
219+
for i := 0; i < typ.NumField(); i++ {
220+
field := typ.Field(i)
221+
tag := field.Tag.Get("hasura")
222+
if tag == "" {
223+
continue
224+
}
225+
226+
var r rel
227+
attrs := strings.Split(tag, ",")
228+
for i := range attrs {
229+
keyValue := strings.Split(attrs[i], ":")
230+
if len(keyValue) != 2 {
231+
return errors.Errorf("invalid hasura tag: %s", tag)
232+
}
233+
switch keyValue[0] {
234+
case "table":
235+
r.tableName = keyValue[1]
236+
case "field":
237+
r.field = keyValue[1]
238+
case "type":
239+
r.typ = keyValue[1]
240+
case "name":
241+
r.name = keyValue[1]
242+
case "comment":
243+
r.comment = keyValue[1]
244+
case "remote_field":
245+
r.remoteField = keyValue[1]
246+
}
247+
}
248+
249+
relationship := Relationship{
250+
Table: PGTable{
251+
Name: name,
252+
},
253+
Name: r.name,
254+
Comment: r.comment,
255+
Using: RelationshipUsing{
256+
Manual: &ManualRelationship{
257+
RemoteTable: PGTable{Name: r.tableName},
258+
ColumnMapping: map[string]string{
259+
r.field: r.remoteField,
260+
},
261+
},
262+
},
263+
}
264+
265+
switch r.typ {
266+
case "oto":
267+
t.ObjectRelationships = append(t.ObjectRelationships, relationship)
268+
case "otm", "mtm":
269+
t.ArrayRelationships = append(t.ArrayRelationships, relationship)
270+
}
271+
}
272+
273+
return nil
274+
}
275+
205276
func formatSelectPermissions(limit uint64, allowAggs bool, columns ...string) SelectPermission {
206277
if limit == 0 {
207278
limit = 10

hasura/requests.go

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,69 @@ type Source struct {
8787

8888
// Table -
8989
type Table struct {
90-
ObjectRelationships []interface{} `json:"object_relationships"`
91-
ArrayRelationships []interface{} `json:"array_relationships"`
90+
ObjectRelationships []Relationship `json:"object_relationships"`
91+
ArrayRelationships []Relationship `json:"array_relationships"`
9292
SelectPermissions []SelectPermission `json:"select_permissions"`
9393
Configuration TableConfiguration `json:"configuration"`
9494
Schema TableSchema `json:"table"`
9595
}
9696

97+
// Relationship -
98+
type Relationship struct {
99+
Table PGTable `json:"table"`
100+
Name string `json:"name"`
101+
Comment string `json:"comment,omitempty"`
102+
Using RelationshipUsing `json:"using"`
103+
}
104+
105+
// RelationshipUsing -
106+
type RelationshipUsing struct {
107+
Manual *ManualRelationship `json:"manual_configuration,omitempty"`
108+
FK *FKRelationship `json:"foreign_key_constraint_on,omitempty"`
109+
}
110+
111+
// PGTable -
112+
type PGTable struct {
113+
Name string `json:"name"`
114+
Schema string `json:"schema"`
115+
}
116+
117+
// UnmarshalJSON -
118+
func (t *PGTable) UnmarshalJSON(data []byte) error {
119+
type buf PGTable
120+
if err := json.Unmarshal(data, (*buf)(t)); err == nil {
121+
return err
122+
}
123+
124+
return json.Unmarshal(data, &t.Name)
125+
}
126+
127+
// MarshalJSON -
128+
func (t *PGTable) MarshalJSON() ([]byte, error) {
129+
if t.Schema == "" {
130+
return json.Marshal(t.Name)
131+
}
132+
133+
type buf PGTable
134+
return json.Marshal((*buf)(t))
135+
}
136+
137+
// ManualRelationship -
138+
type ManualRelationship struct {
139+
RemoteTable PGTable `json:"remote_table"`
140+
ColumnMapping map[string]string `json:"column_mapping"`
141+
}
142+
143+
// FKRelationship -
144+
type FKRelationship struct {
145+
Table string `json:"table"`
146+
Column string `json:"column"`
147+
}
148+
97149
func newMetadataTable(name, schema string) Table {
98150
return Table{
99-
ObjectRelationships: make([]interface{}, 0),
100-
ArrayRelationships: make([]interface{}, 0),
151+
ObjectRelationships: make([]Relationship, 0),
152+
ArrayRelationships: make([]Relationship, 0),
101153
SelectPermissions: make([]SelectPermission, 0),
102154
Schema: TableSchema{
103155
Name: name,

0 commit comments

Comments
 (0)