Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom types #93

Closed
neigaard opened this issue Feb 18, 2020 · 10 comments
Closed

Custom types #93

neigaard opened this issue Feb 18, 2020 · 10 comments
Labels
documentation Improvements or additions to documentation
Milestone

Comments

@neigaard
Copy link

neigaard commented Feb 18, 2020

I have just started using ObjectBox for Flutter and I am missing the Custom Types very very much. Is this a planned feature for the Dart/Flutter version also, and do you have any idea when (maybe you are already working on it)?

Thank you
Søren

@greenrobot
Copy link
Member

We are not aware of active work on this (by the community).

For the time being, maybe a workaround might work? Would it be possible to use smart getters/setters that internally do the conversion, e.g. to a string that gets persisted?

@greenrobot greenrobot added enhancement New feature or request help wanted Looking for contributors (ideas, comments, code, etc) labels Feb 18, 2020
@neigaard
Copy link
Author

Yes, I created fake/shadow getter and setters for those types that simply read/write from/to the real types, and this work just fine. Thank you for the tip, although I have those extra getters/setters it does work and is not to bad I think.

@DPalagi
Copy link

DPalagi commented Apr 8, 2020

Hi !
I'm very new to objectbox, but I want to store an enum property in my Entity ; @neigaard I'm very interested by the code you've put to make this workaround please.

I think that it should be interesting for other new guys like me to have a few examples for questions like this.

Thank you 😊

@neigaard
Copy link
Author

neigaard commented Apr 8, 2020

Sure, take a look at my class here:

enum HouseCategory {
  apartment,
  villa,
  terracedHouse,
  cottage
}

@Entity()
class House {
  @Id()
  int id;

  HouseCategory houseCategory;

  House({this.houseCategory});

  static String fromHouseCategory(HouseCategory houseCategory) {
    if (houseCategory == HouseCategory.apartment) {
      return "apartment";
    } else if (houseCategory == HouseCategory.villa) {
      return "villa";
    } else if (houseCategory == HouseCategory.terracedHouse) {
      return "terracedHouse";
    } else if (houseCategory == HouseCategory.cottage) {
      return "cottage";
    }
    return null;
  }

  static HouseCategory toHouseCategory(String houseCategory) {
    if (houseCategory == "apartment") {
      return HouseCategory.apartment;
    } else if (houseCategory == "villa") {
      return HouseCategory.villa;
    } else if (houseCategory == "terracedHouse") {
      return HouseCategory.terracedHouse;
    } else if (houseCategory == "cottage") {
      return HouseCategory.cottage;
    }
    return null;
  }


  /*
   * Converter setters and getters used for ObjectBox because the built in converters are not implemented in Dart yet
   */
  set houseCategoryOB(String val) {
    houseCategory = val != null ? JsonHelper.toHouseCategory(val) : null;
  }

  String get houseCategoryOB {
    return houseCategory != null ? JsonHelper.fromHouseCategory(houseCategory) : null;
  }
}

So when I use my class I just use the houseCategory property as normal, and then I added the "fake" getter and setter ending with "OB" just because it make sense to me but you can call it anything just not the same name as the real property. How this works is that ObjectBox ignores the real property because it is a unknow type, but the getter and setter is a String type to ObjectBox will call those automaticly and then in those getters and setters I do the conversion and read or write from/to the real property.

I hope it make sense and is usable.

P.S. I can not get code formatting to work :(

Best regards
Søren


edited by @vaind: code formatting (added line brake and language specifier after code-block opening ```)

@DPalagi
Copy link

DPalagi commented Apr 10, 2020

Thank you for your quick response @neigaard ! I'm gonna give it a try to integrate it into the data layer of my app 😁

For multiline code, I think that you have to put 3 times ` before code, then 3 times after it.

Edit : I had to put String get myCustomProperty on the getter in order to be interpreted as String by ObjectBox ; if someone is running into the same stuff 😉

Best regards,
Damien

@vaind
Copy link
Collaborator

vaind commented Apr 14, 2020

Nice find @neigaard, I wasn't aware custom getters already worked like that.

P.S. I've fixed the code-block in your comment

@Buggaboo
Copy link
Contributor

Buggaboo commented May 24, 2020

enum Meh {
  bla,
  bleu
}

// @Entity()
class Type {
  // @Id()
  int id;
  
  Meh thing; // you can slap on @Transient (hint: please merge)
  int _shadow; // stored on db
  
  Type({this.thing}) {
    _shadow = this.thing.index;
  }
  
  // basic fugly implementation here, see pretty extensions below
  set meh (String b) {
    _shadow = Meh.values.where((v) => v.toString().endsWith(b)).toList()[0].index;
  }
  
  get meh {
    return Meh.values[_shadow]; 
  }
  
  @override
  String toString() {
    return 'Type: ${Meh.values[_shadow].toString()}';
  }
}

extension MehSteroid on Meh {
  String asStringWithoutPrefix() {
    return this.toString().substring(4);
  }
  
  static Meh fromString(String s) {
    for (var v in Meh.values) {
      if (v.asStringWithoutPrefix() == s) {
        return v;
      }
    }
    
    return null;
  }
}

/// if you don't want to pollute your class with accessors
extension Steroid on Type {
  
  // same setter, but elsewhere
  set ahem (String b) {
    _shadow = MehSteroid.fromString(b)?.index;
  }
}

void main() {
  print(Type(thing:Meh.bleu)..meh = 'bla');
  print(Type(thing:Meh.bla)..ahem = 'bleu');
}

My two cents, on extensions and enums and shadowing and converters.
If you're lazy like me, you can create your own @EnumSteroid annotation to generate the extension code using code_gen.

@vaind vaind added this to the 1.0 milestone Jan 21, 2021
@vaind
Copy link
Collaborator

vaind commented Jan 21, 2021

This probably won't make it to 1.0 but we should evaluate whether any breaking API changes would be necessary.

@vaind vaind added the more info required Needs more info to become actionable. Auto-closed if no response. label Jan 21, 2021
@vaind
Copy link
Collaborator

vaind commented Apr 23, 2021

Looking at this again after I've just had a look into storing final fields...

To me, I don't think there's anything to be done (in the generator code... docs definitely need an update) to actually support custom types, dart getters and setters work like a charm as some of you already found out.

However, one I wanted to share about storing enums - it's not very safe to store the string representation or an index. Instead, you should define your own map (e.g. use a switch case) to a fixed numbers so that your code doesn't break after you rename an enum, shuffle them around or add a new one. ObjectBox for Java docs have some hints about this: https://docs.objectbox.io/advanced/custom-types#how-to-convert-enums-correctly

@vaind vaind added documentation Improvements or additions to documentation and removed enhancement New feature or request more info required Needs more info to become actionable. Auto-closed if no response. help wanted Looking for contributors (ideas, comments, code, etc) labels Apr 23, 2021
@vaind
Copy link
Collaborator

vaind commented May 12, 2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

5 participants