aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Majewsky <majewsky@gmx.net>2026-04-14 01:00:20 +0200
committerStefan Majewsky <majewsky@gmx.net>2026-04-14 01:00:20 +0200
commit5fb8e4a13afbc4cc3ef6e7492c020f8abf63b37f (patch)
treeb1f4fe95778920cad3fd3b02b00cd44b124bf11e
parentd75031ffd1667c330ccc281ea330503eaeaea88a (diff)
downloadgo-oblast-5fb8e4a13afbc4cc3ef6e7492c020f8abf63b37f.tar.gz
add MysqlDialect
-rw-r--r--dialect.go12
-rw-r--r--plan_test.go63
2 files changed, 75 insertions, 0 deletions
diff --git a/dialect.go b/dialect.go
index a2827e2..d74725e 100644
--- a/dialect.go
+++ b/dialect.go
@@ -39,6 +39,18 @@ type Dialect interface {
InsertSuffixForAutoColumns(columns []string) string
}
+// MysqlDialect is the dialect of MySQL and MariaDB databases.
+func MysqlDialect() Dialect {
+ return mysqlDialect{}
+}
+
+type mysqlDialect struct{}
+
+func (mysqlDialect) Placeholder(_ int) string { return "?" }
+func (mysqlDialect) QuoteIdentifier(name string) string { return "`" + name + "`" }
+func (mysqlDialect) UsesLastInsertID() bool { return true }
+func (mysqlDialect) InsertSuffixForAutoColumns(columns []string) string { return "" }
+
// PostgresDialect is the dialect of PostgreSQL databases.
func PostgresDialect() Dialect {
return postgresDialect{}
diff --git a/plan_test.go b/plan_test.go
index 1095016..3568447 100644
--- a/plan_test.go
+++ b/plan_test.go
@@ -71,6 +71,25 @@ func TestQueryConstructionBasic(t *testing.T) {
PrimaryKeyColumnNames: []string{"ID"},
}
+ t.Run("MysqlDialect", func(t *testing.T) {
+ plan, err := buildPlan(reflect.TypeFor[record](), MysqlDialect(), opts)
+ if err != nil {
+ t.Error(err)
+ }
+ assert.Equal(t, plan.Select.Query, "SELECT `ID`, `Description`, `CreatedAt` FROM `basic_records` WHERE ")
+ assert.DeepEqual(t, plan.Select.ArgumentIndexes, nil)
+ assert.DeepEqual(t, plan.Select.ScanIndexes, [][]int{{0}, {1}, {2}})
+ assert.Equal(t, plan.Insert.Query, "INSERT INTO `basic_records` (`Description`, `CreatedAt`) VALUES (?, ?)")
+ assert.DeepEqual(t, plan.Insert.ArgumentIndexes, [][]int{{1}, {2}})
+ assert.DeepEqual(t, plan.Insert.ScanIndexes, [][]int{{0}})
+ assert.Equal(t, plan.Update.Query, "UPDATE `basic_records` SET `Description` = ?, `CreatedAt` = ? WHERE `ID` = ?")
+ assert.DeepEqual(t, plan.Update.ArgumentIndexes, [][]int{{1}, {2}, {0}})
+ assert.DeepEqual(t, plan.Update.ScanIndexes, nil)
+ assert.Equal(t, plan.Delete.Query, "DELETE FROM `basic_records` WHERE `ID` = ?")
+ assert.DeepEqual(t, plan.Delete.ArgumentIndexes, [][]int{{0}})
+ assert.DeepEqual(t, plan.Delete.ScanIndexes, nil)
+ })
+
t.Run("PostgresDialect", func(t *testing.T) {
plan, err := buildPlan(reflect.TypeFor[record](), PostgresDialect(), opts)
if err != nil {
@@ -119,6 +138,25 @@ func TestQueryConstructionWithoutPrimaryKey(t *testing.T) {
TableName: "foo_bar_relations",
}
+ t.Run("MysqlDialect", func(t *testing.T) {
+ plan, err := buildPlan(reflect.TypeFor[relation](), MysqlDialect(), opts)
+ if err != nil {
+ t.Error(err)
+ }
+ assert.Equal(t, plan.Select.Query, "SELECT `foo_id`, `bar_id` FROM `foo_bar_relations` WHERE ")
+ assert.DeepEqual(t, plan.Select.ArgumentIndexes, nil)
+ assert.DeepEqual(t, plan.Select.ScanIndexes, [][]int{{0}, {1}})
+ assert.Equal(t, plan.Insert.Query, "INSERT INTO `foo_bar_relations` (`foo_id`, `bar_id`) VALUES (?, ?)")
+ assert.DeepEqual(t, plan.Insert.ArgumentIndexes, [][]int{{0}, {1}})
+ assert.DeepEqual(t, plan.Insert.ScanIndexes, nil)
+ assert.Equal(t, plan.Update.Query, "")
+ assert.DeepEqual(t, plan.Update.ArgumentIndexes, nil)
+ assert.DeepEqual(t, plan.Update.ScanIndexes, nil)
+ assert.Equal(t, plan.Delete.Query, "")
+ assert.DeepEqual(t, plan.Delete.ArgumentIndexes, nil)
+ assert.DeepEqual(t, plan.Delete.ScanIndexes, nil)
+ })
+
t.Run("PostgresDialect", func(t *testing.T) {
plan, err := buildPlan(reflect.TypeFor[relation](), PostgresDialect(), opts)
if err != nil {
@@ -187,6 +225,7 @@ func TestQueryConstructionImpossble(t *testing.T) {
}
}
+ t.Run("MysqlDialect", testWith(MysqlDialect()))
t.Run("PostgresDialect", testWith(PostgresDialect()))
t.Run("SqliteDialect", testWith(SqliteDialect()))
}
@@ -202,6 +241,25 @@ func TestQueryConstructionWithMultiplePrimaryKeyColumns(t *testing.T) {
PrimaryKeyColumnNames: []string{"group_id", "name"},
}
+ t.Run("MysqlDialect", func(t *testing.T) {
+ plan, err := buildPlan(reflect.TypeFor[record](), MysqlDialect(), opts)
+ if err != nil {
+ t.Error(err)
+ }
+ assert.Equal(t, plan.Select.Query, "SELECT `group_id`, `name`, `created_at` FROM `complex_records` WHERE ")
+ assert.DeepEqual(t, plan.Select.ArgumentIndexes, nil)
+ assert.DeepEqual(t, plan.Select.ScanIndexes, [][]int{{0}, {1}, {2}})
+ assert.Equal(t, plan.Insert.Query, "INSERT INTO `complex_records` (`group_id`, `name`, `created_at`) VALUES (?, ?, ?)")
+ assert.DeepEqual(t, plan.Insert.ArgumentIndexes, [][]int{{0}, {1}, {2}})
+ assert.DeepEqual(t, plan.Insert.ScanIndexes, nil)
+ assert.Equal(t, plan.Update.Query, "UPDATE `complex_records` SET `created_at` = ? WHERE `group_id` = ? AND `name` = ?")
+ assert.DeepEqual(t, plan.Update.ArgumentIndexes, [][]int{{2}, {0}, {1}})
+ assert.DeepEqual(t, plan.Update.ScanIndexes, nil)
+ assert.Equal(t, plan.Delete.Query, "DELETE FROM `complex_records` WHERE `group_id` = ? AND `name` = ?")
+ assert.DeepEqual(t, plan.Delete.ArgumentIndexes, [][]int{{0}, {1}})
+ assert.DeepEqual(t, plan.Delete.ScanIndexes, nil)
+ })
+
t.Run("PostgresDialect", func(t *testing.T) {
plan, err := buildPlan(reflect.TypeFor[record](), PostgresDialect(), opts)
if err != nil {
@@ -252,6 +310,11 @@ func TestQueryConstructionWithMultipleAutoColumns(t *testing.T) {
PrimaryKeyColumnNames: []string{"id"},
}
+ t.Run("MysqlDialect", func(t *testing.T) {
+ _, err := NewStore[record](MysqlDialect())
+ assert.Equal(t, err.Error(), `cannot use type oblast.record for queries: multiple columns are marked as auto-filled (id, created_at), but this SQL dialect only supports at most one per table`)
+ })
+
t.Run("PostgresDialect", func(t *testing.T) {
plan, err := buildPlan(reflect.TypeFor[record](), PostgresDialect(), opts)
if err != nil {