buildValuesClass method

Class buildValuesClass(
  1. OrmBuildContext ctx
)

Generate

Implementation

Class buildValuesClass(OrmBuildContext ctx) {
  return Class((clazz) {
    var rc = ctx.buildContext.modelClassNameRecase;

    log.info('Generating ${rc.pascalCase}QueryValues');

    clazz
      ..name = '${rc.pascalCase}QueryValues'
      ..extend = refer('MapQueryValues');

    // Override casts so that we can cast Lists
    clazz.methods.add(Method((b) {
      b
        ..name = 'casts'
        ..returns = refer('Map<String, String>')
        ..annotations.add(refer('override'))
        ..type = MethodType.getter
        ..body = Block((b) {
          var args = <String?, Expression>{};

          for (var field in ctx.effectiveFields) {
            var fType = field.type;
            var name = ctx.buildContext.resolveFieldName(field.name);
            var type = ctx.columns[field.name]?.type;
            if (type == null) continue;
            if (const TypeChecker.fromRuntime(List)
                .isAssignableFromType(fType)) {
              args[name] = literalString(type.name);
            }

            /* else if (floatTypes.contains(type)) {
              args[name] = literalString(type.name);
            } */
          }

          b.addExpression(literalMap(args).returned);
        });
    }));

    // Each field generates a getter and setter
    for (var field in ctx.effectiveNormalFields) {
      var fType = field.type;
      var name = ctx.buildContext.resolveFieldName(field.name);
      var type = convertTypeReference(field.type);

      clazz.methods.add(Method((b) {
        var value = refer('values').index(literalString(name!));

        if (fType is InterfaceType && fType.element is EnumElement) {
          value = _deserializeEnumExpression(field, value);
        } else if (const TypeChecker.fromRuntime(List)
            .isAssignableFromType(fType)) {
          value = refer('json')
              .property('decode')
              .call([value.asA(refer('String'))])
              .property('cast')
              .call([]);
        } else if (floatTypes.contains(ctx.columns[field.name]?.type)) {
          // Skip using casts on double
          value = value
              .asA(refer('double?'))
              .ifNullThen(CodeExpression(Code('0.0')));
          //value = refer('double')
          //    .property('tryParse')
          //    .call([value.asA(refer('String'))]).ifNullThen(
          //        CodeExpression(Code('0.0')));
        } else {
          value = value.asA(type);
        }

        b
          ..name = field.name
          ..type = MethodType.getter
          ..returns = type
          ..body = Block((b) => b.addExpression(value.returned));
      }));

      clazz.methods.add(Method((b) {
        Expression value = refer('value');

        if (fType is InterfaceType && fType.element is EnumElement) {
          value = _serializeEnumExpression(field, value);
        } else if (const TypeChecker.fromRuntime(List)
            .isAssignableFromType(fType)) {
          value = refer('json').property('encode').call([value]);
        }

        /* else if (floatTypes.contains(ctx.columns[field.name]?.type)) {
          value = value.property('toString').call([]);
        } */

        b
          ..name = field.name
          ..type = MethodType.setter
          ..requiredParameters.add(Parameter((b) => b
            ..name = 'value'
            ..type = type))
          ..body =
              refer('values').index(literalString(name!)).assign(value).code;
      }));
    }

    // Add an copyFrom(model)
    clazz.methods.add(Method((b) {
      b
        ..name = 'copyFrom'
        ..returns = refer('void')
        ..requiredParameters.add(Parameter((b) => b
          ..name = 'model'
          ..type = ctx.buildContext.modelClassType))
        ..body = Block((b) {
          for (var field in ctx.effectiveNormalFields) {
            if (isSpecialId(ctx, field) || field is RelationFieldImpl) {
              continue;
            }
            b.addExpression(refer(field.name)
                .assign(refer('model').property(field.name)));
          }

          for (var field in ctx.effectiveNormalFields) {
            if (field is RelationFieldImpl) {
              var original = field.originalFieldName;
              var prop = refer('model').property(original);
              // Add only if present
              var target = refer('values').index(literalString(
                  ctx.buildContext.resolveFieldName(field.name)!));

              var foreign = field.relationship.throughContext ??
                  field.relationship.foreign;
              var foreignField = field.relationship.findForeignField(ctx);

              // Added null safety check
              var parsedId = prop.property(foreignField.name);

              //log.fine('Foreign field => ${foreignField.name}');
              if (foreignField.type.nullabilitySuffix ==
                  NullabilitySuffix.question) {
                parsedId = prop.nullSafeProperty(foreignField.name);
              }

              if (foreign != null) {
                if (isSpecialId(foreign, field)) {
                  parsedId =
                      (refer('int').property('tryParse').call([parsedId]));
                }
              }
              var cond = prop.notEqualTo(literalNull);
              var condStr =
                  cond.accept(DartEmitter(useNullSafetySyntax: true));
              var blkStr =
                  Block((b) => b.addExpression(target.assign(parsedId)))
                      .accept(DartEmitter(useNullSafetySyntax: true));
              var ifStmt = Code('if ($condStr) { $blkStr }');
              b.statements.add(ifStmt);
            }
          }
        });
    }));
  });
}