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

Add MySQL backend #4137

Merged
merged 22 commits into from Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0c84c1f
Add MySQL backend collection
adetunjii Feb 15, 2024
ac76a2a
fixed linting
adetunjii Feb 15, 2024
de071d8
fix linting
adetunjii Feb 15, 2024
d3206e4
Merge branch 'main' into mysql/collection
adetunjii Feb 16, 2024
f1169f5
fix typo
adetunjii Feb 16, 2024
6d05f79
Merge branch 'mysql/collection' of https://github.com/adetunjii/Ferre…
adetunjii Feb 16, 2024
d7a1362
Merge branch 'main' into mysql/collection
adetunjii Feb 19, 2024
22dd932
Merge branch 'main' into mysql/collection
AlekSi Feb 21, 2024
711e758
Merge branch 'main' into mysql/collection
adetunjii Feb 21, 2024
2740647
Fix InsertAll query
adetunjii Feb 22, 2024
088187f
Merge branch 'mysql/collection' of https://github.com/adetunjii/Ferre…
adetunjii Feb 22, 2024
7577d6f
Merge branch 'main' into mysql/collection
adetunjii Feb 22, 2024
3687aba
fixed linting
adetunjii Feb 22, 2024
b7963e9
Merge branch 'mysql/collection' of https://github.com/adetunjii/Ferre…
adetunjii Feb 22, 2024
012c4ad
Merge branch 'main' into mysql/collection
AlekSi Feb 25, 2024
724470f
Merge branch 'main' into mysql/collection
adetunjii Feb 26, 2024
2045ec2
Merge branch 'main' of https://github.com/FerretDB/FerretDB into mysq…
adetunjii Feb 28, 2024
6ff428a
Merge branch 'main' of https://github.com/FerretDB/FerretDB into mysq…
adetunjii Mar 1, 2024
1ce379a
Sanitize database and table names
adetunjii Mar 1, 2024
809f66c
Add MySQL backend
adetunjii Mar 1, 2024
1413518
fix linting
adetunjii Mar 1, 2024
28c0e5d
Merge branch 'main' into mysql-backend
AlekSi Mar 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
110 changes: 104 additions & 6 deletions internal/backends/mysql/backend.go
Expand Up @@ -15,7 +15,9 @@
package mysql

import (
"cmp"
"context"
"slices"

"github.com/prometheus/client_golang/prometheus"
"go.uber.org/zap"
Expand Down Expand Up @@ -43,7 +45,14 @@

// NewBackend creates a new Backend.
func NewBackend(params *NewBackendParams) (backends.Backend, error) {
return nil, lazyerrors.New("not yet implemented")
r, err := metadata.NewRegistry(params.URI, params.L, params.P)
if err != nil {
return nil, err

Check warning on line 50 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L48-L50

Added lines #L48 - L50 were not covered by tests
}

return backends.BackendContract(&backend{
r: r,
}), nil

Check warning on line 55 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L53-L55

Added lines #L53 - L55 were not covered by tests
}

// Close implements backends.Backend interface.
Expand All @@ -53,7 +62,56 @@

// Status implements backends.Backend interface.
func (b *backend) Status(ctx context.Context, params *backends.StatusParams) (*backends.StatusResult, error) {
return nil, lazyerrors.New("not yet implemented.")
dbs, err := b.r.DatabaseList(ctx)
if err != nil {
return nil, lazyerrors.Error(err)

Check warning on line 67 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L65-L67

Added lines #L65 - L67 were not covered by tests
}

var res backends.StatusResult

Check warning on line 70 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L70

Added line #L70 was not covered by tests

var pingSucceeded bool

Check warning on line 72 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L72

Added line #L72 was not covered by tests

for _, dbName := range dbs {
var cs []*metadata.Collection

Check warning on line 75 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L74-L75

Added lines #L74 - L75 were not covered by tests

if cs, err = b.r.CollectionList(ctx, dbName); err != nil {
return nil, lazyerrors.Error(err)

Check warning on line 78 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L77-L78

Added lines #L77 - L78 were not covered by tests
}

res.CountCollections += int64(len(cs))

Check warning on line 81 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L81

Added line #L81 was not covered by tests

colls, err := newDatabase(b.r, dbName).ListCollections(ctx, new(backends.ListCollectionsParams))
if err != nil {
return nil, lazyerrors.Error(err)

Check warning on line 85 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L83-L85

Added lines #L83 - L85 were not covered by tests
}

for _, cInfo := range colls.Collections {
if cInfo.Capped() {
res.CountCappedCollections++

Check warning on line 90 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L88-L90

Added lines #L88 - L90 were not covered by tests
}
}

if pingSucceeded {
continue

Check warning on line 95 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L94-L95

Added lines #L94 - L95 were not covered by tests
}

p, err := b.r.DatabaseGetExisting(ctx, dbName)
if err != nil {
return nil, lazyerrors.Error(err)

Check warning on line 100 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L98-L100

Added lines #L98 - L100 were not covered by tests
}

if p == nil {
continue

Check warning on line 104 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L103-L104

Added lines #L103 - L104 were not covered by tests
}

if err = p.Ping(ctx); err != nil {
return nil, lazyerrors.Error(err)

Check warning on line 108 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L107-L108

Added lines #L107 - L108 were not covered by tests
}

pingSucceeded = true

Check warning on line 111 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L111

Added line #L111 was not covered by tests
}

return &res, nil

Check warning on line 114 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L114

Added line #L114 was not covered by tests
}

// Database implements backends.Backend interface.
Expand All @@ -65,22 +123,62 @@
//
//nolint:lll // for readability
func (b *backend) ListDatabases(ctx context.Context, params *backends.ListDatabasesParams) (*backends.ListDatabasesResult, error) {
return nil, lazyerrors.New("not yet implemented")
list, err := b.r.DatabaseList(ctx)
if err != nil {
return nil, err

Check warning on line 128 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L126-L128

Added lines #L126 - L128 were not covered by tests
}

var res *backends.ListDatabasesResult

Check warning on line 131 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L131

Added line #L131 was not covered by tests

if params != nil && len(params.Name) > 0 {
i, found := slices.BinarySearchFunc(list, params.Name, func(dbName, t string) int {
return cmp.Compare(dbName, t)
})

Check warning on line 136 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L133-L136

Added lines #L133 - L136 were not covered by tests

var filteredList []string

Check warning on line 138 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L138

Added line #L138 was not covered by tests

if found {
filteredList = append(filteredList, list[i])

Check warning on line 141 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L140-L141

Added lines #L140 - L141 were not covered by tests
}

list = filteredList

Check warning on line 144 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L144

Added line #L144 was not covered by tests
}

res = &backends.ListDatabasesResult{
Databases: make([]backends.DatabaseInfo, 0, len(list)),

Check warning on line 148 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L147-L148

Added lines #L147 - L148 were not covered by tests
}

for _, dbName := range list {
res.Databases = append(res.Databases, backends.DatabaseInfo{
Name: dbName,
})

Check warning on line 154 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L151-L154

Added lines #L151 - L154 were not covered by tests
}

return res, nil

Check warning on line 157 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L157

Added line #L157 was not covered by tests
}

// DropDatabase implements backends.Backend interface.
func (b *backend) DropDatabase(ctx context.Context, params *backends.DropDatabaseParams) error {
return lazyerrors.New("not yet implemented.")
dropped, err := b.r.DatabaseDrop(ctx, params.Name)
if err != nil {
return lazyerrors.Error(err)

Check warning on line 164 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L162-L164

Added lines #L162 - L164 were not covered by tests
}

if !dropped {
return backends.NewError(backends.ErrorCodeDatabaseDoesNotExist, nil)

Check warning on line 168 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L167-L168

Added lines #L167 - L168 were not covered by tests
}

return nil

Check warning on line 171 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L171

Added line #L171 was not covered by tests
}

// Describe implements prometheus.Collector.
func (b *backend) Describe(ch chan<- *prometheus.Desc) {
// b.r.Describe(ch)
b.r.Describe(ch)

Check warning on line 176 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L176

Added line #L176 was not covered by tests
}

// Collect implements prometheus.Collector.
func (b *backend) Collect(ch chan<- prometheus.Metric) {
// b.r.Collect(ch)
b.r.Collect(ch)

Check warning on line 181 in internal/backends/mysql/backend.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/backend.go#L181

Added line #L181 was not covered by tests
}

// check interfaces
Expand Down
6 changes: 3 additions & 3 deletions internal/backends/mysql/collection.go
Expand Up @@ -189,7 +189,7 @@
}

q := fmt.Sprintf(
`UPDATE %s.%s SET %s = ? WHERE %s = ?`,
`UPDATE %q.%q SET %s = ? WHERE %s = ?`,

Check warning on line 192 in internal/backends/mysql/collection.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/collection.go#L192

Added line #L192 was not covered by tests
c.dbName, meta.TableName,
metadata.DefaultColumn,
metadata.IDColumn,
Expand Down Expand Up @@ -272,7 +272,7 @@
}

q := fmt.Sprintf(
`DELETE FROM %s.%s WHERE %s IN (%s)`,
`DELETE FROM %q.%q WHERE %s IN (%s)`,

Check warning on line 275 in internal/backends/mysql/collection.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/collection.go#L275

Added line #L275 was not covered by tests
c.dbName, meta.TableName,
column,
strings.Join(placeholders, ", "),
Expand Down Expand Up @@ -396,7 +396,7 @@
}

q := "OPTIMIZE TABLE "
q += fmt.Sprintf("%s.%s", c.dbName, coll.TableName)
q += fmt.Sprintf("%q.%q", c.dbName, coll.TableName)

Check warning on line 399 in internal/backends/mysql/collection.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/collection.go#L399

Added line #L399 was not covered by tests

if _, err = p.ExecContext(ctx, q); err != nil {
return nil, lazyerrors.Error(err)
Expand Down
2 changes: 1 addition & 1 deletion internal/backends/mysql/insert.go
Expand Up @@ -54,7 +54,7 @@
}

return fmt.Sprintf(
`INSERT INTO %s.%s (%s) VALUES %s`,
`INSERT INTO %q.%q (%s) VALUES %s`,

Check warning on line 57 in internal/backends/mysql/insert.go

View check run for this annotation

Codecov / codecov/patch

internal/backends/mysql/insert.go#L57

Added line #L57 was not covered by tests
schema, tableName,
columns,
strings.Join(rows, ", "),
Expand Down
6 changes: 6 additions & 0 deletions internal/util/fsql/db.go
Expand Up @@ -67,6 +67,12 @@
return db.sqlDB.Close()
}

// Ping calls [*sql.DB.Ping].
func (db *DB) Ping(ctx context.Context) error {
defer observability.FuncCall(ctx)()
return db.sqlDB.Ping()

Check warning on line 73 in internal/util/fsql/db.go

View check run for this annotation

Codecov / codecov/patch

internal/util/fsql/db.go#L71-L73

Added lines #L71 - L73 were not covered by tests
}

// QueryContext calls [*sql.DB.QueryContext].
func (db *DB) QueryContext(ctx context.Context, query string, args ...any) (*Rows, error) {
defer observability.FuncCall(ctx)()
Expand Down