Skip to content
This repository was archived by the owner on Sep 11, 2025. It is now read-only.
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
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
Loading