insertRow method
Insert a single row. Values must already be coerced to the column types. Returns the new row id (index into rows).
Implementation
int insertRow(List<Object?> values) {
if (values.length != columns.length) {
throw StateError(
'Expected ${columns.length} values, got ${values.length}');
}
// NOT NULL check
for (var i = 0; i < columns.length; i++) {
if (values[i] == null && columns[i].notNull) {
throw FormatException('Column "${columns[i].name}" cannot be NULL');
}
}
// UNIQUE / PRIMARY KEY check
for (var i = 0; i < columns.length; i++) {
final c = columns[i];
if ((c.unique || c.primaryKey) && values[i] != null) {
final cache = _uniqueCacheFor(i);
if (cache != null) {
if (cache.contains(values[i] as Object)) {
throw StateError(
'UNIQUE constraint failed: ${c.name}=${values[i]}');
}
} else {
for (final existing in rows) {
if (existing[i] == values[i]) {
throw StateError(
'UNIQUE constraint failed: ${c.name}=${values[i]}');
}
}
}
}
}
final rowId = rows.length;
rows.add(values);
// Record this row's values in the per-column unique caches we built.
for (final entry in _uniqueCaches.entries) {
final v = values[entry.key];
if (v != null) entry.value.add(v);
}
// Update indexes — expression / partial indexes are not maintained here
// (the executor refreshes them via rebuild), so skip them.
for (final entry in indexDefs.entries) {
final def = entry.value;
if (def.exprSql != null || def.whereSql != null) continue;
final key = _buildIndexKey(def, values);
if (key == null) continue;
final tree = indexes[entry.key]!;
final list = tree.putIfAbsent(key, () => <int>[]);
if (def.unique && list.isNotEmpty) {
rows.removeLast();
throw StateError('UNIQUE index ${entry.key} violation: $key');
}
list.add(rowId);
}
return rowId;
}