diff --git a/config/config.go b/config/config.go index 4cdaddc..fc04d94 100644 --- a/config/config.go +++ b/config/config.go @@ -53,8 +53,10 @@ type Database struct { // Hasura - type Hasura struct { - URL string `yaml:"url"` - Secret string `yaml:"admin_secret"` + URL string `yaml:"url"` + Secret string `yaml:"admin_secret"` + RowsLimit uint64 `yaml:"select_limit"` + EnableAggregations bool `yaml:"allow_aggregation"` } // Validate - diff --git a/hasura/api.go b/hasura/api.go index c7372b6..75c9ca0 100644 --- a/hasura/api.go +++ b/hasura/api.go @@ -148,3 +148,16 @@ func (api *API) TrackTable(schema, name string) error { } return api.post("/v1/query", nil, req, nil) } + +// CreateSelectPermissions - A select permission is used to restrict access to only the specified columns and rows. +func (api *API) CreateSelectPermissions(table, role string, perm Permission) error { + req := request{ + Type: "create_select_permission", + Args: map[string]interface{}{ + "table": table, + "role": role, + "permission": perm, + }, + } + return api.post("/v1/query", nil, req, nil) +} diff --git a/hasura/hasura.go b/hasura/hasura.go index 2afcc0a..7f3ce31 100644 --- a/hasura/hasura.go +++ b/hasura/hasura.go @@ -21,7 +21,7 @@ func Create(hasura config.Hasura, cfg config.Database, views []string, models .. time.Sleep(time.Second * 10) } - metadata, err := Generate(cfg, models...) + metadata, err := Generate(hasura, cfg, models...) if err != nil { return err } @@ -80,11 +80,11 @@ func Create(hasura config.Hasura, cfg config.Database, views []string, models .. } // Generate - creates hasura table structure in JSON from `models`. `models` should be pointer to your table models. `cfg` is DB config from YAML. -func Generate(cfg config.Database, models ...interface{}) (map[string]interface{}, error) { +func Generate(hasura config.Hasura, cfg config.Database, models ...interface{}) (map[string]interface{}, error) { tables := make([]interface{}, 0) schema := getSchema(cfg) for _, model := range models { - table, err := generateOne(schema, model) + table, err := generateOne(hasura, schema, model) if err != nil { return nil, err } @@ -108,7 +108,7 @@ func newTable(schema, name string) table { Name: name, } } -func generateOne(schema string, model interface{}) (table, error) { +func generateOne(hasura config.Hasura, schema string, model interface{}) (table, error) { value := reflect.ValueOf(model) if value.Kind() != reflect.Ptr { return table{}, errors.Errorf("Model has to be pointer") @@ -123,10 +123,10 @@ func generateOne(schema string, model interface{}) (table, error) { t.Columns = getColumns(typ) if p, ok := t.HasuraSchema["select_permissions"]; ok { - t.HasuraSchema["select_permissions"] = append(p.([]interface{}), formatSelectPermissions(t.Columns...)) + t.HasuraSchema["select_permissions"] = append(p.([]interface{}), formatSelectPermissions(hasura.RowsLimit, hasura.EnableAggregations, t.Columns...)) } else { t.HasuraSchema["select_permissions"] = []interface{}{ - formatSelectPermissions(t.Columns...), + formatSelectPermissions(hasura.RowsLimit, hasura.EnableAggregations, t.Columns...), } } t.HasuraSchema["object_relationships"] = []interface{}{} @@ -135,13 +135,17 @@ func generateOne(schema string, model interface{}) (table, error) { return t, nil } -func formatSelectPermissions(columns ...string) map[string]interface{} { +func formatSelectPermissions(limit uint64, allowAggs bool, columns ...string) map[string]interface{} { + if limit == 0 { + limit = 10 + } return map[string]interface{}{ "role": "user", "permission": map[string]interface{}{ "columns": columns, "filter": map[string]interface{}{}, - "allow_aggregations": true, + "allow_aggregations": allowAggs, + "limit": limit, }, } } diff --git a/hasura/hasura_test.go b/hasura/hasura_test.go index 3efc660..80686ea 100644 --- a/hasura/hasura_test.go +++ b/hasura/hasura_test.go @@ -124,6 +124,7 @@ func Test_getColumns(t *testing.T) { func TestGenerate(t *testing.T) { type args struct { cfg config.Database + hasura config.Hasura models []interface{} } tests := []struct { @@ -138,16 +139,20 @@ func TestGenerate(t *testing.T) { cfg: config.Database{ Kind: "mysql", }, + hasura: config.Hasura{ + EnableAggregations: true, + RowsLimit: 5, + }, models: []interface{}{ &testTable{}, &testTable2{}, &testTable3{}, &testTable4{}, }, }, - want: `{"tables":[{"array_relationships":[],"object_relationships":[],"select_permissions":[{"permission":{"allow_aggregations":true,"columns":["field_1","field_2"],"filter":{}},"role":"user"}],"table":{"name":"test_table","schema":"public"}},{"array_relationships":[],"object_relationships":[],"select_permissions":[{"permission":{"allow_aggregations":true,"columns":["field_1","field_2"],"filter":{}},"role":"user"}],"table":{"name":"fake_name","schema":"public"}},{"array_relationships":[],"object_relationships":[],"select_permissions":[{"permission":{"allow_aggregations":true,"columns":["field_2"],"filter":{}},"role":"user"}],"table":{"name":"test_table_3","schema":"public"}},{"array_relationships":[],"object_relationships":[],"select_permissions":[{"permission":{"allow_aggregations":true,"columns":["field_2","field_3"],"filter":{}},"role":"user"}],"table":{"name":"test_table_4","schema":"public"}}],"version":2}`, + want: `{"tables":[{"array_relationships":[],"object_relationships":[],"select_permissions":[{"permission":{"limit":5,"allow_aggregations":true,"columns":["field_1","field_2"],"filter":{}},"role":"user"}],"table":{"name":"test_table","schema":"public"}},{"array_relationships":[],"object_relationships":[],"select_permissions":[{"permission":{"limit":5,"allow_aggregations":true,"columns":["field_1","field_2"],"filter":{}},"role":"user"}],"table":{"name":"fake_name","schema":"public"}},{"array_relationships":[],"object_relationships":[],"select_permissions":[{"permission":{"limit":5,"allow_aggregations":true,"columns":["field_2"],"filter":{}},"role":"user"}],"table":{"name":"test_table_3","schema":"public"}},{"array_relationships":[],"object_relationships":[],"select_permissions":[{"permission":{"limit":5,"allow_aggregations":true,"columns":["field_2","field_3"],"filter":{}},"role":"user"}],"table":{"name":"test_table_4","schema":"public"}}],"version":2}`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Generate(tt.args.cfg, tt.args.models...) + got, err := Generate(tt.args.hasura, tt.args.cfg, tt.args.models...) if (err != nil) != tt.wantErr { t.Errorf("Generate() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/hasura/requests.go b/hasura/requests.go index 8c5dcc8..45ebf18 100644 --- a/hasura/requests.go +++ b/hasura/requests.go @@ -4,3 +4,11 @@ type request struct { Type string `json:"type"` Args interface{} `json:"args"` } + +// Permission - +type Permission struct { + Columns string `json:"columns"` + Limit uint64 `json:"limit"` + AllowAggs bool `json:"allow_aggregations"` + Filter interface{} `json:"filter,omitempty"` +}