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

How to type nullable relations? #1801

Open
itsramiel opened this issue Jun 4, 2024 · 1 comment
Open

How to type nullable relations? #1801

itsramiel opened this issue Jun 4, 2024 · 1 comment

Comments

@itsramiel
Copy link

itsramiel commented Jun 4, 2024

Hey,

I have a use case where a relationship can be nullable. I defined this in the schema using the isOptional but how would I go about typing the field in the model?

Given the models in the example of this repo:

class Blog extends Model {
  static table = TableName.BLOGS

  static associations: Associations = {
    [TableName.POSTS]: { type: 'has_many', foreignKey: 'blog_id' },
  }

  @field('name') name!: string;

}

class Post extends Model {
  static table = TableName.POSTS

  static associations: Associations = {
    [TableName.BLOGS]: { type: 'belongs_to', key: 'blog_id' },
  }

  @field('name') name!: string;
  @text("body") content!: string;

  @relation(TableName.BLOGS, 'blog_id') blog!: Relation<Blog>;
}

Let's assume for the sake of example that you post a Post under no specific Blog how would:
@relation(TableName.BLOGS, 'blog_id') blog!: Relation<Blog>; change?

Changing the type to Relation<Blog> | null doesnt work correctly because post.blog always return an object even the blog is nullable. And Relation<Blog | null> doesnt work because the generic that Relation takes extends Model which is not nullable.

How do I go about creating nullable relations with type safety?

@nhanders
Copy link

nhanders commented Jul 4, 2024

Hi @itsramiel , I had the same issue here and this is how I resolved it. I don't love that I'm ignoring TS errors and using a type assertion, but it does the job for me.

import {
  Model, Relation as WatermelonDbRelation,
} from '@nozbe/watermelondb';
import {
  Observable,
} from 'rxjs';

/**
 * Wrapper of `Relation` to correctly type optional relations. These are
 * relations where the fk is an optional field.
 */
export default class OptionalRelation<
  T extends Model,
> extends WatermelonDbRelation<T> {
  // @ts-ignore
  fetch() {
    return super.fetch() as Promise<T | null>;
  }
  
  // @ts-ignore
  observe() {
    return super.observe() as Observable<T | null>;
  }
}
@relation(TableName.BLOGS, 'blog_id') blog!: OptionalRelation<Blog>;

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

2 participants