UNPKG

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.

120 lines (119 loc) 6.05 kB
import { Databases, Query } from "node-appwrite"; import { createOrUpdateAttribute } from "../collections/attributes.js"; import { getMigrationCollectionSchemas } from "../storage/schemas.js"; import { areCollectionNamesSame, delay, toCamelCase, tryAwaitWithRetry, } from "../utils/index.js"; import {} from "appwrite-utils"; import { ulid } from "ulidx"; export const setupMigrationDatabase = async (config) => { if (!config.useMigrations) { console.log("Migrations database disabled, skipping setup"); return; } console.log("---------------------------------"); console.log("Starting Migrations Setup"); console.log("---------------------------------"); const database = new Databases(config.appwriteClient); if (!config.appwriteClient) { throw new Error("Appwrite client is not initialized in the config"); } let db; const migrationCollectionsSetup = getMigrationCollectionSchemas(); try { db = await tryAwaitWithRetry(async () => await database.get("migrations"), undefined, true); console.log("Migrations database found"); } catch (e) { db = await tryAwaitWithRetry(async () => await database.create("migrations", "Migrations", true)); console.log("Migrations database created"); } if (!db) { console.error("Failed to create or retrieve the migrations database"); return; } for (const [collectionName, { collection, attributes }] of Object.entries(migrationCollectionsSetup)) { const collectionId = toCamelCase(collectionName); let collectionFound; try { collectionFound = await tryAwaitWithRetry(async () => await database.getCollection(db.$id, collectionId), undefined, true); console.log(`Collection found: ${collectionId}`); } catch (e) { console.log(`Collection not found: ${collectionId}`); try { collectionFound = await tryAwaitWithRetry(async () => await database.createCollection(db.$id, collectionId, collectionName, undefined, collection.documentSecurity, collection.enabled), undefined, true); console.log(`Collection created: ${collectionId}`); } catch (createError) { console.error(`Failed to create collection: ${collectionId}`, createError); continue; } } if (!collectionFound) { console.error(`Failed to create or retrieve collection: ${collectionId}`); continue; } for (const attribute of attributes) { try { await createOrUpdateAttribute(database, db.$id, collectionFound, attribute); await delay(100); console.log(`Attribute created/updated: ${attribute.key}`); } catch (attrError) { console.error(`Failed to create/update attribute: ${attribute.key}`, attrError); } } } console.log("---------------------------------"); console.log("Migrations Setup Complete"); console.log("---------------------------------"); }; export const ensureDatabasesExist = async (config, databasesToEnsure) => { if (!config.appwriteClient) { throw new Error("Appwrite client is not initialized in the config"); } const database = new Databases(config.appwriteClient); const databasesToCreate = databasesToEnsure || config.databases || []; if (!databasesToCreate.length) { console.log("No databases to create"); return; } const existingDatabases = await tryAwaitWithRetry(async () => await database.list([Query.limit(500)])); const migrationsDatabase = existingDatabases.databases.find((d) => d.name.toLowerCase().trim().replace(" ", "") === "migrations"); if (config.useMigrations && existingDatabases.databases.length !== 0 && migrationsDatabase) { console.log("Creating all databases including migrations"); databasesToCreate.push(migrationsDatabase); } for (const db of databasesToCreate) { if (!existingDatabases.databases.some((d) => d.name === db.name)) { await tryAwaitWithRetry(async () => await database.create(db.$id || ulid(), db.name, true)); console.log(`${db.name} database created`); } } }; export const wipeOtherDatabases = async (database, databasesToKeep, useMigrations = true) => { console.log(`Databases to keep: ${databasesToKeep.map(db => db.name).join(", ")}`); const allDatabases = await tryAwaitWithRetry(async () => await database.list([Query.limit(500)])); const migrationsDatabase = allDatabases.databases.find((d) => d.name.toLowerCase().trim().replace(" ", "") === "migrations"); if (useMigrations && allDatabases.databases.length !== 0 && migrationsDatabase) { console.log("Wiping all databases except migrations"); databasesToKeep.push(migrationsDatabase); } for (const db of allDatabases.databases) { if (!databasesToKeep.some((d) => d.name === db.name)) { await tryAwaitWithRetry(async () => await database.delete(db.$id)); console.log(`Deleted database: ${db.name}`); } } }; export const ensureCollectionsExist = async (config, database, collectionsToEnsure) => { const databaseClient = new Databases(config.appwriteClient); const collectionsToCreate = collectionsToEnsure || (config.collections ? config.collections : []); const existingCollections = await tryAwaitWithRetry(async () => await databaseClient.listCollections(database.$id, [Query.limit(500)])); for (const collection of collectionsToCreate) { if (!existingCollections.collections.some((c) => c.name === collection.name)) { await tryAwaitWithRetry(async () => await databaseClient.createCollection(database.$id, ulid(), collection.name, undefined, true, true)); console.log(`${collection.name} collection created in ${database.name}`); } } };