prepareInsertBatchedStatements method

List<Statement> prepareInsertBatchedStatements(
  1. String baseSql,
  2. List<String> columns,
  3. List<Map<String, Object?>> records,
  4. int maxParameters, [
  5. String suffixSql = '',
])

Prepare multiple batched insert statements for an array of records.

Since SQLite only supports a limited amount of positional ? parameters, we generate multiple insert statements with each one being filled as much as possible from the given data. All statements are derived from same baseSql - the positional parameters will be appended to this string.

@param baseSql base SQL string to which inserts should be appended @param columns columns that describe records @param records records to be inserted @param maxParameters max parameters this SQLite can accept - determines batching factor @param suffixSql optional SQL string to append to each insert statement @returns array of statements ready to be executed by the adapter

Implementation

List<Statement> prepareInsertBatchedStatements(
  String baseSql,
  List<String> columns,
  List<Map<String, Object?>> records,
  int maxParameters, [
  String suffixSql = '',
]) {
  final stmts = <Statement>[];
  final columnCount = columns.length;
  final recordCount = records.length;

  // Amount of rows we can insert at once
  final batchMaxSize = (maxParameters / columnCount).floor();

  // keep a temporary join array for joining strings, to avoid
  // the overhead of generating a new array every time
  final tempColJoinArray =
      List<String>.filled(columnCount, '', growable: false);

  int processed = 0;
  int prevInsertCount = -1;
  String insertPattern = '';

  while (processed < recordCount) {
    final currentInsertCount = min(recordCount - processed, batchMaxSize);

    // cache insert pattern as it is going to be the same for every batch
    // of `batchMaxSize` - ideally we can externalize this cache since for a
    // given adapter this is _always_ going to be the same
    if (currentInsertCount != prevInsertCount) {
      insertPattern = List.generate(currentInsertCount, (recordIdx) {
        for (int i = 0; i < columnCount; i++) {
          tempColJoinArray[i] = makePositionalParam(
            recordIdx * columnCount + i + 1,
          );
        }
        return ' (${tempColJoinArray.join(', ')})';
      }).join(',');
    }

    String sql = baseSql + insertPattern;

    if (suffixSql != '') {
      sql += ' $suffixSql';
    }

    final List<Object?> args = [];
    for (int i = 0; i < currentInsertCount; i++) {
      for (int j = 0; j < columnCount; j++) {
        args.add(records[processed + i][columns[j]]);
      }
    }

    processed += currentInsertCount;
    prevInsertCount = currentInsertCount;
    stmts.add(Statement(sql, args));
  }
  return stmts;
}