floor icon indicating copy to clipboard operation
floor copied to clipboard

TypeConverter not generated for field.

Open BojanDolic opened this issue 3 years ago • 1 comments

I encountered problems while creating and using TypeConverter with the floor library.

The problem is as follows: I have an entity called Coil which contains a couple of fields.

@entity
class Coil {
  @primaryKey
  final int? id;

  String coilName;
  String coilDesc;
  CapacitorBank mmcBank;
  final String coilType;
  double resonantFrequency;

  Coil({
    this.id,
    this.coilName = "",
    this.coilDesc = "",
    this.coilType = "",
    this.resonantFrequency = 0.0,
    CapacitorBank? capBank,
  }) : mmcBank = capBank ?? CapacitorBank();
}

Note mmcBank and capBank

CapacitorBank class has the following fields:

/// This refers to MMC
class CapacitorBank {
  int seriesCapacitorCount;
  int parallelCapacitorCount;
  double capacitance;

  CapacitorBank({
    this.capacitance = 0.0,
    this.seriesCapacitorCount = 0,
    this.parallelCapacitorCount = 0,
  });

  factory CapacitorBank.fromDatabase(String databaseValue) {
    var valuesList = databaseValue.split(",");
    return CapacitorBank(
      capacitance: double.parse(
        valuesList.elementAt(0),
      ),
      seriesCapacitorCount: int.parse(
        valuesList.elementAt(1),
      ),
      parallelCapacitorCount: int.parse(
        valuesList.elementAt(2),
      ),
    );
  }

  String toDatabaseString() =>
      "$capacitance,$seriesCapacitorCount,$parallelCapacitorCount,";
}

CapacitorBank is a separate class and I need to save it inside the database. As I can see, floor does not support database relations fully so I had to come up with another solution to this problem. I came up with a solution to use type converters. I wanted to save variables from CapacitorBank like array inside mmcBank field inside the Coil table. Here is the type converter I use to do so:

class CapacitorBankConverter extends TypeConverter<CapacitorBank, String> {
  @override
  CapacitorBank decode(String databaseValue) {
    return CapacitorBank.fromDatabase(databaseValue);
  }

  @override
  String encode(CapacitorBank value) {
    return value.toDatabaseString();
  }
}

At first, everything worked fine while I was inserting some values inside database under mmcBank field but when I tried to retrieve this data, it was returning me only default values provided with the CapacitorBank constructor.

I looked at coil_database.g.dart file to investigate what is causing this and found out that type converters are not generated for queries.

This is my dao file:

@dao
abstract class CoilDao {
  @insert
  Future<void> insertCoil(Coil coil);

  @delete
  Future<void> deleteCoil(Coil coil);

  @update
  Future<void> updateCoil(Coil coil);

  @Query("SELECT * FROM Coil")
  Stream<List<Coil>> getCoils();
}

As you can see I have function getCoils() which returns everything from Coil table. When I looked for that function inside coil_database.g.dart it was generated like this:

@override
  Stream<List<Coil>> getCoils() {
    return _queryAdapter.queryListStream('SELECT * FROM Coil',
        mapper: (Map<String, Object?> row) => Coil(
            id: row['id'] as int?,
            coilName: row['coilName'] as String,
            coilDesc: row['coilDesc'] as String,
            coilType: row['coilType'] as String,
            resonantFrequency: row['resonantFrequency'] as double),
        queryableName: 'Coil',
        isView: false);
  }

Problem is that inside the function, the query does not return mmcBank field.

Line that is missing inside this file is:

capBank: _capacitorBankConverter.decode(row['mmcBank'] as String)

BojanDolic avatar Mar 09 '22 12:03 BojanDolic

@BojanDolic Yes, it's true, the floor_generator doesn't take into account constructor parameters that are not declared as a class field. Frankly, I more prefer to keep entity constructors simple. In your case, I would recommend adding a factory as shown below:

Coil(
    this.id,
    this.coilName,
    this.coilDesc,
    this.coilType,
    this.resonantFrequency,
    this.mmcBank,
  );

  factory Coil.capBank({
    int? id,
    String? coilName,
    String? coilDesc,
    String? coilType,
    double? resonantFrequency,
    CapacitorBank? capBank,
  }) {
    return Coil(
      id,
      coilName ?? '',
      coilDesc ?? '',
      coilType ?? '',
      resonantFrequency ?? 0.0,
      capBank ?? CapacitorBank(),
    );
  } 

It should solve the problem completely.

dkaera avatar Jul 27 '22 13:07 dkaera

Closed due inactivity

SEGVeenstra avatar Jul 04 '23 14:07 SEGVeenstra