Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support new Dgraph connection string format #803

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

# Change Log

## 2025-03-28 - Runtime 0.17.7

- feat: support new Dgraph connection string format [#803](https://github.com/hypermodeinc/modus/pull/803)

## 2025-03-20 - Runtime 0.17.6

- fix: correct json in introspection query results [#798](https://github.com/hypermodeinc/modus/pull/798)
Expand Down
1 change: 1 addition & 0 deletions lib/manifest/dgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const ConnectionTypeDgraph ConnectionType = "dgraph"
type DgraphConnectionInfo struct {
Name string `json:"-"`
Type ConnectionType `json:"type"`
ConnStr string `json:"connString"`
GrpcTarget string `json:"grpcTarget"`
Key string `json:"key"`
}
Expand Down
18 changes: 18 additions & 0 deletions lib/manifest/modus_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,24 @@
"required": ["type", "connString"],
"additionalProperties": false
},
{
"properties": {
"type": {
"type": "string",
"const": "dgraph",
"description": "Type of the connection."
},
"connString": {
"type": "string",
"minLength": 1,
"pattern": "^dgraph:\\/\\/(.*?@)?([0-9a-zA-Z.-]*?)(:\\d+)?(\\/[0-9a-zA-Z.-]+)?(\\?.+)?$",
"description": "The Dgraph connection string in URI format.",
"markdownDescription": "The Dgraph connection string in URI format.\n\nReference: https://docs.hypermode.com/modus/app-manifest#dgraph-connection"
}
},
"required": ["type", "connString"],
"additionalProperties": false
},
{
"properties": {
"type": {
Expand Down
5 changes: 5 additions & 0 deletions lib/manifest/test/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ func TestReadManifest(t *testing.T) {
GrpcTarget: "localhost:9080",
Key: "",
},
"dgraph-with-connstr": manifest.DgraphConnectionInfo{
Name: "dgraph-with-connstr",
Type: manifest.ConnectionTypeDgraph,
ConnStr: "dgraph://localhost:9080?sslmode=disable",
},
"my-neo4j": manifest.Neo4jConnectionInfo{
Name: "my-neo4j",
Type: manifest.ConnectionTypeNeo4j,
Expand Down
4 changes: 4 additions & 0 deletions lib/manifest/test/valid_modus.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@
"type": "dgraph",
"grpcTarget": "localhost:9080"
},
"dgraph-with-connstr": {
"type": "dgraph",
"connString": "dgraph://localhost:9080?sslmode=disable"
},
"my-neo4j": {
"type": "neo4j",
"dbUri": "bolt://localhost:7687",
Expand Down
6 changes: 4 additions & 2 deletions runtime/dgraphclient/dgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ import (

"github.com/dgraph-io/dgo/v240"
"github.com/dgraph-io/dgo/v240/protos/api"
"google.golang.org/grpc"
)

type dgraphConnector struct {
conn *grpc.ClientConn
dgClient *dgo.Dgraph
}

func newDgraphConnector(dgClient *dgo.Dgraph) *dgraphConnector {
return &dgraphConnector{dgClient}
}

func (dc *dgraphConnector) alterSchema(ctx context.Context, schema string) (string, error) {
op := &api.Operation{Schema: schema}
if err := dc.dgClient.Alter(ctx, op); err != nil {
Expand Down
110 changes: 51 additions & 59 deletions runtime/dgraphclient/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,17 @@ package dgraphclient

import (
"context"
"crypto/x509"
"fmt"
"strings"

"github.com/hypermodeinc/modus/lib/manifest"
"github.com/hypermodeinc/modus/runtime/manifestdata"
"github.com/hypermodeinc/modus/runtime/secrets"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"

"github.com/dgraph-io/dgo/v240"
"github.com/dgraph-io/dgo/v240/protos/api"
"github.com/puzpuzpuz/xsync/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

var dgr = newDgraphRegistry()
Expand All @@ -34,33 +30,6 @@ type dgraphRegistry struct {
cache *xsync.MapOf[string, *dgraphConnector]
}

type authCreds struct {
token string
}

func (a *authCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
if len(a.token) == 0 {
return nil, nil
}

headers := make(map[string]string, 1)
if len(uri) > 0 && strings.Contains(strings.ToLower(uri[0]), "cloud.dgraph.io") {
headers["X-Auth-Token"] = a.token
} else {
token := a.token
if !strings.HasPrefix(token, "Bearer ") {
token = "Bearer " + token
}
headers["Authorization"] = token
}

return headers, nil
}

func (a *authCreds) RequireTransportSecurity() bool {
return true
}

func newDgraphRegistry() *dgraphRegistry {
return &dgraphRegistry{
cache: xsync.NewMapOf[string, *dgraphConnector](),
Expand All @@ -70,7 +39,7 @@ func newDgraphRegistry() *dgraphRegistry {
func ShutdownConns() {
dgr.cache.Range(func(key string, _ *dgraphConnector) bool {
if connector, ok := dgr.cache.LoadAndDelete(key); ok {
connector.conn.Close()
connector.dgClient.Close()
}
return true
})
Expand Down Expand Up @@ -101,42 +70,65 @@ func createConnector(ctx context.Context, dgName string) (*dgraphConnector, erro
}

connection := info.(manifest.DgraphConnectionInfo)
if connection.GrpcTarget == "" {
return nil, fmt.Errorf("dgraph connection [%s] has empty GrpcTarget", dgName)
}

var opts []grpc.DialOption
if strings.Split(connection.GrpcTarget, ":")[0] == "localhost" {
opts = []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
if connection.ConnStr != "" {
if connection.GrpcTarget != "" {
return nil, fmt.Errorf("dgraph connection [%s] has both connString and grpcTarget (use one or the other)", dgName)
} else if connection.Key != "" {
return nil, fmt.Errorf("dgraph connection [%s] has both connString and key (the key should be part of the connection string)", dgName)
}
} else {
pool, err := x509.SystemCertPool()
connStr, err := secrets.ApplySecretsToString(ctx, info, connection.ConnStr)
if err != nil {
return nil, err
}
creds := credentials.NewClientTLSFromCert(pool, "")
opts = []grpc.DialOption{
grpc.WithTransportCredentials(creds),
return connectWithConnectionString(connStr)
} else if connection.GrpcTarget != "" {
target, err := secrets.ApplySecretsToString(ctx, info, connection.GrpcTarget)
if err != nil {
return nil, err
}
if connection.Key != "" {
if conKey, err := secrets.ApplySecretsToString(ctx, info, connection.Key); err != nil {
return nil, err
} else if conKey != "" {
opts = append(opts, grpc.WithPerRPCCredentials(&authCreds{conKey}))
}
key, err := secrets.ApplySecretsToString(ctx, info, connection.Key)
if err != nil {
return nil, err
}
return connectWithGrpcTarget(target, key)
} else {
return nil, fmt.Errorf("dgraph connection [%s] needs either a connString or a grpcTarget", dgName)
}
}

conn, err := grpc.NewClient(connection.GrpcTarget, opts...)
if err != nil {
func connectWithConnectionString(connStr string) (*dgraphConnector, error) {
if dgClient, err := dgo.Open(connStr); err != nil {
return nil, err
} else {
return newDgraphConnector(dgClient), nil
}
}

ds := &dgraphConnector{
conn: conn,
dgClient: dgo.NewDgraphClient(api.NewDgraphClient(conn)),
func connectWithGrpcTarget(target string, key string) (*dgraphConnector, error) {
var opts []dgo.ClientOption
if strings.Split(target, ":")[0] == "localhost" {
opts = []dgo.ClientOption{
dgo.WithGrpcOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
}
} else if key == "" {
opts = []dgo.ClientOption{
dgo.WithSystemCertPool(),
}
} else if strings.Contains(strings.ToLower(target), "cloud.dgraph.io") {
opts = []dgo.ClientOption{
dgo.WithSystemCertPool(),
dgo.WithDgraphAPIKey(key),
}
} else {
opts = []dgo.ClientOption{
dgo.WithSystemCertPool(),
dgo.WithBearerToken(key),
}
}

return ds, nil
if dgClient, err := dgo.NewClient(target, opts...); err != nil {
return nil, err
} else {
return newDgraphConnector(dgClient), nil
}
}
23 changes: 10 additions & 13 deletions runtime/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/hypermodeinc/modus/runtime
go 1.24.0

require (
github.com/hypermodeinc/modus/lib/manifest v0.17.0
github.com/hypermodeinc/modus/lib/manifest v0.17.1
github.com/hypermodeinc/modus/lib/metadata v0.15.0
github.com/hypermodeinc/modus/lib/wasmextractor v0.13.0 // indirect
)
Expand All @@ -16,7 +16,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17
github.com/buger/jsonparser v1.1.1
github.com/chewxy/math32 v1.11.1
github.com/dgraph-io/dgo/v240 v240.1.0
github.com/dgraph-io/dgo/v240 v240.2.0
github.com/docker/docker v28.0.2+incompatible
github.com/docker/go-connections v0.5.0
github.com/fatih/color v1.18.0
Expand Down Expand Up @@ -55,17 +55,6 @@ require (
google.golang.org/grpc v1.71.0
)

require (
github.com/containerd/log v0.1.0 // indirect
github.com/hypermodeinc/dgraph/v24 v24.0.3-0.20250123224129-a0d027dcffe0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
)

require (
contrib.go.opencensus.io/exporter/jaeger v0.2.1 // indirect
contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect
Expand Down Expand Up @@ -103,6 +92,7 @@ require (
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/dgraph-io/badger/v4 v4.5.1 // indirect
Expand Down Expand Up @@ -153,6 +143,7 @@ require (
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/vault/api v1.15.0 // indirect
github.com/hypermodeinc/dgraph/v24 v24.0.3-0.20250123224129-a0d027dcffe0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
Expand Down Expand Up @@ -182,11 +173,14 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/panicwrap v1.0.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/phf/go-queue v0.0.0-20170504031614-9abe38d0371d // indirect
github.com/philhofer/fwd v1.1.2 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
Expand All @@ -199,10 +193,13 @@ require (
github.com/r3labs/sse/v2 v2.10.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/soheilhy/cmux v0.1.5 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
Expand Down
8 changes: 4 additions & 4 deletions runtime/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvw
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/dgraph-io/badger/v4 v4.5.1 h1:7DCIXrQjo1LKmM96YD+hLVJ2EEsyyoWxJfpdd56HLps=
github.com/dgraph-io/badger/v4 v4.5.1/go.mod h1:qn3Be0j3TfV4kPbVoK0arXCD1/nr1ftth6sbL5jxdoA=
github.com/dgraph-io/dgo/v240 v240.1.0 h1:xd8z9kEXDWOAblaLJ2HLg2tXD6ngMQwq3ehLUS7GKNg=
github.com/dgraph-io/dgo/v240 v240.1.0/go.mod h1:r8WASETKfodzKqThSAhhTNIzcEMychArKKlZXQufWuA=
github.com/dgraph-io/dgo/v240 v240.2.0 h1:dX7CCx7OSPl38GQ7Pa6jUB1RN21tyNlYpjNFgOsqp7k=
github.com/dgraph-io/dgo/v240 v240.2.0/go.mod h1:CyEuwJgQ8NoNjWbj2ZnvVFPixe5akCbWPR1O0fHpQ+U=
github.com/dgraph-io/gqlgen v0.13.2 h1:TNhndk+eHKj5qE7BenKKSYdSIdOGhLqxR1rCiMso9KM=
github.com/dgraph-io/gqlgen v0.13.2/go.mod h1:iCOrOv9lngN7KAo+jMgvUPVDlYHdf7qDwsTkQby2Sis=
github.com/dgraph-io/gqlparser/v2 v2.1.1/go.mod h1:MYS4jppjyx8b9tuUtjV7jU1UFZK6P9fvO8TsIsQtRKU=
Expand Down Expand Up @@ -412,8 +412,8 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hypermodeinc/dgraph/v24 v24.0.3-0.20250123224129-a0d027dcffe0 h1:yOWDWYXrF8cfjXbB3fqabYDKcMqJWqgPKAraauinRe4=
github.com/hypermodeinc/dgraph/v24 v24.0.3-0.20250123224129-a0d027dcffe0/go.mod h1:cxYPGOzHMDPQbv5uf9i2CI/dWKrKcyVmRLX7j/P3DxM=
github.com/hypermodeinc/modus/lib/manifest v0.17.0 h1:IelVTN1Bj3ErdyqRLk+3CCPKJJxKnEDsIwL3Rl48TKY=
github.com/hypermodeinc/modus/lib/manifest v0.17.0/go.mod h1:E/lB1Je+vugQhIOfbnJJShTurKzNBp9ZfgQnOrqmfQI=
github.com/hypermodeinc/modus/lib/manifest v0.17.1 h1:EuZRni0s+CNPbN+hFcTcFGmo6n2Mr22Mq7l71Lu4YcQ=
github.com/hypermodeinc/modus/lib/manifest v0.17.1/go.mod h1:HVrZY6o4wuZThtbOXEWInga4I7tVzdgK1gSNg1bsYX0=
github.com/hypermodeinc/modus/lib/metadata v0.15.0 h1:Qu75TZg7l43Fi61EhnjasTHZvztrGA90vzDLnCB6ILI=
github.com/hypermodeinc/modus/lib/metadata v0.15.0/go.mod h1:vnIwX2DpQyGk93DawGgIaqC5jEdvMeA9tGtvefbwTJw=
github.com/hypermodeinc/modus/lib/wasmextractor v0.13.0 h1:9o8qqAllL9qIPYqc5adF+Aw3XWLmLqPiBPMu0AIyiMI=
Expand Down
2 changes: 1 addition & 1 deletion sdk/go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.23.1
toolchain go1.24.1

require (
github.com/hypermodeinc/modus/lib/manifest v0.17.0
github.com/hypermodeinc/modus/lib/manifest v0.17.1
github.com/hypermodeinc/modus/lib/wasmextractor v0.13.0
)

Expand Down
4 changes: 2 additions & 2 deletions sdk/go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hypermodeinc/modus/lib/manifest v0.17.0 h1:IelVTN1Bj3ErdyqRLk+3CCPKJJxKnEDsIwL3Rl48TKY=
github.com/hypermodeinc/modus/lib/manifest v0.17.0/go.mod h1:E/lB1Je+vugQhIOfbnJJShTurKzNBp9ZfgQnOrqmfQI=
github.com/hypermodeinc/modus/lib/manifest v0.17.1 h1:EuZRni0s+CNPbN+hFcTcFGmo6n2Mr22Mq7l71Lu4YcQ=
github.com/hypermodeinc/modus/lib/manifest v0.17.1/go.mod h1:HVrZY6o4wuZThtbOXEWInga4I7tVzdgK1gSNg1bsYX0=
github.com/hypermodeinc/modus/lib/wasmextractor v0.13.0 h1:9o8qqAllL9qIPYqc5adF+Aw3XWLmLqPiBPMu0AIyiMI=
github.com/hypermodeinc/modus/lib/wasmextractor v0.13.0/go.mod h1:YCesMU95vF5qkscLMKSYr92OloLe1KGwyiqW2i4OmnE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
Expand Down