Hi all,
I’m currently iterating via the scaffolding feature to flesh out some ideas. The process requires multiple rounds of changes in the schema and scaffold regeneration.
However, there are multiple manual changes that I have to keep making each time, such as removing certain fields from the forms and in case of userId, assign it to context.currentUser.id in the appropriate service file.
Is there a better way to go through this repeated process?
No, i had the same problem with the services, i wish there was an abstraction which extends the generated method then we would not have to start from scratch each time.
For the fields, they filters only the auto-generated columns (id, createdAt, updatedAt) before generating views. but it is hardcoded and there is no config to ignore certain fields.
Many of the use cases I have run into relying on some kind of specification related to the data models, so my current thinking is that a meta.ts file (or meta directory with multiple files) in the api/db directory would be a good start. That way it’s as close to the schema definition as possible (unless we can actually put it in the schema itself). This makes it easy to remember to update meta when we update the schema.
The structure of meta could be something like this (although this is just a rough shot and will require significant refinement).
I think the general idea is to be able to customize scaffolding at both the model level and field level (method level in the case of services). Does it look like that from your perspective?
I didn’t really think about it but separation of concerns is an important topic to me. So i probably would go for some sort of copy of the schema structure where you can switch a boolean if you want to not generate the field. I would put that file in the web folder.
// api/**/schema.prisma
model Question {
id Int @id @default(autoincrement())
label String @db.VarChar(255)
author String @db.VarChar(255)
}
Concerning the services, i would just rename the existing service to myservice.base.ts (which would be responsible for the basic queries only) and add a myservice.ts to extend it.
// service.base.ts
export const question: QueryResolvers['question'] = ({ id }) => {
return db.question.findUnique({
where: { id }
})
}
// service.ts
import {question} from "./service.base"
export const question: QueryResolvers['question'] = ({ id }) => {
return question({ id })
}
This way the generator could just overwrite the base.ts when the service already exists and you could keep your hard work.
For Radmin I have it so you can just add /// @radmin-skip to fields you don’t want to have included in your generated forms or tables. And for more advanced customization I have a separate radmin.config.ts file, kind of similar to @tvo’s meta-file.
There are a lot of application-related aspects of data models that go beyond the actual model-to-database mapping. Django specifies these aspects in the ORM itself and that enables form generation to be very powerful, among other things. Even many cases of CRUD form validation is actually validation of the data model itself, so putting that info next to (or integrated with) the data model allow that same validation to be used in scripting scenarios or in multiple different forms. There is also the idea of signals (or hooks) such as pre-save or post-save that can give rise to autocomputation of fields such as generating url slugs or encrypting data prior to save, etc.
Coming from Django, I find Prisma so limiting and can’t wait till the day Redwood abstracts away from just Prisma and allows different ORM bindings. I’d love to use TypeORM or Drizzle along with all the other good stuff that Redwood offers.
@Tobbe the directive is nice for an admin app but what if you want different forms ? Could you describe a standard form of you *.config.ts file ? where is located this file in the redwood tree ?
@tvo I mainly work with SPA so i have this reflex to do things separated on 2 sides because i had to manage different clients with the same api. But the idea of defining different view of the same model on server side is maybe better thant going on the client. Django-Rest-Framework have a “Serializer” Layer and specifically a “ModelSerializer” class which basically defines the interface between requests and models. You can then define as many subset of field you may want for each model. It allows you to add some binding, validation and data transformation. One could imagine having the scaffold generator command prompting the user to choose which serializer to use to generate the form if any is defined. IMO it is a deep topic and it is other ways to cut the server layers. It should be discuss and planed with the Redwood core team as this has architectural impact and maybe doesn’t fit to their vision. I’m personnaly a bit frustrated by many points of the current architecture and i would really like to know where this project goes.
If it’s more specifically the forms you guys are interested in we’ve got another initiative going with zod and forms that might interest you. I’ll see if I can get the guy who’s lead on that to jump in here and maybe give you something to play around with
Sure, I’m always up for trying out new features and help with feedback.
The main challenge here I think is to have a more configurable scaffolding/generating mechanism. Forms is one aspect of it. If we can get to a point where we can regenerate sdl, services, forms, etc. after updating the schema without losing custom changes, that would immensely speed up the dev process.
I’m tinkering with workarounds for my own project right now. To be able to do this with redwood generators, I believe access to the context being passed to templates is necessary.
@tvo, @growms sorry for the delay. but here’s a bit of info on the project Tobbe is referring to.
the current goal is to have a component that takes in a zod schema and generates the appropriate form for you as a result. you can see a demo here via codesandbox.
the eventual goal would be provide CLI tools to generate that zod schema from other sources, mainly your prisma model and/or graphql mutations. so then your model can be the source of other things.
skimming through the thread it seems like you’re looking for models that can drive other things in the app, or at least other things in the app can be derived from the model. this seems to match closer to the long-term goal, but the project is a ways from that state. it’s in a stage of figuring out if this AutoForm is a good idea the community would benefit from. so please do add some input in that discussion via the codesandbox, which has instructions on providing feedback.