question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

VIEW models no longer have encapsulated, null-safe data models from joined tables

See original GitHub issue

Let’s take the following *.sq files:

-- Animal.sq
CREATE TABLE animal(
    id INTEGER PRIMARY KEY AUTOINCREMENT
);

animal_view:
CREATE VIEW animal_view AS
SELECT A.*, H.*, C.*
FROM animal A
LEFT JOIN human H ON H.animal_id = A.id
LEFT JOIN cat C ON C.animal_id = A.id;
-- Human.sq
CREATE TABLE human(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    animal_id INTEGER NOT NULL,
    first_name TEXT NOT NULL,
    last_name TEXT NOT NULL,
    FOREIGN KEY(animal_id) REFERENCES animal(id)
);
Cat.sq
CREATE TABLE cat(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    animal_id INTEGER NOT NULL,
    name TEXT,
    pattern TEXT,
    FOREIGN KEY(animal_id) REFERENCES animal(id)
);

For SqlDelight 0.9.0, or pre-1.0 for that matter, the animal_view model looks like so:

  interface Animal_viewModel<T1 extends AnimalModel, T2 extends HumanModel, T3 extends CatModel> {
    @NonNull
    T1 A();

    @Nullable
    T2 H();

    @Nullable
    T3 C();
  }

Where for T1, T2, and T3 we have:

public interface AnimalModel {
  ...
  long id();
  ...
}

public interface HumanModel {
  ...
  long id();

  long animal_id();

  @NonNull
  String first_name();

  @NonNull
  String last_name();
  ...
}

public interface CatModel {
  ...
  long id();

  long animal_id();

  @Nullable
  String name();

  @Nullable
  String pattern();
  ...
}

Notice how we have encapsulation of the joined table models and some null-safety thanks to the nullable annotations. Even though the generated code is in Java, Kotlin can infer the null type-safety thanks to the annotations.

When compiling these same *.sq files with SqlDelight 1.1.3, we get the following, more flat-structured model for animal_view:

interface Animal_view {
    val id: Long

    val id_: Long?

    val animal_id: Long?

    val first_name: String?

    val last_name: String?

    val id__: Long?

    val animal_id_: Long?

    val name: String?

    val pattern: String?
    ...

Two issues I see with the newer model structure:

  1. Slight naming conflict with id and animal_id. It is not straightforward to distinguish between id, id_, and id__ or animal_id and animal_id_. This can become even more confusing/error prone with larger projections.
  2. Everything aside from the first id is nullable. This potentially leads to code that requires !! or checkNotNull if the code is certain that for a given row entry, a subset of of the columns are non-null.

In many ways, I find the pre-version 1 view models to be safer to use. Any reason why we would not want to bring a similar structure back? In Kotlin of course. 🙂

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

9reactions
ansmancommented, May 4, 2019

Well even if you use fine grain projections it could still generate a model for a subset. As it is right now it’s pretty inconvenient because of name clashes and when you have utility methods for the full model.

3reactions
eygrabercommented, Mar 25, 2020

Any chance this will ever be re-evaluated? There are many instances throughout my code base that would benefit from using a star projection, even though there are other places where star projections are bad.

I’ve been sort of using mappers, but I interface directly with SqlDelight in all of our modules so it’s difficult. I wanted to make a “store” abstraction so we can only expose what we need to, but there are others on my team who don’t want that. My point being that real world scenarios can sometimes outweigh idealistic practices.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Is it possible to create view models by out of ... - Stack Overflow
1 Answer 1 · Data Model: It is a simple class related to specified table from the database and can be used in...
Read more >
Inner join drops records in result - Azure Databricks
You perform an inner join, but the resulting joined table is missing data. For example, assume you have two tables, orders and models...
Read more >
Inner join drops records in result - Databricks Knowledge Base
You perform an inner join, but the resulting joined table is missing data. For example, assume you have two tables, orders and models....
Read more >
NULL SAFE Join - No One Will Tell You This❤️Data Engineer
SQL Interview PRO. NULL SAFE Join - Tricky SQL Interview Question SQL Joins - No One Will Tell You This❤️ Data Engineer...
Read more >
Join SQL Server tables where columns include NULL values
Dealing with NULL values especially when joining tables can become a challenge. Let's take a look at this issue and how this can...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found