Release notes v0.0.119

More breaking changes, results in more release notes. So to do my self a favor, I should stop doing breaking changes, so I don't have to write release notes. Does it work that way? Maybe.

Code gen

We are well on our way to enable the JSDoc eslint plugin. At last, the generator output should now be stable and never trigger an error when the jsdoc rules are enabled.

There was a bug in the generated sql 'where xxxIn' behaviour. The generated where function would ignore an empty array, that could result in unexpectedly updating or deleting all rows of a table. In this release, an empty 'where xxxIn' array should result in zero rows updated, deleted or selected.

We now have dynamic ORDER BY support in the sql generator. This works by accepting an array of columns you want to sort on, and an optional order specification. Using it would look something like the following:

// Get users sorted by their age, ascending
const result = await query`SELECT * FROM "user" u ${userOrderBy(["age"])}`.exec(
  sql,
);

// Get users sorted by their age descending, and if multiple users have the same age, on name ascending.
// In tis case name is an optional column, so we can specify where the 'null' values should go.
const result = await query`SELECT * FROM "user" u ${userOrderBy(
  ["age", "name"],
  {
    age: "DESC",
    name: "ASC NULLS FIRST",
  },
)}`.exec(sql);

The values that can be put in the 'orderBy' and 'orderBySpec' arguments, should be marked as .searchable() in the spec. Of course the query builder also supports these fields:

const [newestUser] = await queryUser({
  orderBy: ["createdAt"],
  orderBySpec: ["DESC"],
  posts: {
    limit: 1,
    orderBy: ["likedCount"],
  },
  limit: 1,
}).exec(sql);

The above would get the 'newest' user, with a single post that has the least likes. The default behaviour is still the same, orderBy: ["createdAt", "updatedAt", "id"]. However, you need to update the xxxOrderBy calls where you specified for example the tableName argument.

Store

We removed the getNestedFileGroup in this release as the query builder has the same options and more. The only limit is that the new call doesn't return the full group depth, but instead you always specify the levels you need.

The following examples illustrate equal behaviour:

// Old
await getNestedFileGroup(sql, { excludeFiles: true });

// New, get 2 levels of children for all roots, correctly ordered.
const result = await queryFileGroup({
  orderBy: ["order"],
  children: {
    orderBy: ["order"],
    children: {
      orderBy: ["order"],
    },
  },
  where: {
    parentIsNull: true,
  },
}).exec(sql);
// Old
await getNestedFileGroup(sql, { rootId: myFileGroupId });

// New, get 1 level of children for the specified 'root'
// and include the file, correctly ordered.
const result = await queryFileGroup({
  orderBy: ["order"],
  children: {
    orderBy: ["order"],
    file: {},
  },
  where: {
    id: myFileGroupId,
  },
}).exec(sql);

In closing

That's it, we are expecting some more breaking changes in the query builder soon, as we move the viaXxx to the where builder instead. Also if you want to help design the next few things, pleas take a look at dependencies between routes, consistent & validated JSDoc or integrating OpenAPI 3 a bit more.