romeerez / orchid-orm

Orchid ORM
https://orchid-orm.netlify.app/
MIT License
488 stars 14 forks source link

Redesign table config #401

Open romeerez opened 6 days ago

romeerez commented 6 days ago

The current way of defining tables is weird, to say the least.

You can't simply tell TS that books belong to authors and authors have many books, because TS is confused with the type recursion (book -> author -> book -> author -> ...).

The limitation can be only bypassed by using class syntax.

I've been looking for a workaround to make it look nicer for years, and finally I got it!

I have a working proof-of-concept, so this should work out well, here is the spoiler of the future table syntax:

const BookTable = defineTable("book")
  .columns((t) => ({
    id: t.identity().primaryKey(),
    title: t.string(),
    authorId: t.integer().references(() => AuthorTable("id")),
  }))
  .relations((t) => ({
    author: t.belongsTo({
      from: ["authorId"],
      to: () => AuthorTable("id"),
    }),
  }));

const AuthorTable = defineTable("author")
  .columns((t) => ({
    id: t.identity().primaryKey(),
    name: t.string(),
  }))
  .relations((t) => ({
    books: t.hasMany({
      from: ["id"],
      to: () => BookTable("id"),
    }),
  }));
mordechaim commented 5 days ago

Starting to look like drizzle... I hope the existing config will be backward compatible, or at least, move to Orchid 2.0

IlyaSemenov commented 5 days ago

Since columns are an essential, inseparable part of the table, shouldn't they be rather passed as the second argument of defineTable? Is there any point in defineTable() without .columns() other than (quite arguable) clarity of code?

Example:

const BookTable = defineTable("book", t => ({
  id: t.identity().primaryKey(),
  title: t.string(),
  authorId: t.integer().references(() => AuthorTable("id")),
})).relations(t => ({
  author: t.belongsTo({
    from: ["authorId"],
    to: () => AuthorTable("id"),
  }),
}))
romeerez commented 3 days ago

Starting to look like drizzle... I hope the existing config will be backward compatible, or at least, move to Orchid 2.0

As for compatibility - sure, will be kept (not forever).

I'm was happy to get around TS limitations for that syntax, but seems like you're not really appreciating it, why not?

columns passed as the second argument

Good idea!

I guess sure, let columns be the second argument, as long as they don't depend on any of possible table options.

There are some possible options such as softDelete, noPrimaryKey, maybe some others, and if the t arg somehow depends on those options, columns must to follow the options. But that's not the case, so softDelete, noPrimaryKey and future parameters can be defined after columns (by chaining a method call).