Skip to content

Commit

Permalink
feat: support MySQL database connections (#722)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattjohnsonpint authored Jan 24, 2025
1 parent 973f7ed commit 8e19ed8
Show file tree
Hide file tree
Showing 47 changed files with 4,861 additions and 343 deletions.
2 changes: 2 additions & 0 deletions .trunk/configs/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"datasource",
"dbname",
"dbpool",
"dburl",
"dcli",
"Debugf",
"dgraph",
Expand Down Expand Up @@ -87,6 +88,7 @@
"jackc",
"Jairus",
"jensneuse",
"jmoiron",
"joho",
"jsonlogs",
"jsonparser",
Expand Down
4 changes: 4 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@
"label": "HTTP Client Example",
"value": "http"
},
{
"label": "MySQL Client Example",
"value": "mysql"
},
{
"label": "Neo4j Client Example",
"value": "neo4j"
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
[#707](https://github.com/hypermodeinc/modus/pull/707)
- feat: support type aliases and redefinitions
[#721](https://github.com/hypermodeinc/modus/pull/721)
- feat: support MySQL database connections [#722](https://github.com/hypermodeinc/modus/pull/722)

## 2025-01-09 - CLI 0.16.6

Expand Down
1 change: 1 addition & 0 deletions go.work
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use (
./sdk/go/examples/embedding
./sdk/go/examples/graphql
./sdk/go/examples/http
./sdk/go/examples/mysql
./sdk/go/examples/neo4j
./sdk/go/examples/postgresql
./sdk/go/examples/simple
Expand Down
7 changes: 7 additions & 0 deletions lib/manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,13 @@ func parseManifestJson(data []byte, manifest *Manifest) error {
}
info.Name = name
manifest.Connections[name] = info
case ConnectionTypeMysql:
var info MysqlConnectionInfo
if err := json.Unmarshal(rawCon, &info); err != nil {
return fmt.Errorf("failed to parse mysql connection [%s]: %w", name, err)
}
info.Name = name
manifest.Connections[name] = info
case ConnectionTypeDgraph:
var info DgraphConnectionInfo
if err := json.Unmarshal(rawCon, &info); err != nil {
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 @@ -219,6 +219,24 @@
"required": ["type", "connString"],
"additionalProperties": false
},
{
"properties": {
"type": {
"type": "string",
"const": "mysql",
"description": "Type of the connection."
},
"connString": {
"type": "string",
"minLength": 1,
"pattern": "^mysql:\\/\\/(.*?@)?([0-9a-zA-Z.-]*?)(:\\d+)?(\\/[0-9a-zA-Z.-]+)?(\\?.+)?$",
"description": "The MySQL connection string in URI format.",
"markdownDescription": "The MySQL connection string in URI format.\n\nReference: https://docs.hypermode.com/modus/app-manifest#mysql-connection"
}
},
"required": ["type", "connString"],
"additionalProperties": false
},
{
"properties": {
"type": {
Expand Down
34 changes: 34 additions & 0 deletions lib/manifest/mysql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2025 Hypermode Inc.
* Licensed under the terms of the Apache License, Version 2.0
* See the LICENSE file that accompanied this code for further details.
*
* SPDX-FileCopyrightText: 2025 Hypermode Inc. <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

package manifest

const ConnectionTypeMysql ConnectionType = "mysql"

type MysqlConnectionInfo struct {
Name string `json:"-"`
Type ConnectionType `json:"type"`
ConnStr string `json:"connString"`
}

func (info MysqlConnectionInfo) ConnectionName() string {
return info.Name
}

func (info MysqlConnectionInfo) ConnectionType() ConnectionType {
return info.Type
}

func (info MysqlConnectionInfo) Hash() string {
return computeHash(info.Name, info.Type, info.ConnStr)
}

func (info MysqlConnectionInfo) Variables() []string {
return extractVariables(info.ConnStr)
}
20 changes: 20 additions & 0 deletions lib/manifest/test/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ func TestReadManifest(t *testing.T) {
Type: manifest.ConnectionTypePostgresql,
ConnStr: "postgresql://{{POSTGRESQL_USERNAME}}:{{POSTGRESQL_PASSWORD}}@1.2.3.4:5432/data?sslmode=disable",
},
"my-mysql": manifest.MysqlConnectionInfo{
Name: "my-mysql",
Type: manifest.ConnectionTypeMysql,
ConnStr: "mysql://{{MYSQL_USERNAME}}:{{MYSQL_PASSWORD}}@1.2.3.4:3306/mydb?sslmode=disable",
},
"my-dgraph-cloud": manifest.DgraphConnectionInfo{
Name: "my-dgraph-cloud",
Type: manifest.ConnectionTypeDgraph,
Expand Down Expand Up @@ -207,6 +212,20 @@ func TestPostgresConnectionInfo_Hash(t *testing.T) {
}
}

func TestMysqlConnectionInfo_Hash(t *testing.T) {
connection := manifest.MysqlConnectionInfo{
Name: "my-database",
ConnStr: "mysql://{{MYSQL_USERNAME}}:{{MYSQL_PASSWORD}}@1.2.3.4:3306/mydb?sslmode=disable",
}

expectedHash := "3b96055cec5bd4195901e1442c856fe5b5493b0af0dde8f64f1d14a4795f5272"

actualHash := connection.Hash()
if actualHash != expectedHash {
t.Errorf("Expected hash: %s, but got: %s", expectedHash, actualHash)
}
}

func TestDgraphCloudConnectionInfo_Hash(t *testing.T) {
connection := manifest.DgraphConnectionInfo{
Name: "my-dgraph-cloud",
Expand Down Expand Up @@ -259,6 +278,7 @@ func TestGetVariablesFromManifest(t *testing.T) {
"my-rest-api": {"API_TOKEN"},
"another-rest-api": {"USERNAME", "PASSWORD"},
"neon": {"POSTGRESQL_USERNAME", "POSTGRESQL_PASSWORD"},
"my-mysql": {"MYSQL_USERNAME", "MYSQL_PASSWORD"},
"my-dgraph-cloud": {"DGRAPH_KEY"},
"my-neo4j": {"NEO4J_USERNAME", "NEO4J_PASSWORD"},
}
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 @@ -64,6 +64,10 @@
"type": "postgresql",
"connString": "postgresql://{{POSTGRESQL_USERNAME}}:{{POSTGRESQL_PASSWORD}}@1.2.3.4:5432/data?sslmode=disable"
},
"my-mysql": {
"type": "mysql",
"connString": "mysql://{{MYSQL_USERNAME}}:{{MYSQL_PASSWORD}}@1.2.3.4:3306/mydb?sslmode=disable"
},
"my-dgraph-cloud": {
"type": "dgraph",
"grpcTarget": "frozen-mango.grpc.eu-central-1.aws.cloud.dgraph.io:443",
Expand Down
4 changes: 4 additions & 0 deletions runtime/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ require (
github.com/docker/go-connections v0.5.0
github.com/fatih/color v1.18.0
github.com/getsentry/sentry-go v0.31.1
github.com/go-sql-driver/mysql v1.8.1
github.com/go-viper/mapstructure/v2 v2.2.1
github.com/goccy/go-json v0.10.4
github.com/gofrs/flock v0.12.1
Expand All @@ -46,15 +47,18 @@ require (
github.com/tetratelabs/wazero v1.8.2
github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5
github.com/twpayne/go-geom v1.6.0
github.com/viterin/vek v0.4.2
github.com/wundergraph/graphql-go-tools/execution v1.2.0
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.142
github.com/xo/dburl v0.23.2
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8
golang.org/x/sys v0.29.0
google.golang.org/grpc v1.69.4
)

require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.54 // indirect
Expand Down
16 changes: 16 additions & 0 deletions runtime/go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/99designs/gqlgen v0.17.49 h1:b3hNGexHd33fBSAd4NDT/c3NCcQzcAVkknhN9ym36YQ=
github.com/99designs/gqlgen v0.17.49/go.mod h1:tC8YFVZMed81x7UJ7ORUwXF4Kn6SXuucFqQBhN8+BU0=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
Expand All @@ -11,6 +15,10 @@ github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/alecthomas/assert/v2 v2.10.0 h1:jjRCHsj6hBJhkmhznrCzoNpbA3zqy0fYiUcYZP/GkPY=
github.com/alecthomas/assert/v2 v2.10.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/archdx/zerolog-sentry v1.8.5 h1:W24e5+yfZiQ83yd9OjBw+o6ERUzyUlCpoBS97gUlwK8=
github.com/archdx/zerolog-sentry v1.8.5/go.mod h1:XrFHGe1CH5DQk/XSySu/IJSi5C9XR6+zpc97zVf/c4c=
github.com/aws/aws-sdk-go-v2 v1.33.0 h1:Evgm4DI9imD81V0WwD+TN4DCwjUMdc94TrduMLbgZJs=
Expand Down Expand Up @@ -100,6 +108,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q=
github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
Expand Down Expand Up @@ -138,6 +148,8 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hypermodeinc/modus/lib/manifest v0.16.1 h1:/37OgLlRhn9UNxNChzCUSDNNUqWHyRliPxQ1EoeQrRM=
github.com/hypermodeinc/modus/lib/manifest v0.16.1/go.mod h1:NaG6aE+ekaufwqblbd70t/s1urmAQjNPL1nB4YhM27E=
github.com/hypermodeinc/modus/lib/metadata v0.15.0 h1:Qu75TZg7l43Fi61EhnjasTHZvztrGA90vzDLnCB6ILI=
Expand Down Expand Up @@ -282,6 +294,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/twpayne/go-geom v1.6.0 h1:WPOJLCdd8OdcnHvKQepLKwOZrn5BzVlNxtQB59IDHRE=
github.com/twpayne/go-geom v1.6.0/go.mod h1:Kr+Nly6BswFsKM5sd31YaoWS5PeDDH2NftJTK7Gd028=
github.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8=
github.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww=
github.com/viterin/partial v1.1.0 h1:iH1l1xqBlapXsYzADS1dcbizg3iQUKTU1rbwkHv/80E=
Expand All @@ -298,6 +312,8 @@ github.com/wundergraph/graphql-go-tools/execution v1.2.0 h1:9PXcNSN2n231q/YZZS3k
github.com/wundergraph/graphql-go-tools/execution v1.2.0/go.mod h1:sv2LtqCiTCdiK0P6x3KUYLb9C1V8RW9H/9eqEdfgktY=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.142 h1:CNuk0zoqmoJVP9Wq03GWLvi64Vpq1qwBIdRgV1669U8=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.142/go.mod h1:B7eV0Qh8Lop9QzIOQcsvKp3S0ejfC6mgyWoJnI917yQ=
github.com/xo/dburl v0.23.2 h1:Fl88cvayrgE56JA/sqhNMLljCW/b7RmG1mMkKMZUFgA=
github.com/xo/dburl v0.23.2/go.mod h1:uazlaAQxj4gkshhfuuYyvwCBouOmNnG2aDxTCFZpmL4=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
Expand Down
2 changes: 1 addition & 1 deletion runtime/services/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func Stop(ctx context.Context) {

collections.Shutdown(ctx)
middleware.Shutdown()
sqlclient.ShutdownPGPools()
sqlclient.Shutdown()
dgraphclient.ShutdownConns()
neo4jclient.CloseDrivers(ctx)
logger.Close()
Expand Down
Loading

0 comments on commit 8e19ed8

Please sign in to comment.