appwrite-utils-cli
Version:
Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.
170 lines (169 loc) • 8.08 kB
JavaScript
import inquirer from "inquirer";
import path from "path";
import chalk from "chalk";
import { MessageFormatter } from "../../shared/messageFormatter.js";
import { SchemaGenerator } from "../../shared/schemaGenerator.js";
import { setupDirsFiles } from "../../utils/setupFiles.js";
import { fetchAllDatabases } from "../../databases/methods.js";
export const schemaCommands = {
async generateSchemas(cli) {
MessageFormatter.progress("Generating schemas...", { prefix: "Schemas" });
// Prompt user for schema type preference
const { schemaType } = await inquirer.prompt([
{
type: "list",
name: "schemaType",
message: "What type of schemas would you like to generate?",
choices: [
{ name: "TypeScript (Zod) schemas", value: "zod" },
{ name: "JSON schemas", value: "json" },
{ name: "Python (Pydantic) models", value: "pydantic" },
{ name: "TypeScript + JSON", value: "both" },
{ name: "All (Zod, JSON, Pydantic)", value: "all" },
],
default: "all",
},
]);
// Get the config folder path (where the config file is located)
const configFolderPath = cli.controller.getAppwriteFolderPath();
if (!configFolderPath) {
MessageFormatter.error("Failed to get config folder path", undefined, { prefix: "Schemas" });
return;
}
// Prompt for schema output directory (optional override)
const defaultSchemaOut = path.join(configFolderPath, cli.controller.config?.schemaConfig?.outputDirectory || 'schemas');
const { schemaOutDir } = await inquirer.prompt([
{
type: 'input',
name: 'schemaOutDir',
message: 'Output directory for schemas:',
default: defaultSchemaOut,
validate: (input) => input && input.trim().length > 0 ? true : 'Please provide an output directory',
}
]);
// Create SchemaGenerator with the correct base path and generate schemas
const schemaGenerator = new SchemaGenerator(cli.controller.config, configFolderPath);
const outDirRel = path.isAbsolute(schemaOutDir) ? schemaOutDir : path.relative(configFolderPath, schemaOutDir);
await schemaGenerator.generateSchemas({ format: schemaType, verbose: true, outputDir: outDirRel });
MessageFormatter.success("Schema generation completed", { prefix: "Schemas" });
},
async generateConstants(cli) {
MessageFormatter.progress("Generating cross-language constants...", { prefix: "Constants" });
if (!cli.controller?.config) {
MessageFormatter.error("No configuration found", undefined, { prefix: "Constants" });
return;
}
// Prompt for languages
const { languages } = await inquirer.prompt([
{
type: "checkbox",
name: "languages",
message: "Select languages for constants generation:",
choices: [
{ name: "TypeScript", value: "typescript", checked: true },
{ name: "JavaScript", value: "javascript" },
{ name: "Python", value: "python" },
{ name: "PHP", value: "php" },
{ name: "Dart", value: "dart" },
{ name: "JSON", value: "json" },
{ name: "Environment Variables", value: "env" },
],
validate: (input) => {
if (input.length === 0) {
return "Please select at least one language";
}
return true;
},
},
]);
// Prompt for which constants to include
const { includeWhat } = await inquirer.prompt([
{
type: 'checkbox',
name: 'includeWhat',
message: 'Select which constants to generate:',
choices: [
{ name: 'Databases', value: 'databases', checked: true },
{ name: 'Collections/Tables', value: 'collections', checked: true },
{ name: 'Buckets', value: 'buckets', checked: true },
{ name: 'Functions', value: 'functions', checked: true },
],
validate: (input) => input.length > 0 ? true : 'Select at least one category',
}
]);
// Determine default output directory based on config location
const configPath = cli.controller.getAppwriteFolderPath();
const defaultOutputDir = configPath
? path.join(configPath, "constants")
: path.join(process.cwd(), "constants");
// Prompt for output directory
const { outputDir } = await inquirer.prompt([
{
type: "input",
name: "outputDir",
message: "Output directory for constants files:",
default: defaultOutputDir,
validate: (input) => {
if (!input.trim()) {
return "Output directory cannot be empty";
}
return true;
},
},
]);
try {
const { ConstantsGenerator } = await import("../../utils/constantsGenerator.js");
const generator = new ConstantsGenerator(cli.controller.config);
const include = {
databases: includeWhat.includes('databases'),
collections: includeWhat.includes('collections'),
buckets: includeWhat.includes('buckets'),
functions: includeWhat.includes('functions'),
};
MessageFormatter.info(`Generating constants for: ${languages.join(", ")}`, { prefix: "Constants" });
await generator.generateFiles(languages, outputDir, include);
MessageFormatter.success(`Constants generated in ${outputDir}`, { prefix: "Constants" });
}
catch (error) {
MessageFormatter.error("Failed to generate constants", error instanceof Error ? error : new Error(String(error)), { prefix: "Constants" });
}
},
async importData(cli) {
MessageFormatter.progress("Importing data...", { prefix: "Import" });
const { doBackup } = await inquirer.prompt([
{
type: "confirm",
name: "doBackup",
message: "Do you want to perform a backup before importing?",
default: true,
},
]);
const databases = await cli.selectDatabases(await fetchAllDatabases(cli.controller.database), "Select databases to import data into:", true);
const collections = await cli.selectCollectionsAndTables(databases[0], cli.controller.database, "Select collections/tables to import data into (leave empty for all):", true);
const { shouldWriteFile } = await inquirer.prompt([
{
type: "confirm",
name: "shouldWriteFile",
message: "Do you want to write the imported data to a file?",
default: false,
},
]);
const options = {
databases,
collections: collections.map((c) => c.name),
doBackup,
importData: true,
shouldWriteFile,
};
try {
await cli.controller.importData(options);
MessageFormatter.success("Data import completed successfully", { prefix: "Import" });
}
catch (error) {
MessageFormatter.error("Error importing data", error instanceof Error ? error : new Error(String(error)), { prefix: "Import" });
}
},
async setupDirsFiles(cli, withExampleData = false) {
await setupDirsFiles(withExampleData, cli.currentDir);
}
};