Closed valiafetisov closed 1 year ago
sqlite
or postgres
or mysql
as the data storage+/-
Have user roles out of the box
knex
and written in js+/-
Authorization can be derived from "PostgreSQL's RBAC and Row-Level Security"
+/-
Basically an encapsulated service extensible only via configuration and calls to other servicesTypeORM - ORM for TypeScript
Data Mapper
pattern with custom repositories?TypeGraphQL - A library to create graphql schema from the code (so it doesn't need to be maintained separately)
Prisma ORM – "Next-generation ORM for Node.js & TypeScript, ..."
prisma
language
Knexjs – "A query builder for PostgreSQL, ..."
Kysely
(see below), TypeORM
, Prisma
, MikroORM
(see below)Kysely - "A type-safe typescript SQL query builder"
MikroORM – "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns"
Kysely
)Nexus – "Code-First, Type-Safe, GraphQL Schema Construction"
But
"But", in rejection of what?
Other remarks:
Conclude the very initial technical stack
what I'm missing here at the moment to come to a conclusion is a set of requirements that we have that these tools will help us with. I know we have it in docs and issues elsewhere - can you link them / do a high-level overview of the requirements here or in a dedicated issue as well, so that we can reach a more grounded decision?
Good points, thank you!
what I'm missing here at the moment to come to a conclusion is a set of requirements
You're right, those are the initial requirements I've just put together based on the existing input. Feel free to comment there as well!
But please note, the initial purpose of the current issue was to investigate, if we can use use any existing headless ORMs. And I think the conclusion is clear: we better not if we want to keep flexibility for the long-term features. I agree about spending more time on other "bare tools" and will more thoroughly look into typeorm
competitors like prisma
, knex.js
, nexus
, etc
@BracketJohn I've added 5 more libraries to the Bare tools
section above and further specified requirements in #3. I think my conclusion stands the same, although MikroORM
looks interesting (but also less popular/less integrated). Let me know if you want to see other tools in the list
Generates schema directly from types 😮
wow, this is actually crazy - I think the limitation here then is, that they will not be able to support many features that exist in SQL but not in TS? I see that they for exampke support UUID, but as you said: it's quite complex already. If I imagine something like check-constraints this would probably be a lot more complex.
Thanks for expanding the section. There's no more tooling I'm missing -> which one do you want to go with, based on the requirements collected in #3?
other than that: I think it's time to get going, thjanks for already opening the issues 🎊 Let's do full-steam ahead starting on Monday (:
It requires a complex build-step that will be hard to impossible to modularize
Prisma update: Actually, they have client-side extensions now: This is quite nice as it adds typed alterations to the prisma client. This also allows to implement computed properties: https://www.prisma.io/docs/concepts/components/prisma-client/client-extensions
As discussed in the daily: in order to settle with ORM, we need to finally compare two closest competitors: Prisma vs TypeORM. Here are my requirements
Flexibility. My main fear is that because Prisma models have to be pre-compiled, we might end up with essential feature that they simply don't support yet, or a feature the support of which they will drop one day? Don't have a good example for this yet (maybe enums?)
Support for extensible model structure. I think that the main quality of the ORM (at least for this particular project) is to not only provide the type-safe interface of the database, but the extensible model to build business logic. In other words, have a central place where we define tables AND actions that can be taken with them.
With TypeORM it will look like this:
// CoreUnit.ts
@Entity()
export class CoreUnit {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@Column()
descriptionSentence: string
async updateDescription(context: Context, descriptionSentence: string): Promise<CoreUnit> {
await context.roles.verifyIsAdmin()
await this.save({ descriptionSentence })
return this
}
}
// usage
CoreUnit.findOneBy({ id: '123' }).updateDescription()
Prisma instead suggests to Wrap a Prisma Model in a Class
(but client extensions feature might also help here, they just didn't add it to the same guide):
// schema.prisma
model CoreUnit {
id String @id @default(cuid())
name String
descriptionSentence String
}
// CoreUnit.ts
class CoreUnit {
constructor(private readonly CoreUnit: PrismaClient['CoreUnit']) {}
async updateDescription(context: Context, id: string, descriptionSentence: string): Promise<CoreUnit> {
await context.roles.verifyIsAdmin()
return this.CoreUnit.update(id, { descriptionSentence })
}
}
// usage
const prisma = new PrismaClient()
const coreUnit = new CoreUnit(prisma.CoreUnit)
await coreUnit.updateDescription(context, '123', 'test test')
The ability to dynamically define model. I expect that the end goal of this product (development-wise) is to make a declarative-like interface where in some file we just define how this particular model behaves on a business-level and then everything else is geneated: the endpoints, the interfaces, input validators, etc. For this to work, I expect that we will need to extend or come up with our own declarative structure that will require necessary fields and "dynamically" generated models based on that.
Split logic info different module
folders
Hooks. I expect that some part of the logic in this project will be hooks: do something, when something else changes. The first known feature requiring hooks is record history. The requirement to preserve previous values along with the method name that changed them as well as the user
Migrations
Virtual columns
@VirtualColumn
decoratorclient-extensions
to add custom fields and methods to query resultsDynamic data source. In the end, due to the offline-first requirements, we might want to use possibility to dynamically change/set/create duplicate of the datasource based on the locally available data
Flexibility. My main fear is that because Prisma models have to be pre-compiled, we might end up with essential feature that they simply don't support yet, or a feature the support of which they will drop one day? Don't have a good example for this yet (maybe enums?)
agreed - with an open end project like this it is probably best to keep all options open
Prisma instead suggests to Wrap a Prisma Model in a Class (but client extensions feature might also help here, they just didn't add it to the same guide):
I think here Prisma is actually on the same level as typeORM with the recent extensions feature. If you look at the docs of this you'll see that you can modify behavior on most levels. I think this should be neough.
The ability to dynamically define model. I expect that the end goal of this product (development-wise) is to make a declarative-like interface where in some file we just define how this particular model behaves on a business-level and then everything else is geneated: the endpoints, the interfaces, input validators, etc. For this to work, I expect that we will need to extend or come up with our own declarative structure that will require necessary fields and "dynamically" generated models based on that.
where is this requirement from?
Split logic info different module folders
as outlined orally: I have not seen this actually happening in https://github.com/makerdao-ses/ecosystem-api instead I've seen https://github.com/makerdao-ses/ecosystem-api/blob/main/seeds/01-CoreUnits.js as a central definition and then in https://github.com/makerdao-ses/ecosystem-api/tree/main/src/modules/Auth it's only about business logic -> where do you get this requirement from?
Virtual columns
as above: this should be resolved by client-extensions
(you also write this, I just want to make clear that in my eyes the two solutions are on the same level here)
doing a summary here: I see that in point (1), (3) (if actual requirement), (4) (if actual requirement) typeorm leads. If 3 and 4 are both not requirements it would boil down to (1).
what about considerations like developer-experience and improved typescript support, both of which are probably important to external contributors?
I think here Prisma is actually on the same level as typeORM with the recent extensions feature
Agree with this, extensions feature is quite nice. Although the interface is not as friendly as a wide variety of decorators
The ability to dynamically define model.
where is this requirement from?
There is a requirement to build document interface for every kind of document and every kind of action on top of this document. From this I derive that we would rather make a declarative structure where the interface is generated from it, instead of forcing to implement the UI/validators separately separately for each model and force external developers to do it every time they submit a change.
Split logic info different module folders
where do you get this requirement from?
This was raised during the meeting with Wouter. As far as I understood, ecosystem-api should not be eyed as a quality standard, if we can do better. I personally would prefer to keep those things in one place, but also understand that as soon as there relations, you can no longer clearly separate those things
what about considerations like developer-experience and improved typescript support, both of which are probably important to external contributors?
Overall, I see no major differences here, some things just done differently here vs there. There is also no much difference features-wise (4 is really no a very big deal), but the only real considerations for me here were 1 and 3.
Not sure what this is about as I'm just here to the reference on an issue on the Prisma repository, but if y'all need dynamically generated Prisma schémas, I have a library on my profile which would let you generate them programatically. 😂
Goal
Overview on the existing tools that we can use
Context
During the initial planning, we raised the questions and mentioned few existing solutions which might cover some of the requirements. Those include sanity, strapi, slicknode for headless CMSs and postgraphile and graphile for automatically generated graphql endpoints.
Tasks