chore: disable runtime mysql schema creation

This commit is contained in:
richjohnrambo
2026-09-13 13:56:24 +08:00
parent eefc3c2fbd
commit ccbd385d2f
5 changed files with 547 additions and 96 deletions
-84
View File
@@ -290,50 +290,6 @@ func (a *adapter) Open(jsonconfig json.RawMessage) error {
return errors.New("mysql adapter failed to open tenant registry database: " + err.Error())
}
}
if a.registryDB != nil || !databaseMissing {
controlDB := a.db
if a.registryDB != nil {
controlDB = a.registryDB
}
if err = ensureIMRegistrationInviteControlTables(controlDB); err != nil {
return errors.New("mysql adapter failed to ensure registration invite control schema: " + err.Error())
}
if err = ensureIMTenantEntryControlTables(controlDB); err != nil {
return errors.New("mysql adapter failed to ensure tenant entry control schema: " + err.Error())
}
}
if !databaseMissing {
if err = ensureIMGroupBusinessTables(a.db); err != nil {
return errors.New("mysql adapter failed to ensure group business schema: " + err.Error())
}
if err = ensureIMHTTPInfrastructureTables(a.db); err != nil {
return errors.New("mysql adapter failed to ensure HTTP infrastructure schema: " + err.Error())
}
if err = ensureIMAdminGovernanceTables(a.db); err != nil {
return errors.New("mysql adapter failed to ensure admin governance schema: " + err.Error())
}
if err = ensureIMFileReviewTables(a.db); err != nil {
return errors.New("mysql adapter failed to ensure file review schema: " + err.Error())
}
if err = ensureIMOrganizationVisibilityTables(a.db); err != nil {
return errors.New("mysql adapter failed to ensure organization visibility schema: " + err.Error())
}
if err = ensureIMAttendanceTables(a.db); err != nil {
return errors.New("mysql adapter failed to ensure attendance schema: " + err.Error())
}
if err = ensureIMMeetingNotesTables(a.db); err != nil {
return errors.New("mysql adapter failed to ensure meeting notes schema: " + err.Error())
}
if err = ensureSnowflakePrimaryKeys(a.db); err != nil {
return errors.New("mysql adapter failed to ensure snowflake primary keys: " + err.Error())
}
if err = ensureUserIdentitySchema(a.db); err != nil {
return errors.New("mysql adapter failed to ensure user identity schema: " + err.Error())
}
if err = ensureIMRegistrationInviteUseTable(a.db); err != nil {
return errors.New("mysql adapter failed to ensure registration invite usage schema: " + err.Error())
}
}
}
return err
}
@@ -544,46 +500,6 @@ func (a *adapter) TenantAdapterFor(tenantID t.TenantID) (dbadapter.TenantBusines
db.Close()
return nil, nil, err
}
if err = ensureIMGroupBusinessTables(db); err != nil {
db.Close()
return nil, nil, err
}
if err = ensureIMHTTPInfrastructureTables(db); err != nil {
db.Close()
return nil, nil, err
}
if err = ensureIMAdminGovernanceTables(db); err != nil {
db.Close()
return nil, nil, err
}
if err = ensureIMFileReviewTables(db); err != nil {
db.Close()
return nil, nil, err
}
if err = ensureIMOrganizationVisibilityTables(db); err != nil {
db.Close()
return nil, nil, err
}
if err = ensureIMAttendanceTables(db); err != nil {
db.Close()
return nil, nil, err
}
if err = ensureIMMeetingNotesTables(db); err != nil {
db.Close()
return nil, nil, err
}
if err = ensureSnowflakePrimaryKeys(db); err != nil {
db.Close()
return nil, nil, err
}
if err = ensureUserIdentitySchema(db); err != nil {
db.Close()
return nil, nil, err
}
if err = ensureIMRegistrationInviteUseTable(db); err != nil {
db.Close()
return nil, nil, err
}
registryDB := a.registryDB
if registryDB == nil {
registryDB = a.db
-10
View File
@@ -157,16 +157,6 @@ func ensureIMGroupBusinessTables(exec sqlExecutor) error {
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_idempotency_request(user_id, method, route, idempotency_key),
INDEX idx_im_group_idempotency_created(created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`CREATE TABLE IF NOT EXISTS im_group_events_outbox (
id BIGINT NOT NULL AUTO_INCREMENT, event_id VARCHAR(64) NOT NULL, topic VARCHAR(32) NOT NULL,
actor_user_id BIGINT NOT NULL DEFAULT 0, event_type VARCHAR(64) NOT NULL, payload JSON,
status VARCHAR(16) NOT NULL DEFAULT 'pending', attempts INT NOT NULL DEFAULT 0,
next_retry_at DATETIME(3), delivered_at DATETIME(3),
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_events_outbox_event(event_id),
INDEX idx_im_group_events_outbox_pending(status, next_retry_at, id), INDEX idx_im_group_events_outbox_topic(topic, id DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`UPDATE im_topics SET public=JSON_SET(public, '$.fn', JSON_UNQUOTE(JSON_EXTRACT(public, '$.name')))
WHERE name LIKE 'grp%' AND JSON_VALID(public)
AND COALESCE(JSON_UNQUOTE(JSON_EXTRACT(public, '$.fn')), '') = ''
+5 -2
View File
@@ -22,8 +22,8 @@ func TestEnsureIMGroupBusinessTablesUsesSelectedTenantDatabase(t *testing.T) {
if err := ensureIMGroupBusinessTables(exec); err != nil {
t.Fatal(err)
}
if len(exec.statements) != 14 {
t.Fatalf("executed %d group schema statements, want 14", len(exec.statements))
if len(exec.statements) != 13 {
t.Fatalf("executed %d group schema statements, want 13", len(exec.statements))
}
for _, statement := range exec.statements {
if strings.Contains(strings.ToLower(statement), "tinode.") || strings.Contains(strings.ToLower(statement), "create database") {
@@ -31,6 +31,9 @@ func TestEnsureIMGroupBusinessTablesUsesSelectedTenantDatabase(t *testing.T) {
}
}
joined := strings.ToLower(strings.Join(exec.statements, "\n"))
if strings.Contains(joined, "im_group_events_outbox") {
t.Fatal("group event outbox table must not be created")
}
for _, expected := range []string{
"primary key(id), unique index uk_im_group_settings_topic(topic)",
"primary key(id), unique index uk_im_group_announcement_reads_announcement_user(announcement_id, user_id)",
@@ -55,6 +55,66 @@ func TestMessageSearchDoesNotClearScannedHead(t *testing.T) {
}
}
func TestRuntimeOpenDoesNotAutoCreateOrMigrateTables(t *testing.T) {
source, err := os.ReadFile("adapter.go")
if err != nil {
t.Fatal(err)
}
body := string(source)
for _, tc := range []struct {
name string
function string
end string
}{
{
name: "Open",
function: "func (a *adapter) Open",
end: "\nfunc (a *adapter) Close",
},
{
name: "TenantAdapterFor",
function: "func (a *adapter) TenantAdapterFor",
end: "\nfunc (a *adapter) tenantByID",
},
} {
fn := sourceBetween(t, body, tc.function, tc.end)
for _, forbidden := range []string{
"ensureIMRegistrationInviteControlTables",
"ensureIMTenantEntryControlTables",
"ensureIMGroupBusinessTables",
"ensureIMHTTPInfrastructureTables",
"ensureIMAdminGovernanceTables",
"ensureIMFileReviewTables",
"ensureIMOrganizationVisibilityTables",
"ensureIMAttendanceTables",
"ensureIMMeetingNotesTables",
"ensureSnowflakePrimaryKeys",
"ensureUserIdentitySchema",
"ensureIMRegistrationInviteUseTable",
"CREATE DATABASE",
"CREATE TABLE",
"ALTER TABLE",
} {
if strings.Contains(fn, forbidden) {
t.Fatalf("%s must not auto-create or auto-migrate schema; found %q", tc.name, forbidden)
}
}
}
}
func sourceBetween(t *testing.T, source, startMarker, endMarker string) string {
t.Helper()
start := strings.Index(source, startMarker)
if start < 0 {
t.Fatalf("missing source marker %q", startMarker)
}
end := strings.Index(source[start:], endMarker)
if end < 0 {
t.Fatalf("missing source marker %q after %q", endMarker, startMarker)
}
return source[start : start+end]
}
func TestSearchPaginationCursorUsesLastReturnedRow(t *testing.T) {
source, err := os.ReadFile("tenant_adapter.go")
if err != nil {