build method

  1. @override
Future<void> build(
  1. BuildStep buildStep
)

Generates the outputs for a given BuildStep.

Implementation

@override
Future<void> build(BuildStep buildStep) async {
  final inputId = buildStep.inputId;

  final connPool = await buildStep.fetchResource(_connPoolResource);

  final query = await buildStep.readAsString(inputId);

  ParseResult parseResult;

  final holder = await connPool.acquireHolder(Options.defaults());
  try {
    parseResult = await (await holder.getConnection()).parse(
        query: query,
        outputFormat: OutputFormat.binary,
        expectedCardinality: Cardinality.many,
        state: Session.defaults(),
        privilegedMode: false);
  } finally {
    await holder.release();
  }

  if (debug) {
    await buildStep.writeAsString(
        inputId.addExtension('.debug'), parseResult.toString());
  }

  final fileName = basenameWithoutExtension(buildStep.inputId.path);

  if (RegExp(r'^(\d|_)|[^0-9A-Za-z_]').hasMatch(fileName)) {
    throw ArgumentError(
        'only filenames containing A-Z, a-z, 0-9 and _ are supported',
        fileName);
  }

  final typeName = fileName[0].toUpperCase() + fileName.substring(1);

  final file = LibraryBuilder();

  final returnType =
      _walkCodec(parseResult.outCodec, file, typeName: typeName);

  file.body.add(declareConst('_query').assign(_queryString(query)).statement);

  file.body
      .add(declareFinal('_outCodec').assign(returnType.codecExpr).statement);

  if (parseResult.inCodec is! ObjectCodec &&
      parseResult.inCodec is! NullCodec) {
    throw EdgeDBError(
        'expected inCodec to be ObjectCodec or NullCodec, got ${parseResult.inCodec.runtimeType}');
  }
  final ObjectCodec? inCodec = parseResult.inCodec is ObjectCodec
      ? parseResult.inCodec as ObjectCodec
      : null;

  final namedArgs = inCodec != null && inCodec.fields[0].name != '0';

  Class? argsClass;
  if (inCodec != null) {
    final walkedCodec = _walkCodec(inCodec, file,
        typeName: 'Param', isArgsCodec: true, omitOutput: true);
    file.body.add(
        declareFinal('_inCodec').assign(walkedCodec.codecExpr).statement);
    argsClass = walkedCodec.classExpr;
  }

  file.body.add(Extension((builder) => builder
    ..name = '${typeName}Extension'
    ..on = Reference('Executor', 'package:edgedb/src/client.dart')
    ..methods.add(Method((builder) {
      builder
        ..name = fileName
        ..returns = TypeReference((ref) => ref
          ..symbol = 'Future'
          ..types.add(parseResult.cardinality == Cardinality.many
              ? TypeReference((ref) => ref
                ..symbol = 'List'
                ..types.add(returnType.typeRef))
              : TypeReference((ref) => ref
                ..symbol = returnType.typeRef.symbol
                ..url = returnType.typeRef.url
                ..isNullable =
                    parseResult.cardinality == Cardinality.atMostOne)));
      if (argsClass != null) {
        int i = 0;
        final params = argsClass.fields.map((field) => Parameter((builder) {
              builder
                ..name = namedArgs ? field.name : '\$${field.name}'
                ..type = field.type
                ..named = namedArgs
                ..required = namedArgs &&
                    inCodec.fields[i++].cardinality == Cardinality.one;
            }));
        namedArgs
            ? builder.optionalParameters.addAll(params)
            : builder.requiredParameters.addAll(params);
      }
      builder
        ..modifier = MethodModifier.async
        ..body =
            Reference('executeWithCodec', 'package:edgedb/src/client.dart')
                .call([
                  Reference('this'),
                  literalString(fileName),
                  Reference('_outCodec'),
                  inCodec != null
                      ? Reference('_inCodec')
                      : Reference('nullCodec',
                          'package:edgedb/src/codecs/codecs.dart'),
                  Reference('Cardinality',
                          'package:edgedb/src/primitives/types.dart')
                      .property(parseResult.cardinality.name),
                  Reference('_query'),
                  inCodec != null
                      ? (namedArgs
                          ? literalMap({
                              for (var field in inCodec.fields)
                                literalString(field.name):
                                    Reference(field.name)
                            }, Reference('String'), Reference('dynamic'))
                          : literalList([
                              for (var field in inCodec.fields)
                                Reference('\$${field.name}')
                            ], Reference('dynamic')))
                      : literalNull
                ], {}, [
                  returnType.typeRef
                ])
                .awaited
                .returned
                .statement;
    }))));

  final generatedCode = DartFormatter().format(file
      .build()
      .accept(DartEmitter.scoped(useNullSafetySyntax: true))
      .toString());

  await buildStep.writeAsString(
      inputId.addExtension('.dart'),
      '// AUTOGENERATED by \'edgeql_codegen\' builder\n'
      '// To re-generate use `dart run build_runner`\n\n'
      '$generatedCode');
}