coerceForColumn function

Object? coerceForColumn(
  1. Object? value,
  2. ColumnDef col, {
  3. bool strict = false,
})

Coerce a value to the column's type for storage/comparison purposes.

Implementation

Object? coerceForColumn(Object? value, ColumnDef col, {bool strict = false}) {
  if (value == null) {
    if (col.notNull) {
      throw FormatException('Column ${col.name} is NOT NULL');
    }
    return null;
  }
  if (strict) {
    final ok = switch (col.type) {
      // SQLite STRICT INTEGER accepts integer-valued REALs; we follow.
      DataType.integer =>
        value is int || (value is double && value == value.truncateToDouble()),
      DataType.real => value is double || value is int,
      DataType.text => value is String,
      DataType.boolean => value is bool,
      DataType.blob => value is List<int>,
      DataType.numeric =>
        value is num || (value is String && double.tryParse(value) != null),
      DataType.any => true,
    };
    if (!ok) {
      throw FormatException(
        'STRICT: column ${col.name} expects ${col.type.name}, got ${value.runtimeType}',
      );
    }
    // Even in STRICT we still normalize 1.0 -> 1 for INTEGER columns and
    // run NUMERIC affinity, otherwise leave the value alone.
    if (col.type == DataType.integer && value is double) {
      return value.toInt();
    }
    if (col.type == DataType.numeric) {
      return coerce(value, DataType.numeric);
    }
    return value;
  }
  // SQLite affinity semantics in non-strict mode:
  //   * BLOB affinity never converts \u2014 every value is stored verbatim.
  //   * INTEGER / REAL / NUMERIC affinity tries to convert; if the value
  //     cannot be losslessly converted (e.g. INTEGER column receiving the
  //     string 'abc') the original value is stored unchanged, matching
  //     SQLite's "no-op when conversion fails" rule.
  //   * TEXT and BOOLEAN affinity continue to delegate to [coerce], which
  //     already performs the standard conversions.
  if (col.type == DataType.blob) return value;
  if (col.type == DataType.integer ||
      col.type == DataType.real ||
      col.type == DataType.numeric) {
    try {
      return coerce(value, col.type);
    } on FormatException {
      return value;
    }
  }
  return coerce(value, col.type);
}