createRow method

Future<R> createRow(
  1. List<Assignment> assignments(
    1. F
    ), {
  2. 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);
}