Release notes v0.0.103
Another big release, another set of release notes. Usually that means there are some breaking changes, as is the case with v0.0.103. This release notes are a bit different tho, we renamed to Compas! Due to that we have a bit more breaking changes than planned. Find a migration guide near the bottom of this doc. Buckle up, and let's get started.
TL;DR
First time this is needed, let's go:
- Stable generated validators
- Any type custom validators
- Default validator errors, removed
validatorSetError
- Add
dumpApiStructure
- Generate sql query builders
Lint config changes
We did some version bumps on the dependencies of @compas/lint-config. This brought a new ESLint rule no-unsafe-optional-chaining. This is now enabled by default.
Stable validator output
Previously, if you introduced a new type somewhere, all anonymous validators would get a different name. This was simply based on an increasing number, where a unique type would get a new number and thus created function names like anonymousValidator3
. The new anonymous validator names will look something like anonymousValidator781180217
. These names are based on a hash generated from te type. This results in git diffs being easier to read.
Any Validators
We now have support for custom validators for T.any()
types. These should return a boolean value, and don't have to worry about nullability. A simple example:
// generate.js
const T = new TypeCreator();
app.add(
T.any().raw("{ myType: true }").validator("myValidator", {
javaScript: 'import { myValidator } from "./dist/custom-validators.js";',
typeScript: 'import { myValidator } from "./src/custom-validators.ts";',
}),
);
// src/custom-validator.js
type MyType = { myType: true };
function isMyType(value): value is MyType {
return value?.myType === true;
}
This way you can even reuse you custom validator as a TypeScript type-guard.
Inline validators
To improve performance and reduce call stacks, we introduce inline validators. This is a fully backwards compatible change. For now only a few cases will be inlined, for example any types, booleans, string oneOf and references. There is a trade-off here between re-usability and decreasing callstacks. So we are not sure yet how far this will go and if we should find a better way of doing it.
Simplified strict object validation
In your anonymous-validator file, you will now find all static keys of the objects that are validated in strict mode. Instead of allocating a Set every validation call, we now reuse this set, and do the strict check first. This is inspired by the key checks done in the generated UPDATE
and INSERT
query partials.
Simplified validation errors
We do not generate validationSetError
any more. Instead we have defaults depending on the throwingValidators
option. When true, as is the default for isNodeServer
, this will throw via AppError.validationError
and thus result in a 400
status code in a HTTP request context. When throwingValidators
is false, the default for isNode
and isBrowser
, The returned errors array, will contain plain JavaScript objects.
Removed default of unsafe dumpStructure
option
Dump structure served us well as the only way of exposing a structure to the outside world. However, it has some downsides. The outside world does not need to know what the object relations are, or other internal types. So we added dumpApiStructure
. This only exposes the routes and types referenced by the routes. As a side effect, this breaks for generated api clients that depend on these types.
When isNodeServer
is true, this new settings are in effect as defaults. For package maintainers, you would need to add dumpStructure
to the generator options, if it is part of your api surface.
SQL Query builders
The biggest feature of this release is nested sql query builders. It solves a few things in one go:
- Get nested results from Postgres
- Transform results in usable JavaScript objects, converting Dates back and removing nulls
- Includes the old traverse builder
There are still lots of missing features and some limitations:
- Offset and limit are not supported in nested builders yet
- Generated transformers don't work with self referencing types, either direct or indirect.
- Transformers only work correctly nested with a valid builder object. This will most likely always be the case.
Note that we have enabled the transformers for the basic queries as well, and thus you'd be able to directly benefit from it without having to use a nested query.
SQL Where and query builder argument validation
We have removed the custom key check from generated Where partials, and now use full validator features. This may not be completely obvious, but as noted above will result in a AppError.validationError
.
SQL Where or support
The last small, but darn useful feature is OR
support in the generated Where partials. The new where-objects now accept an $or
key with an array of nested where-objects. This allows for any recursing OR
and AND
combination necessary.
Migration guide
This will be a collection of steps and settings to overcome the breaking changes. Make sure to update the dependencies, that depend on Compas, first. So first any packages, then private services and then the final project that depends on these packages and services. Projects that only use the api client generators, should wait on the respective api's to update.
The first thing is to clean up the current installation:
yarn lbu docker clean
This will remove the Docker containers and volumes created by LBU. Next install the new packages, by replacing @lbu
with @compas
and changing the versions to 0.0.103
. At this point it is a good time tho rename all your imports and script references. For imports, the following replace may work:
- Replace search:
"@lbu/([\w-]+)"
- Replace value:
"@compas/$1"
There are no default generate settings for packages anymore. A good starting point is:
/** @type {GenerateOpts} */
const generateOpts = {
enabledGroups: ["store"],
enabledGenerators: ["type", "sql", "validator"],
throwingValidators: true,
isNode: true,
dumpStructure: true,
dumpPostgres: true,
};
For projects already running in production (not advisable...), recurring jobs should be automatically upgraded. This will be removed in the next feature release. Migrations are a bit trickier and require a manual query:
BEGIN;
UPDATE "migration"
SET
namespace = '@compas/store'
WHERE
namespace = '@lbu/store';
COMMIT;
Other than the breaking changes mentioned earlier in this doc, this should be it.
In closing
A big release since a while. This was mostly due to time, features piling up and renaming to Compas. One of the last ones before a v0.1.0. Much work is still needed on writing the docs. And prefer to have this release tested in the wild, before going in beta.