From 5d760626514e0f4c7e6fb4f2638f24de9f14ca19 Mon Sep 17 00:00:00 2001 From: KarnerTh Date: Tue, 21 Nov 2023 20:13:26 +0100 Subject: [PATCH] add sqlite support (#55) * add sqlite support * prepare sqlite database for ci * do not fail if sqlite database does not exists when preparing * fix file piping * use relative path for sqlite database file --- .github/workflows/test.yml | 2 + Makefile | 5 + config/config_test.go | 4 +- database/connector_factory.go | 5 + database/connector_factory_test.go | 1 + database/database_integration_test.go | 69 ++++++---- database/sqlite.go | 147 ++++++++++++++++++++++ database/type.go | 1 + go.mod | 17 ++- go.sum | 41 +++++- test/db-table-setup.sql | 35 ++---- test/sqlite/sqlite-enum-setup.sql | 6 + test/sqlite/sqlite-multiple-databases.sql | 8 ++ 13 files changed, 290 insertions(+), 51 deletions(-) create mode 100644 database/sqlite.go create mode 100644 test/sqlite/sqlite-enum-setup.sql create mode 100644 test/sqlite/sqlite-multiple-databases.sql diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aa6a97d..0ffb6df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,6 +8,8 @@ jobs: uses: actions/checkout@v3 - name: Start container with test databases run: docker-compose -f test/docker-compose.yaml up -d + - name: Prepare sqlite database + run: make prepare-sqlite - name: Wait for docker containers to start run: sleep 30 - name: Set up Go diff --git a/Makefile b/Makefile index 9cf19b3..907e1d4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,11 @@ GIT_TAG := $(shell git describe --tags --abbrev=0) test_target := "./..." +.PHONY: prepare-sqlite +prepare-sqlite: + rm -f mermerd_test.db + cat test/db-table-setup.sql test/sqlite/sqlite-enum-setup.sql test/sqlite/sqlite-multiple-databases.sql | sqlite3 mermerd_test.db + .PHONY: test-coverage test-coverage: go test -cover -coverprofile=coverage.out ./...; go tool cover -html=coverage.out -o coverage.html; rm coverage.out diff --git a/config/config_test.go b/config/config_test.go index 466c3cf..8adc94a 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -71,12 +71,12 @@ connectionStringSuggestions: assert.ElementsMatch(t, config.RelationshipLabels(), []RelationshipLabel{ - RelationshipLabel{ + { PkName: "schema.table1", FkName: "schema.table2", Label: "is_a", }, - RelationshipLabel{ + { PkName: "table-name", FkName: "another-table-name", Label: "has_many", diff --git a/database/connector_factory.go b/database/connector_factory.go index 2da5e47..6462f09 100644 --- a/database/connector_factory.go +++ b/database/connector_factory.go @@ -32,6 +32,11 @@ func (connectorFactory) NewConnector(connectionString string) (Connector, error) dbType: MsSql, connectionString: connectionString, }, nil + case strings.HasPrefix(connectionString, "sqlite3"): + return &sqliteConnector{ + dbType: Sqlite3, + connectionString: connectionString, + }, nil default: return nil, errors.New("could not create connector for db") } diff --git a/database/connector_factory_test.go b/database/connector_factory_test.go index eee13ba..695ab6e 100644 --- a/database/connector_factory_test.go +++ b/database/connector_factory_test.go @@ -17,6 +17,7 @@ func TestNewConnector(t *testing.T) { {connectionString: "postgres://user:password@localhost:5432/yourDb", expectedDbType: Postgres}, {connectionString: "mysql://root:password@tcp(127.0.0.1:3306)/yourDb", expectedDbType: MySql}, {connectionString: "sqlserver://sa:securePassword1!@localhost:1433?database=mermerd_test", expectedDbType: MsSql}, + {connectionString: "sqlite3://mermerd_test.db", expectedDbType: Sqlite3}, } for index, testCase := range testCases { diff --git a/database/database_integration_test.go b/database/database_integration_test.go index 7193fce..b4be533 100644 --- a/database/database_integration_test.go +++ b/database/database_integration_test.go @@ -26,6 +26,7 @@ var ( testConnectionMySql connectionParameter = connectionParameter{connectionString: "mysql://root:password@tcp(127.0.0.1:3306)/mermerd_test", schema: "mermerd_test"} testConnectionMsSql connectionParameter = connectionParameter{connectionString: "sqlserver://sa:securePassword1!@localhost:1433?database=mermerd_test", schema: "dbo"} testConnectionAzure connectionParameter = connectionParameter{connectionString: "sqlserver://sa:securePassword1!@localhost:1434?database=mermerd_test", schema: "dbo"} + testConnectionSqlite connectionParameter = connectionParameter{connectionString: "sqlite3://../mermerd_test.db", schema: "mermerd_test"} ) func TestDatabaseIntegrations(t *testing.T) { @@ -60,6 +61,11 @@ func TestDatabaseIntegrations(t *testing.T) { connectionString: testConnectionAzure.connectionString, schema: testConnectionAzure.schema, }, + { + dbType: Sqlite3, + connectionString: testConnectionSqlite.connectionString, + schema: testConnectionSqlite.schema, + }, } for _, testCase := range testCases { @@ -207,9 +213,11 @@ func TestDatabaseIntegrations(t *testing.T) { // Assert assert.Nil(t, err) assert.Len(t, constraintResults, 1) - constraint := constraintResults[0] - assert.True(t, constraint.IsPrimary) - assert.False(t, constraint.HasMultiplePK) + if len(constraintResults) >= 1 { + constraint := constraintResults[0] + assert.True(t, constraint.IsPrimary) + assert.False(t, constraint.HasMultiplePK) + } }) t.Run("Many-to-one relation #1", func(t *testing.T) { @@ -222,9 +230,11 @@ func TestDatabaseIntegrations(t *testing.T) { // Assert assert.Nil(t, err) assert.Len(t, constraintResults, 1) - constraint := constraintResults[0] - assert.False(t, constraint.IsPrimary) - assert.False(t, constraint.HasMultiplePK) + if len(constraintResults) >= 1 { + constraint := constraintResults[0] + assert.False(t, constraint.IsPrimary) + assert.False(t, constraint.HasMultiplePK) + } }) t.Run("Many-to-one relation #2", func(t *testing.T) { @@ -245,8 +255,10 @@ func TestDatabaseIntegrations(t *testing.T) { } } assert.NotNil(t, constraint) - assert.True(t, constraint.IsPrimary) - assert.True(t, constraint.HasMultiplePK) + if constraint != nil { + assert.True(t, constraint.IsPrimary) + assert.True(t, constraint.HasMultiplePK) + } }) // Multiple primary keys (https://github.com/KarnerTh/mermerd/issues/8) @@ -261,16 +273,22 @@ func TestDatabaseIntegrations(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, constraintResults) assert.Len(t, constraintResults, 2) - assert.True(t, constraintResults[0].IsPrimary) - assert.True(t, constraintResults[0].HasMultiplePK) - assert.Equal(t, constraintResults[0].ColumnName, "aid") - assert.True(t, constraintResults[1].IsPrimary) - assert.True(t, constraintResults[1].HasMultiplePK) - assert.Equal(t, constraintResults[1].ColumnName, "bid") + if len(constraintResults) >= 2 { + assert.True(t, constraintResults[0].IsPrimary) + assert.True(t, constraintResults[0].HasMultiplePK) + assert.Equal(t, constraintResults[0].ColumnName, "aid") + assert.True(t, constraintResults[1].IsPrimary) + assert.True(t, constraintResults[1].HasMultiplePK) + assert.Equal(t, constraintResults[1].ColumnName, "bid") + } }) }) t.Run("Multiple schemas (Issue #23)", func(t *testing.T) { + if testCase.dbType == Sqlite3 { + t.Skip("Sqlite does not support multiple schemas") + } + connector := getConnectionAndConnect(t) t.Run("GetTables", func(t *testing.T) { @@ -318,11 +336,14 @@ func TestDatabaseIntegrations(t *testing.T) { // Assert assert.Nil(t, err) assert.Len(t, constraintResults, 1) - assert.False(t, constraintResults[0].IsPrimary) - assert.False(t, constraintResults[0].HasMultiplePK) - assert.Equal(t, constraintResults[0].ColumnName, "aid") - assert.Equal(t, constraintResults[0].FkTable, "test_3_b") - assert.Equal(t, constraintResults[0].PkTable, "test_3_a") + + if len(constraintResults) >= 1 { + assert.False(t, constraintResults[0].IsPrimary) + assert.False(t, constraintResults[0].HasMultiplePK) + assert.Equal(t, constraintResults[0].ColumnName, "aid") + assert.Equal(t, constraintResults[0].FkTable, "test_3_b") + assert.Equal(t, constraintResults[0].PkTable, "test_3_a") + } }) t.Run("Get schema from FK and PK table", func(t *testing.T) { @@ -335,10 +356,12 @@ func TestDatabaseIntegrations(t *testing.T) { // Assert assert.Nil(t, err) assert.Len(t, constraintResults, 1) - assert.Equal(t, constraintResults[0].FkTable, "test_3_b") - assert.Equal(t, constraintResults[0].FkSchema, "other_db") - assert.Equal(t, constraintResults[0].PkTable, "test_3_a") - assert.Equal(t, constraintResults[0].PkSchema, testCase.schema) + if len(constraintResults) >= 1 { + assert.Equal(t, constraintResults[0].FkTable, "test_3_b") + assert.Equal(t, constraintResults[0].FkSchema, "other_db") + assert.Equal(t, constraintResults[0].PkTable, "test_3_a") + assert.Equal(t, constraintResults[0].PkSchema, testCase.schema) + } }) }) }) diff --git a/database/sqlite.go b/database/sqlite.go new file mode 100644 index 0000000..0eed783 --- /dev/null +++ b/database/sqlite.go @@ -0,0 +1,147 @@ +package database + +import ( + "database/sql" + "fmt" + "strings" + + _ "modernc.org/sqlite" +) + +type sqliteConnector baseConnector + +func (c *sqliteConnector) GetDbType() DbType { + return c.dbType +} + +func getFilenameFromConnectionString(connectionString string) string { + return strings.Replace(connectionString, "sqlite3://", "", 1) +} + +func (c *sqliteConnector) Connect() error { + db, err := sql.Open(c.dbType.String(), getFilenameFromConnectionString(c.connectionString)) + if err != nil { + return err + } + + if err := db.Ping(); err != nil { + return err + } + + c.db = db + return nil +} + +func (c *sqliteConnector) Close() { + err := c.db.Close() + if err != nil { + fmt.Println("could not close database connection", err) + } +} + +func (c *sqliteConnector) GetSchemas() ([]string, error) { + fileName := getFilenameFromConnectionString(c.connectionString) + schema := strings.Replace(fileName, ".db", "", 1) + return []string{schema}, nil +} + +func (c *sqliteConnector) GetTables(schemaNames []string) ([]TableDetail, error) { + rows, err := c.db.Query(` + select distinct tbl_name + from sqlite_schema + `) + if err != nil { + return nil, err + } + + var tables []TableDetail + for rows.Next() { + table := TableDetail{Schema: schemaNames[0]} + if err = rows.Scan(&table.Name); err != nil { + return nil, err + } + + table.Name = SanitizeValue(table.Name) + tables = append(tables, table) + } + + return tables, nil +} + +func (c *sqliteConnector) GetColumns(tableName TableDetail) ([]ColumnResult, error) { + rows, err := c.db.Query(` + select + t.name, + type, + pk > 0, -- first pk has 1, second has 2 ... + (case when fk.id is not null then 1 else 0 end) "isForeign", + (case when t."notnull" = true then false else true end) "nullable", + coalesce( + (select (case when i."unique" = true and i.origin = "u" then true else false end) "isUnique" + from pragma_index_list(:tableName) i + left join pragma_index_info(i.name) ii + where ii.name = t.name), + 0 + ) "isUnique" + from pragma_table_info(:tableName) t + left join pragma_foreign_key_list(:tableName) fk on t.name = fk."from"; + `, sql.Named("tableName", tableName.Name)) + if err != nil { + return nil, err + } + + var columns []ColumnResult + for rows.Next() { + var column ColumnResult + if err = rows.Scan(&column.Name, &column.DataType, &column.IsPrimary, &column.IsForeign, &column.IsNullable, &column.IsUnique); err != nil { + return nil, err + } + + column.Name = SanitizeValue(column.Name) + column.DataType = SanitizeValue(column.DataType) + + columns = append(columns, column) + } + + return columns, nil +} + +func (c *sqliteConnector) GetConstraints(tableName TableDetail) ([]ConstraintResult, error) { + rows, err := c.db.Query(` +select + pk."table" "pkTableName", + fk.name "pkTableName", + pk."from", + coalesce((select pk > 0 from pragma_table_info(fk.name) ti where ti.name = pk."from"), 0) "isPrimary", -- first pk has 1, second has 2 ... + coalesce((select count(*) > 1 from pragma_table_info(fk.name) ti where pk > 0), 0) "hasMultiplePK" + from sqlite_master fk + join pragma_foreign_key_list(fk.name) pk on pk."table" != fk.name + where fk.name = :tableName or pk."table" = :tableName + `, sql.Named("tableName", tableName.Name)) + if err != nil { + return nil, err + } + + var constraints []ConstraintResult + for rows.Next() { + constraint := ConstraintResult{ + PkSchema: tableName.Schema, + FkSchema: tableName.Schema, // sqlite only has one schema + } + err = rows.Scan( + &constraint.PkTable, + &constraint.FkTable, + &constraint.ColumnName, + &constraint.IsPrimary, + &constraint.HasMultiplePK, + ) + + if err != nil { + return nil, err + } + + constraints = append(constraints, constraint) + } + + return constraints, nil +} diff --git a/database/type.go b/database/type.go index 739bf7e..4958e47 100644 --- a/database/type.go +++ b/database/type.go @@ -6,6 +6,7 @@ const ( Postgres DbType = "pgx" MySql DbType = "mysql" MsSql DbType = "sqlserver" + Sqlite3 DbType = "sqlite" ) func (c DbType) String() string { diff --git a/go.mod b/go.mod index 436868b..b231c94 100644 --- a/go.mod +++ b/go.mod @@ -13,13 +13,16 @@ require ( github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.8.1 + modernc.org/sqlite v1.27.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect @@ -37,6 +40,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -44,9 +48,20 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect golang.org/x/crypto v0.7.0 // indirect - golang.org/x/sys v0.6.0 // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/sys v0.9.0 // indirect golang.org/x/term v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect + golang.org/x/tools v0.6.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + lukechampine.com/uint128 v1.2.0 // indirect + modernc.org/cc/v3 v3.40.0 // indirect + modernc.org/ccgo/v3 v3.16.13 // indirect + modernc.org/libc v1.29.0 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/opt v0.1.3 // indirect + modernc.org/strutil v1.1.3 // indirect + modernc.org/token v1.0.1 // indirect ) diff --git a/go.sum b/go.sum index 2410be5..8ad1e99 100644 --- a/go.sum +++ b/go.sum @@ -71,6 +71,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw= github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -147,8 +149,11 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -244,6 +249,7 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= @@ -260,6 +266,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -379,6 +387,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -435,6 +445,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -484,8 +495,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= @@ -560,6 +571,8 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -675,6 +688,30 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= +modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= +modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= +modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= +modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/libc v1.29.0 h1:tTFRFq69YKCF2QyGNuRUQxKBm1uZZLubf6Cjh/pVHXs= +modernc.org/libc v1.29.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8= +modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= +modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= +modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= +modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/test/db-table-setup.sql b/test/db-table-setup.sql index 5f09a38..72f78af 100644 --- a/test/db-table-setup.sql +++ b/test/db-table-setup.sql @@ -8,14 +8,16 @@ create table article create table article_detail ( id int not null primary key, - created_at timestamp not null + created_at timestamp not null, + foreign key (id) references article (id) ); create table article_comment ( id int not null primary key, article_id int not null, - comment varchar(255) not null + comment varchar(255) not null, + foreign key (article_id) references article (id) ); create table label @@ -27,37 +29,24 @@ create table label create table article_label ( article_id int not null, - label_id int not null + label_id int not null, + foreign key (article_id) references article (id), + foreign key (label_id) references label (id), + primary key (article_id, label_id) ); --- one-to-one relation -alter table article_detail - add constraint fk_article_detail_id foreign key (id) references article (id); - --- one-to-many relation -alter table article_comment - add constraint fk_article_comment_id foreign key (article_id) references article (id); - --- many-to-many relation -alter table article_label - add constraint fk_article_label_article_id foreign key (article_id) references article (id); -alter table article_label - add constraint fk_article_label_label_id foreign key (label_id) references label (id); -alter table article_label - add primary key (article_id, label_id); - -- Test case for https://github.com/KarnerTh/mermerd/issues/8 create table test_1_a ( - id int, - xid int, + id int not null, + xid int not null, primary key (id, xid) ); create table test_1_b ( - aid int, - bid int, + aid int not null, + bid int not null, primary key (aid, bid), foreign key (aid, bid) references test_1_a (id, xid) ); diff --git a/test/sqlite/sqlite-enum-setup.sql b/test/sqlite/sqlite-enum-setup.sql new file mode 100644 index 0000000..500819a --- /dev/null +++ b/test/sqlite/sqlite-enum-setup.sql @@ -0,0 +1,6 @@ +-- Test case for https://github.com/KarnerTh/mermerd/issues/15 +-- only stub, because sqlite does not support enums +create table test_2_enum( + fruit TEXT CHECK( fruit IN ('apple','banana') ) +); + diff --git a/test/sqlite/sqlite-multiple-databases.sql b/test/sqlite/sqlite-multiple-databases.sql new file mode 100644 index 0000000..1ce99da --- /dev/null +++ b/test/sqlite/sqlite-multiple-databases.sql @@ -0,0 +1,8 @@ +-- Test case for https://github.com/KarnerTh/mermerd/issues/23 +-- only stub, becuase sqlite does not support multiple databases +create table test_3_a +( + id int not null primary key, + title varchar(255) not null +); +