CLI
The CLI (Command Line Interface) is a part of the framework system that allows you to use the full power of the framework on the command line - manipulate data, import, export, etc.
The framework scans the directory for a list of commands and provides you with the ability to see what commands are available to run.
CLI commands are part of the framework inheritance process.
Run Command
You are able to create a group of commands by putting files in a directory. You can see ‘migration’ as an example of grouping commands.
# On the project level
node src/cli.ts {command}
# OR
npm run cli
The command path works the same way as in controllers. Any file will be parsed as a command, and folders will group commands together. But unlike at the controller level, you are not able to change that behavior.
You are able to create a group of commands by putting files in a directory. You can see ‘migration’ as an example of grouping commands.
commands / migration / create.ts; // migration/create command
commands / migration / migrate.ts; // migration/migrate command
API
You are able to run a command from any place in the framework.
this.app.runCliCommand(commandName: string, args: {}): Promise;
Where:
commandName
- the name of the command that you want to start.
args
- the arguments that you want to pass to the command.
Creating Your Own Command
All passed arguments on the command line are parsed with the help of the parseArgs
module.
import AbstractCommand from "@adaptivestone/framework/modules/AbstractCommand.js";
import type { CommandArgumentToTypes } from "@adaptivestone/framework/modules/AbstractCommand.js";
class CommandName extends AbstractCommand {
static get description() {
return "Some nice description of the command";
}
/**
* You are able to add command arguments for parsing here.
* https://nodejs.org/api/util.html#utilparseargsconfig
*/
static get commandArguments() {
return {
id: {
type: "string",
description: "User ID to find the user",
},
email: {
type: "string",
description: "User email to find/create the user",
},
password: {
type: "string",
description: "New password for the user",
},
roles: {
type: "string",
required: true, // make sure that command will ask this from user
description:
"User roles as a comma-separated string (--roles=user,admin,someOtherRoles)",
},
update: {
type: "boolean",
default: false,
description: "Update the user if they exist",
},
} as const; // <- this is important for type generation
}
static isShouldInitModels = true; // Default value. Can be omitted.
/**
* If true, then this command will get model paths with inheritance.
*/
static isShouldGetModelPaths = true;
/**
* Return the name of the connection that you want to use.
*/
static getMongoConnectionName(commandName, commandArguments) {
return `CLI: ${commandName} ${JSON.stringify(args)}`;
}
async run() {
// CommandArgumentToTypes will generate types from commandArguments description
const { id, email, password, roles, update } = this
.args as CommandArgumentToTypes<typeof CommandName.commandArguments>;
return new Promise((resolve, reject) => {});
}
}
export default CommandName;
Framework Commands
The framework comes with a few built-in commands.
Migration
Migration commands allow you to migrate some data to another, or fill the database with some data.
The key point here is that a migration is executed only once per file.
You can use migrations for different cases, not only to modify data in the database.
Creating a Migration
The migration command comes with a template to generate a migration.
node src/cli.ts migration/create --name={someName}
After creating the migration, please edit it and implement any logic that you want here.
Applying a Migration
node src/cli.ts migration/migrate
A migration is executed in the order it was created. It is executed only once per life.
DropIndex
Sometimes it is very useful to drop indexes on already created models. For example, you created a unique index for non-required fields and missed that null
values also should be unique per collection.
The framework will take care of creating indexes based on your model on the next start, so you can drop an index and be sure that it will be recreated after.
Run dropindex
node src/cli.ts dropindex --model={modelName}
SyncIndexes
Synchronizes the indexes defined in the models with the real ones indexed in the database. The command will remove all indexes from the database that do not exist in the model OR have different parameters. Then it will create new indexes.
This can be a dangerous command in case you have some unique index features.
Run SyncIndexes
node src/cli.ts SyncIndexes
OpenAPI Documentation
The framework can generate documentation in the OpenAPI (Swagger) format. That is a pretty standard format for exchanging documentation. The framework only generates a JSON file and does not provide any viewer like the online version at https://petstore.swagger.io/ or a self-hosted version.
It is a good idea to set up documentation on the CI level for the stage environment and put the JSON file in the public directory. Then you can use online viewers to check the documentation.
Run OpenAPI
node src/cli.ts getopenapijson --output={PATH}
The output is optional.
Usage example:
node src/cli.ts getopenapijson --output='src/public/openApi.json'
CreateUser
The createuser
command creates a new user.
Run CreateUser
node src/cli.ts createuser --email=somemail@gmail.com --password=somePassword --roles=user,admin,someOtherRoles
Only email and password are required.
You are able to update a user as well. You need to specify the email or user ID to find the user and the '--update' flag to allow user updates.
Generate Random Bytes
In some cases, you need a random byte string. This command helps you to generate a random byte string.
Run Generate Random Bytes
node src/cli.ts generateRandomBytes
or
npm run cli generateRandomBytes
Generate TypeScript Types
A special command to generate types for TypeScript.
Run Generate TypeScript Types
node src/cli.ts generateTypes
or
npm run cli generateTypes