buildUpsertSql<T> static method

SqlStatement buildUpsertSql<T>(
  1. List<TetherModel<T>> models,
  2. String originalSupabaseTableName, {
  3. required Map<String, SupabaseTableInfo> tableSchemas,
})

Generates a structured UPSERT statement for a list of models.

Implementation

static SqlStatement buildUpsertSql<T>(
  List<TetherModel<T>> models,
  String originalSupabaseTableName, {
  required Map<String, SupabaseTableInfo> tableSchemas,
}) {
  if (models.isEmpty) {
    throw ArgumentError(
      'Cannot build UPSERT statement from empty model list.',
    );
  }

  final schemaKey = originalSupabaseTableName.contains('.')
      ? originalSupabaseTableName
      : 'public.$originalSupabaseTableName';

  final tableInfo = tableSchemas[schemaKey];
  if (tableInfo == null) {
    throw Exception(
      "Schema information for table '$schemaKey' not found. Cannot build upsert SQL.",
    );
  }

  final localTableName = tableInfo.localName;
  final pkInfos = tableInfo.primaryKeys;
  if (pkInfos.isEmpty) {
    throw ArgumentError(
      "Cannot build UPSERT: No primary keys defined for table '$schemaKey'. Conflict target is required.",
    );
  }
  final pkLocalNames = pkInfos.map((pk) => pk.localName).toList();
  final conflictTarget = pkLocalNames.join(', ');

  final firstModelMap = models.first.toSqlite();
  if (firstModelMap.isEmpty) {
    throw ArgumentError('Cannot build UPSERT: First model has no data.');
  }

  final columns = firstModelMap.keys.toList();
  final columnCount = columns.length;
  final valuePlaceholderGroup =
      '(${List.filled(columnCount, '?').join(', ')})';
  final allPlaceholders = List.filled(
    models.length,
    valuePlaceholderGroup,
  ).join(', ');
  final allArguments = <Object?>[];

  final updateColumns =
      columns.where((key) => !pkLocalNames.contains(key)).toList();
  final updateSetClauses =
      updateColumns.map((key) => '$key = excluded.$key').join(', ');

  for (final model in models) {
    final map = model.toSqlite();
    if (map.length != columnCount ||
        map.keys.join(',') != columns.join(',')) {
      throw ArgumentError(
        'Inconsistent model structure detected for bulk UPSERT.',
      );
    }
    allArguments.addAll(map.values);
  }

  return SqlStatement(
    operationType: SqlOperationType.upsert,
    tableName: localTableName,
    insertColumns: columns,
    insertValuesPlaceholders: allPlaceholders,
    insertArguments: allArguments,
    upsertConflictTarget: conflictTarget,
    upsertUpdateSetClauses:
        updateSetClauses.isNotEmpty ? updateSetClauses : null,
  );
}