fluent-kit icon indicating copy to clipboard operation
fluent-kit copied to clipboard

Write once properties

Open MrMage opened this issue 5 years ago • 2 comments

Many models contain "write-once" fields that will only ever be set at creation time (e.g. the creation timestamp), but shall not modified ever after. Will Fluent 4 support declaring such properties, allowing them to be set in the initializer, but nowhere else? The idea is to make accidental manipulations of these properties later on all but impossible.

If that's not possible yet with Fluent 4, I'd suggest this as a feature request.

MrMage avatar Mar 21 '19 10:03 MrMage

Transferring this to FluentKit since that's where the code would live for such a feature.

It should be possible to declare field defaults in Fluent 4, which could be an improvement to how we handle timestamps. Those types of properties could be made to only support reading. But, I'm not sure how write-once properties would work. If you need to be able to write the property ever (even if only once), then the property needs to be writable. There's not really a way to tell the compiler to only make it writable once.

To give some context, this is how setting a read only property w/ a default could work:

struct Planet: Model {
    let id = Field<Int>("id")
    let name = Field<String>("name")
    let createdAt = ReadOnlyField<Date>("createdAt", default: .currentDate)
}

let planet: Row<Planet> // from DB
try planet.get(\.createdAt) // Date
try planet.set(\.createdAt, to: ...) // Compiler error, ambiguous use of `set`

I'm not sure I love that API though since it's within the realm of possibility that you might need to update the createdAt field for whatever reason. It seems like it should be up to the developer whether to do that or not.

FWIW, ReadOnlyField could be declared entirely in user code without needing any internal Fluent support.

tanner0101 avatar Mar 21 '19 17:03 tanner0101

In "regular" Swift, there is a way to declare write-once properties: let. My idea was similar; have a kind of property that doesn't expose a set method, with the only place to set its value in an initializer or when decoding from a database result set. However, I now see that set is (needs to, I guess) declared on the model itself, not on each individual field.

Explicit manual updates could still be done via a SQL UPDATE command, but by avoiding a set method we could avoid accidentally changing the corresponding property on the model and then calling save() with that changed property — again, similar to how let works.

MrMage avatar Mar 22 '19 08:03 MrMage