@@ -125,6 +125,7 @@ final class PluginMetadataRegistry: @unchecked Sendable {
125125 private let lock = NSLock ( )
126126 private var snapshots : [ String : PluginMetadataSnapshot ] = [ : ]
127127 private var schemeIndex : [ String : String ] = [ : ]
128+ private var reverseTypeIndex : [ String : String ] = [ : ]
128129
129130 private init ( ) {
130131 registerBuiltInDefaults ( )
@@ -505,6 +506,11 @@ final class PluginMetadataRegistry: @unchecked Sendable {
505506 schemeIndex [ scheme. lowercased ( ) ] = entry. typeId
506507 }
507508 }
509+
510+ // Built-in type aliases: multi-type plugins where an alias maps to a primary plugin type ID
511+ reverseTypeIndex [ " MariaDB " ] = " MySQL "
512+ reverseTypeIndex [ " Redshift " ] = " PostgreSQL "
513+ reverseTypeIndex [ " ScyllaDB " ] = " Cassandra "
508514 }
509515
510516 func register( snapshot: PluginMetadataSnapshot , forTypeId typeId: String ) {
@@ -543,6 +549,107 @@ final class PluginMetadataRegistry: @unchecked Sendable {
543549 return DatabaseType ( rawValue: typeId)
544550 }
545551
552+ // MARK: - Dynamic Type Registration
553+
554+ /// Registers an alias type ID that maps to a primary type ID.
555+ /// Used for multi-type plugins (e.g., MariaDB → MySQL, Redshift → PostgreSQL).
556+ func registerTypeAlias( _ aliasTypeId: String , primaryTypeId: String ) {
557+ lock. lock ( )
558+ defer { lock. unlock ( ) }
559+ reverseTypeIndex [ aliasTypeId] = primaryTypeId
560+ }
561+
562+ /// Returns all registered type IDs (sorted for deterministic UI ordering).
563+ func allRegisteredTypeIds( ) -> [ String ] {
564+ lock. lock ( )
565+ defer { lock. unlock ( ) }
566+ return Array ( snapshots. keys) . sorted ( )
567+ }
568+
569+ /// Resolves a database type raw value to its plugin type ID for driver lookup.
570+ /// For multi-type plugins (MySQL serves MariaDB), maps the alias to the primary.
571+ /// Does NOT remap for snapshot lookups — use snapshot(forTypeId:) directly.
572+ func pluginTypeId( for rawValue: String ) -> String {
573+ lock. lock ( )
574+ defer { lock. unlock ( ) }
575+ return reverseTypeIndex [ rawValue] ?? rawValue
576+ }
577+
578+ /// Checks if a type ID is registered (has a snapshot).
579+ func hasType( _ typeId: String ) -> Bool {
580+ lock. lock ( )
581+ defer { lock. unlock ( ) }
582+ return snapshots [ typeId] != nil
583+ }
584+
585+ // MARK: - Snapshot Builder
586+
587+ /// Builds a PluginMetadataSnapshot from a DriverPlugin's protocol properties.
588+ /// Used by PluginManager to self-register plugins at load time.
589+ func buildMetadataSnapshot(
590+ from driverType: any DriverPlugin . Type ,
591+ isDownloadable: Bool = false ,
592+ parameterStyle: ParameterStyle = . questionMark
593+ ) -> PluginMetadataSnapshot {
594+ let schemes = driverType. urlSchemes
595+ let primaryScheme = schemes. first ?? driverType. databaseTypeId. lowercased ( )
596+
597+ return PluginMetadataSnapshot (
598+ displayName: driverType. databaseDisplayName,
599+ iconName: driverType. iconName,
600+ defaultPort: driverType. defaultPort,
601+ requiresAuthentication: driverType. requiresAuthentication,
602+ supportsForeignKeys: driverType. supportsForeignKeys,
603+ supportsSchemaEditing: driverType. supportsSchemaEditing,
604+ isDownloadable: isDownloadable,
605+ primaryUrlScheme: primaryScheme,
606+ parameterStyle: parameterStyle,
607+ navigationModel: driverType. navigationModel,
608+ explainVariants: driverType. explainVariants,
609+ pathFieldRole: driverType. pathFieldRole,
610+ supportsHealthMonitor: driverType. supportsHealthMonitor,
611+ urlSchemes: schemes,
612+ postConnectActions: driverType. postConnectActions,
613+ brandColorHex: driverType. brandColorHex,
614+ queryLanguageName: driverType. queryLanguageName,
615+ editorLanguage: driverType. editorLanguage,
616+ connectionMode: driverType. connectionMode,
617+ supportsDatabaseSwitching: driverType. supportsDatabaseSwitching,
618+ capabilities: PluginMetadataSnapshot . CapabilityFlags (
619+ supportsSchemaSwitching: driverType. supportsSchemaSwitching,
620+ supportsImport: driverType. supportsImport,
621+ supportsExport: driverType. supportsExport,
622+ supportsSSH: driverType. supportsSSH,
623+ supportsSSL: driverType. supportsSSL,
624+ supportsCascadeDrop: driverType. supportsCascadeDrop,
625+ supportsForeignKeyDisable: driverType. supportsForeignKeyDisable,
626+ supportsReadOnlyMode: driverType. supportsReadOnlyMode,
627+ supportsQueryProgress: driverType. supportsQueryProgress,
628+ requiresReconnectForDatabaseSwitch: driverType. requiresReconnectForDatabaseSwitch
629+ ) ,
630+ schema: PluginMetadataSnapshot . SchemaInfo (
631+ defaultSchemaName: driverType. defaultSchemaName,
632+ defaultGroupName: driverType. defaultGroupName,
633+ tableEntityName: driverType. tableEntityName,
634+ defaultPrimaryKeyColumn: driverType. defaultPrimaryKeyColumn,
635+ immutableColumns: driverType. immutableColumns,
636+ systemDatabaseNames: driverType. systemDatabaseNames,
637+ systemSchemaNames: driverType. systemSchemaNames,
638+ fileExtensions: driverType. fileExtensions,
639+ databaseGroupingStrategy: driverType. databaseGroupingStrategy,
640+ structureColumnFields: driverType. structureColumnFields
641+ ) ,
642+ editor: PluginMetadataSnapshot . EditorConfig (
643+ sqlDialect: driverType. sqlDialect,
644+ statementCompletions: driverType. statementCompletions,
645+ columnTypesByCategory: driverType. columnTypesByCategory
646+ ) ,
647+ connection: PluginMetadataSnapshot . ConnectionConfig (
648+ additionalConnectionFields: driverType. additionalConnectionFields
649+ )
650+ )
651+ }
652+
546653 func allFileExtensions( ) -> [ String : String ] {
547654 lock. lock ( )
548655 defer { lock. unlock ( ) }
0 commit comments