build method
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');
}