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

Inheritance / Polymorphism #473

Closed
hussam789 opened this issue Sep 21, 2016 · 5 comments
Closed

Inheritance / Polymorphism #473

hussam789 opened this issue Sep 21, 2016 · 5 comments

Comments

@hussam789
Copy link

Given than i have these models:

public class Zoo {
  private int id;
  private Date openning_hour;
  private Date closing_hour;
  private String manager;
  private ArrayList<Animal> animals;
}

public abstract class Animal  {
  private String name;
  private int zoo_id;
}

public class Dog extends Animal {
  private boolean canSmellFromFar;
}

public class Spider extends Animal {
  private boolean bites;
}

and if i have two tables (Zoo, Animal), and we have a Query getAllAnimalIntTheZoo(int zooId).
can it return sub-types of Animal?

@AlecKazakova
Copy link
Collaborator

SQLDelight currently wont play well with joined table inheritance (the sql side solution to inheritance). The query will have to return a Mapper<GetAllAnimals> so it's really the return type that needs to inherit from Animal as well as GetAllAnimals. Heres what I would try:

-- AnimalParent.sq
CREATE TABLE animal_parent (
  name STRING NOT NULL PRIMARY KEY,
  zoo_id INTEGER REFERENCES zoo
);

-- Dog.sq
CREATE TABLE dog (
  name STRING PRIMARY KEY REFERENCES animal_parent,
  can_small_from_far INTEGER AS Boolean
);

-- Spider.sq
CREATE TABLE spider (
  name STRING PRIMARY KEY REFERENCES animal_parent,
  bites INTEGER AS Boolean
);

-- Animal.sq
animals_view:
CREATE VIEW animal AS
SELECT animal_parent.name, zoo_id, can_smell_from_far, bites
FROM animal_parent
LEFT JOIN dog USING (name)
LEFT JOIN spider USER (spider);
// Dog.java
@AutoValue public abstract class Dog implements Animal {
  @Override public Boolean bites() {
    throw new UnsupportedOperationException("Only available to spiders");
  }
}

// Spider.java
@AutoValue public abstract class Spider implements Animal {
  @Override public Boolean can_smell_from_far() {
    throw new UnsupportedOperationException("Only available to dogs");
  }
}

// Animal.java
public interface Animal extends AnimalModel {
  Factory FACTORY = new Factory();

  RowMapper<Animal> MAPPER = FACTORY.get_all_animals_in_the_zooMapper(new Get_all_animals_in_the_zooCreator<Animal>() {
    @Override public Animal create(String name, int zoo_id, Boolean can_smell_from_far, Boolean bites) {
      if (can_smell_from_far != null) {
        // This is a dog
        return new AutoValue_Dog(name, zoo_id, can_smell_from_far);
      }
      if (bites != null) {
        // This is a spider
        return new AutoValue_Spider(name, zoo_id, bites);
      }
      throw new AssertionError();
    }
  });
}

and then your queries are on the animal table and use the Animal.MAPPER mapper. So your getAllAnimalsInZoo would look like

get_all_animals_in_zoo:
SELECT *
FROM animal
WHERE zoo_id=?;

it's pretty verbose. There might be a slightly more elegant solution or something that could be built into sqldelight but I haven't encountered this problem myself so I'm not sure. Let me know if you have more questions/concerns.

@bangarharshit
Copy link

bangarharshit commented Oct 13, 2016

I also had the same use case in past. In my chat messenger app, when I am storing message it can be of different type Image, Text, Video (around 10). What I did is to write my custom mapper and marshal.

public final class MessageContainer {
  // Common meta-data like send time
   public final MessageTypeEnum messageType;
   public final BaseMessage baseMessage;  // BaseMessage is serialisable. 
}

My mapper and marshal are taking care of deserialising and serialising base message into and from string. It's not a scalable approach though and I am thinking of generating this code myself using some kind of converter like Converter<BaseMessage,String>. I need to check code - http://stackoverflow.com/questions/14308467/sqlite-convert-text-to-numbers (sql server has a really useful method which I couldn't find in sqlite - http://www.w3schools.com/sql/func_convert.asp)

@AlecStrong, Do you recommend committing model files along with .sq files into the version control. https://github.com/alexsimo/delightful-persistence/tree/4d17062afae866750133545368695a0de5205ad0/app/src/main/java/com/alexsimo/delightfulpersistence/database

@AlecKazakova
Copy link
Collaborator

If you mean the generated *Model.java files then no, those shouldn't be checked in (as they exist under the generated folder). If you mean the files you write which implement *Model then yes, those should be checked in.

@AlecKazakova
Copy link
Collaborator

working-kotlin branch has diverged significantly from this style so closing for now

@gabrielpaim
Copy link

gabrielpaim commented May 26, 2019

Hi there,

I'd like to know if is there any update on this. Is there any plans for SqlDelight to support polymorphism/inheritance?

@AlecStrong Would you still recommend the same approach to deal with this still? That is, joining all inherited tables into a single view and treating it on mapper as a STI. I find it somehow uncomfortable, but maybe it still remains as good strategy to deal with it.

Thank you!

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

No branches or pull requests

4 participants