createRow method
Future<R>
createRow(
- List<
Assignment> assignments(- F
- ExecutionOptions options = const ExecutionOptions(),
Inserts and returns a complete row.
Uses RETURNING when supported. Otherwise inserts and reads the primary key on one transaction; keys must be literal values or one generated identity.
Implementation
Future<R> createRow(
List<Assignment> Function(F) assignments, {
ExecutionOptions options = const ExecutionOptions(),
}) {
final mutation = insert(assignments);
if (database.capabilities.returning) {
return mutation.returning(definition.selectRow).single(options: options);
}
final keys = definition.schema.primaryKey;
final values = <String, ParameterNode>{};
final generated = <String>{};
for (final key in keys) {
final column = definition.schema.columns.firstWhere((c) => c.name == key);
final assignment = mutation.writeAssignments
.where((a) => a.field.definition.name == key)
.firstOrNull;
if (assignment?.assignedValue case final ParameterNode parameter) {
values[key] = parameter;
} else if (column.generated && assignment?.assignedValue == null) {
generated.add(key);
} else {
throw const OrmException(
'CAPABILITY.CREATE_KEY',
'Reading an inserted row without RETURNING requires literal primary keys or a generated identity.',
);
}
}
if (keys.isEmpty || generated.length > 1) {
throw const OrmException(
'CAPABILITY.CREATE_KEY',
'Reading an inserted row requires a primary key and at most one generated identity.',
);
}
Future<R> create(QueryContext tx) async {
try {
final bound = Mutation.internal(
tx,
mutation.queryFields,
mutation.queryState,
mutation.mutationKind,
mutation.writeAssignments,
fieldsFactory: mutation.fieldsFactory,
);
final result = await tx.executeCommand(
bound.compile(),
options: options,
changedTables: [definition.schema],
affectedOnly: true,
cascade: false,
);
if (generated.isNotEmpty) {
if (result.lastInsertId == null) {
throw const OrmException(
'DRIVER.IDENTITY',
'The driver did not return the generated identity.',
);
}
values[generated.single] = ParameterNode(result.lastInsertId);
}
SqlNode? predicate;
for (final key in keys) {
final equal = BinaryNode(
ColumnNode(queryState.source, key),
'=',
values[key]!,
);
predicate = predicate == null
? equal
: BinaryNode(predicate, 'AND', equal);
}
return await Query.internal(
tx,
queryFields,
queryState.copy(
predicate: Expr<bool?>.internal(
predicate!,
Codecs.boolean.nullable(),
),
),
definition.selectRow(queryFields),
).single(options: options);
} catch (_) {
tx.markFailed();
rethrow;
}
}
return database.inTransaction
? create(database)
: database.atomic(create, acquire: options.acquisition);
}