On Friday, 2 December 2022 at 04:14:37 UTC, kinke wrote:
On Friday, 2 December 2022 at 00:24:44 UTC, WebFreak001 wrote:
I want to use the static initializers (when used with an UDA)
as default values inside my SQL database.
See
https://github.com/rorm-orm/dorm/blob/a86c7856e71bbc18cd50a7a6f701c325a4746518/source/dorm/declarative/conversion.d#L959
With my current design it's not really possible to move it out
of compile time to runtime because the type description I
create there gets serialized and output for use in another
program (the migrator). Right now it's simply taking the
compile time struct I generate and just dumping it without
modification into a JSON serializer.
[...]
Okay, so what's blocking CTFE construction of these models?
AFAICT, you have a templated base constructor in `Model`, which
runs an optional `@constructValue!(() => Clock.currTime +
4.hours)` lambda UDA for all fields of the derived type. Can't
you replace all of that with a default ctor in the derived type?
```
class MyModel : Model {
int x = 123; // statically initialized
SysTime validUntil; // dynamically initialized in ctor
this() {
validUntil = Clock.currTime + 4.hours;
}
}
```
Such an instance should be CTFE-constructible, and the valid
instance would feature the expected value for the `validUntil`
field. If you need to know about such dynamically generated
fields (as e.g. here in this time-critical example), an option
would be a `@dynamicallyInitialized` UDA. Then if you
additionally need to be able to re-run these current
`@constructValue` lambdas for an already constructed instance,
you could probably go with creating a fresh new instance and
copying over the fresh new field values.
constructValue is entirely different than this default value.
It's not being put into the database, it's just for the library
to send it when it's missing. (so other apps accessing the
database can't use the same info) - It's also still an open
question if it even gives any value because it isn't part of the
DB.
To support constructValues I iterate over all DB fields and run
their constructors. I implemented listing the fields with a
ListFields!T template. However now when I want to generate the DB
field information I also use this same template to list all
columns to generate attributes, such as what default value to put
into SQL. Problem here is that that tries to call the
constructor, which wants to iterate over the fields, while the
fields are still being iterated. (or something similar to this)
Basically in the end the compiler complained about forward
reference / the size of the fields not being known when I put in
a field of a template type that would try to use the same
ListFields template on the class I put that value in.
Right now I hack around this by adding an `int cacheHack`
template parameter to ListFields, which simply does nothing.
However this fixes that the compiler thinks the template isn't
usable and everything seems to work with this.
Anyway this is all completely different from the default value
thing, because I already found workarounds and changed some
internals a bit to support things like cyclic data structures.
I would still like a way to access the initializer from class
fields, and it would be especially cool would be to know if they
are explicitly set. Right now I have this weird and heavy
`@defaultValue(...)` annotation that's basically the same as `=
...;`, that I just needed to add to make it possible to use
T.init as default value in the DB as well, but not force it. My
code uses `@defaultFromInit` to make it use the initializer, but
it would be great if I didn't need this at all. (although because
of my cyclic template issues it might break again and be unusable
for me)