setUpOrmed function

OrmedTestConfig setUpOrmed({
  1. required DataSource dataSource,
  2. Future<void> runMigrations(
    1. DataSource
    )?,
  3. List<Migration>? migrations,
  4. List<MigrationDescriptor>? migrationDescriptors,
  5. List<DatabaseSeeder Function(OrmConnection)>? seeders,
  6. DatabaseIsolationStrategy strategy = DatabaseIsolationStrategy.migrateWithTransactions,
  7. bool parallel = false,
  8. DriverAdapter adapterFactory(
    1. String testDbName
    )?,
  9. bool migrateBaseDatabase = true,
})

Configures Ormed for testing.

Call this once in your test file's main() before defining tests. Returns an OrmedTestConfig that can be passed to ormedGroup to ensure the correct database manager is used.

Future<void> main() async {
  final harness = await createTestHarness();
  final config = setUpOrmed(dataSource: harness.dataSource, ...);

  tearDownAll(() => harness.dispose());

  runAllDriverTests(config); // Pass config to tests
}

migrateBaseDatabase defaults to true and runs the configured migrations on the manager's base data source so the connections registered with ConnectionManager are usable outside of an ormedGroup.

Implementation

OrmedTestConfig setUpOrmed({
  required DataSource dataSource,
  Future<void> Function(DataSource)? runMigrations,
  List<Migration>? migrations,
  List<MigrationDescriptor>? migrationDescriptors,
  List<DatabaseSeeder Function(OrmConnection)>? seeders,
  DatabaseIsolationStrategy strategy =
      DatabaseIsolationStrategy.migrateWithTransactions,
  bool parallel = false, // Deprecated, ignored
  DriverAdapter Function(String testDbName)? adapterFactory,
  bool migrateBaseDatabase = true,

  //TODO
  //ModelRegistry reigstry
  //DriverAdapter adapter // remove datasource and create data source inside setupOrmed when needed dont accept user datasource
}) {
  final dbName = dataSource.options.name;

  // Generate a unique config key for this setUpOrmed call.
  // This ensures that even if multiple test files use the same DataSource name,
  // they get separate managers (unless they explicitly share one).
  final configKey = _generateConfigKey(dbName);

  // Create the configuration hash for collision detection
  final configHash = sha256
      .string(
        '$dbName:${migrations?.length ?? 0}:${migrationDescriptors?.length ?? 0}:$strategy',
      )
      .toString()
      .substring(0, 16);

  // Check for existing manager with same DataSource name.
  // For migrateWithTransactions, we WANT to share the provisioned database
  // across multiple test files (like Laravel's RefreshDatabase).
  // But each test file gets its own config key to track its lifecycle.
  late final TestDatabaseManager resolvedManager;
  var hasResolvedManager = false;

  // Look for an existing manager that can be shared
  for (final entry in _managers.entries) {
    final existingManager = entry.value;
    if (existingManager.baseDataSource.options.name == dbName) {
      // Found an existing manager for the same database
      // Verify configurations match (same migrations, etc.)
      if (strategy == DatabaseIsolationStrategy.migrateWithTransactions) {
        // For migrateWithTransactions, we share the manager
        resolvedManager = existingManager;
        // Store under our config key as well
        _managers[configKey] = resolvedManager;
        hasResolvedManager = true;
        break;
      } else {
        // For other strategies, we need separate databases per test file
        // So create a new manager
      }
    }
  }

  // Create new manager if we didn't find one to share
  if (!hasResolvedManager) {
    final baseSchema = _resolveBaseSchemaName(
      dataSource: dataSource,
      configKey: configKey,
      migrateBaseDatabase: migrateBaseDatabase,
    );
    resolvedManager = TestDatabaseManager(
      baseDataSource: dataSource,
      runMigrations: runMigrations,
      migrations: migrations,
      migrationDescriptors: migrationDescriptors,
      seeders: seeders,
      strategy: strategy,
      adapterFactory: adapterFactory,
      baseSchema: baseSchema,
    );
    _managers[configKey] = resolvedManager;
  }

  // Create the config object
  final config = OrmedTestConfig._(
    configKey: configKey,
    dataSourceName: dbName,
    configHash: configHash,
  );

  // Track as the last registered config for legacy fallback
  _lastRegisteredConfig = config;

  // Push to config stack
  _configStack.add(config);

  setUpAll(() async {
    await resolvedManager.initialize();
  });

  if (migrateBaseDatabase) {
    setUpAll(() async {
      await resolvedManager.migrate(resolvedManager.baseDataSource);
    });
  }

  tearDownAll(() async {
    // Remove from config stack
    _configStack.remove(config);
    if (_lastRegisteredConfig == config) {
      _lastRegisteredConfig = _configStack.isNotEmpty
          ? _configStack.last
          : null;
    }

    await resolvedManager.cleanup();
    _managers.remove(configKey);
  });

  return config;
}