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

Stricter field type, and nullable by default #95

Open
kiaking opened this issue Nov 8, 2021 · 2 comments
Open

Stricter field type, and nullable by default #95

kiaking opened this issue Nov 8, 2021 · 2 comments
Labels
enhancement New feature or request

Comments

@kiaking
Copy link
Member

kiaking commented Nov 8, 2021

This is still just an idea, so looking for feedback.

What do you think about making model attributes more strict? Currently, we have several fields with primitive types, such as string, number. etc. At the moment, these fields will cast values rather than restrict them. So passing true to string field will make it 'true'.

The idea is to make them fail instead of casting.

class User extends Model {
  static entity = 'users'

  @Str() name!: string
}

new User({ name: true }) // <- Error('name is not string')

In addition to this, how about if we make all the fields nullable by default. Because in the frontend, usually many fields are going to be nullable.

So instead of having nullable option, we'll add NonNullable decorator (if this is possible).

class User extends Model {
  static entity = 'users'

  // This field is number, and not nullable.
  @Num()
  @NonNullable()
  id!: number

  // This field is string, or null.
  @Str()
  name!: string | null
}

The default value should behave the same,

class User extends Model {
  static entity = 'users'

  // This field is nullable, but if we pass `null`, it becomes `John Doe`.
  // so technically it wouldn't be `null`.
  @Str('John Doe')
  name!: string
}
@kiaking kiaking added the enhancement New feature or request label Nov 8, 2021
@kiaking kiaking added this to the v1.0.0-alpha.1 milestone Nov 8, 2021
@superfreddialpad
Copy link

superfreddialpad commented Nov 10, 2021

I think that making field types stricter is a great idea, I think it's more in-line with the spirit of typescript. If one wishes for true to exist as "true" in a string field, they should cast it themselves and not rely on the orm to do it automatically, which could lead to difficult-to-track-down bugs. Better to throw an Error and have it show up right away.

I don't have a strong opinion on whether to make attributes nullable by default, but I think that is orthogonal to the behavior of the default value. As per the spec [emphasis mine]:

4.4.15 null value
primitive value that represents the intentional absence of any object value

I contend that null should be a valid value for a nullable field, and that undefined should be the only value that uses the default. So an example user class:

class User extends Model {
  static entity = 'users'
  @Num(50)
  @NonNullable()
  age!: number

  @Str('John Doe')
  name!: string | null
}

should have the following behavior:

const r = store.$repo(User);

// saves { age: 50, name: 'John Doe' }
r.save({});

// saves { age: 50, name: null }
r.save({ name: null });

// throws Error - age is non-nullable
r.save({ age: null });

I'm also curious about specification of behavior for fields without a default. I don't know what the correct/current behavior is, but for example:

class Post extends Model {
  @Str()
  @NonNullable()
  body!: string

  @Str()
  title: string | null
}

const r = store.$repo(Model);

// throws Error - body is non-nullable and has no default
r.save({ title: "B" });

// what about a nullable field with no default?
// throws Error - makes the most sense to me.
// { title: null, body: "test" } - rather this be expressed as `Str(null)`
// { title: undefined, body: "test" }
// { body: "test" }
r.save({ body: "test" });

it's possible that this diverges too much from the current behavior, but this is how I think it should behave based on my understanding of the meaning of null.

@kiaking
Copy link
Member Author

kiaking commented Nov 19, 2021

Thanks for the feedback!

I'm also curious about specification of behavior for fields without a default. I don't know what the correct/current behavior is, but for example:

Yes, I think this is how it should work if make null by default and add NonNullable option. If the field is NonNullable, then either passing in null or undefined to the persistent method should throw. The nullable field without default value is same as setting default value as null.

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

No branches or pull requests

2 participants