Moor: Suggestion: Support for enums

Created on 7 Apr 2020  路  8Comments  路  Source: simolus3/moor

.moor:

CREATE TABLE Foo(
    "columnName" ENUM(MyEnum) NOT NULL PRIMARY KEY
)

.dart:

class Foo extends Table {
  EnumColumn get columnName => enum<MyEnum>()();
}

This would generate a converter class and adjust the model to use the created converter:

class MyEnumConverter extends TypeConverter<MyEnum, int> {
  @override
  MyEnum mapToDart(int fromDb) {
    return fromDb == null ? null : MyEnum.values[fromDb];
  }

  @override
  int mapToSql(MyEnum value) {
    return value.index;
  }
}
enhancement generator

All 8 comments

I like the idea :+1: Enums are a common usage of type converters, so it makes sense to simplify this.
I've implemented the Dart part of this today (had to use intEnum instead of enum because it's a keyword), and I'll look at the integration for moor files tomorrow.

I like the idea 馃憤 Enums are a common usage of type converters, so it makes sense to simplify this.
I've implemented the Dart part of this today (had to use intEnum instead of enum because it's a keyword), and I'll look at the integration for moor files tomorrow.

My current implementation:

table.moor:

import 'enum_converters.dart';

CREATE TABLE Table(
    "enumColumn" INT MAPPED BY `EnumConverters.testEnum` NOT NULL,
...

test_enum.dart:

enum TestEnum {
  value0,
  value1,
  value2,
  ...
}

enum_converters.dart:

import 'enum_converter.dart';
import 'test_enum.dart';

class EnumConverters {
  static const testEnum = EnumConverter(TestEnum.values);
}

enum_converter.dart:

import 'package:flutter/foundation.dart';
import 'package:moor/moor.dart';

@immutable
class EnumConverter<T> extends TypeConverter<T, int> {
  final List<T> values;

  const EnumConverter(this.values);

  @override
  T mapToDart(int fromDb) {
    return fromDb == null ? null : values[fromDb];
  }

  @override
  int mapToSql(T value) {
    return value == null ? null : values.indexOf(value);
  }
}

Supported in the upcoming moor 3.1 version with this syntax:

CREATE TABLE Table(
    "enumColumn" ENUM(TestEnum),

enum_converter.dart:

import 'package:flutter/foundation.dart';
import 'package:moor/moor.dart';

@immutable
class EnumConverter<T> extends TypeConverter<T, int> {
  final List<T> values;

  const EnumConverter(this.values);

  @override
  T mapToDart(int fromDb) {
    return fromDb == null ? null : values[fromDb];
  }

  @override
  int mapToSql(T value) {
    return value == null ? null : values.indexOf(value);
  }
}

@JCKodel I'm sorry but this is a terrible and downright dangerous way to convert enums if you value data-integrity.

Should yourself/any other unaware team members modify the values at all inside TestEnum and it isn't sequential (add a value anywhere except the end, remove any value), then you've lost accurate mapping to/from the database as this mapping relies on the enum values' position within the TestEnum.

@jamie1192 It depends. If a backend already have int values hardcoded to meanings, this works fine (and it's my use case).

@JCKodel

enum TestEnum {
  value0,
  value1,
  value2,
}

final converter = EnumConverter<TestEnum>(TestEnum.values);

print(converter.mapToSql(TestEnum.value0)); // prints 0
print(converter.mapToSql(TestEnum.value2)); // prints 2

Now lets add another value to TestEnum-

enum TestEnum {
  someNewValue,
  value0,
  value1,
  value2,
}


final converter = EnumConverter<TestEnum>(TestEnum.values);

print(converter.mapToSql(TestEnum.someNewValue)); // prints 0
print(converter.mapToSql(TestEnum.value0)); // prints 1, was 0 before
print(converter.mapToSql(TestEnum.value2)); // prints 3, was 2 before

Your hardcoded int values on your back-end now no longer match the enums in your front-end if you/someone else unknowingly adds a new value to TestEnum.

This is just asking for trouble.

@jamie1192 I don't care!

and yet you claim to "... meet any need for software development with quality and performance." on your website.

How ironic.

Was this page helpful?
0 / 5 - 0 ratings