From 07aaf74c65469a2800b509a17f83c454567de867 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Thu, 7 Aug 2025 14:19:52 +0530 Subject: [PATCH 1/6] feat: introduce tables commands and deprecate collections commands --- example.php | 2 +- templates/cli/lib/commands/pull.js.twig | 59 +++++++++ templates/cli/lib/commands/push.js.twig | 155 +++++++++++++++++++++++- templates/cli/lib/config.js.twig | 46 +++++++ templates/cli/lib/questions.js.twig | 30 ++++- 5 files changed, 286 insertions(+), 6 deletions(-) diff --git a/example.php b/example.php index 9eafe7b9a..8d5b54b1b 100644 --- a/example.php +++ b/example.php @@ -42,7 +42,7 @@ function getSSLPage($url) { $platform = 'console'; // $platform = 'server'; - $version = '1.7.x'; + $version = '1.8.x'; $spec = getSSLPage("https://raw.githubusercontent.com/appwrite/appwrite/{$version}/app/config/specs/swagger2-{$version}-{$platform}.json"); if(empty($spec)) { diff --git a/templates/cli/lib/commands/pull.js.twig b/templates/cli/lib/commands/pull.js.twig index 89d0beadc..3e449522b 100644 --- a/templates/cli/lib/commands/pull.js.twig +++ b/templates/cli/lib/commands/pull.js.twig @@ -9,6 +9,7 @@ const { projectsGet } = require("./projects"); const { functionsList, functionsGetDeploymentDownload, functionsListDeployments } = require("./functions"); const { sitesList, sitesGetDeploymentDownload, sitesListDeployments } = require("./sites"); const { databasesGet, databasesListCollections, databasesList } = require("./databases"); +const { gridsListDatabases, gridsGetDatabase, gridsListTables } = require("./grids"); const { storageListBuckets } = require("./storage"); const { localConfig } = require("../config"); const { paginate } = require("../paginate"); @@ -336,6 +337,58 @@ const pullCollection = async () => { success(`Successfully pulled ${chalk.bold(total)} collections.`); } +const pullTable = async () => { + log("Fetching tables ..."); + let total = 0; + + const fetchResponse = await gridsListDatabases({ + queries: [JSON.stringify({ method: 'limit', values: [1] })], + parseOutput: false + }); + if (fetchResponse["databases"].length <= 0) { + log("No tables found."); + success(`Successfully pulled ${chalk.bold(total)} tables.`); + return; + } + + let databases = cliConfig.ids; + + if (databases.length === 0) { + if (cliConfig.all) { + databases = (await paginate(gridsListDatabases, { parseOutput: false }, 100, 'databases')).databases.map(database => database.$id); + } else { + databases = (await inquirer.prompt(questionsPullCollection)).databases; + } + } + + for (const databaseId of databases) { + const database = await gridsGetDatabase({ + databaseId, + parseOutput: false + }); + + total++; + log(`Pulling all tables from ${chalk.bold(database['name'])} database ...`); + + localConfig.addDatabase(database); + + const { tables } = await paginate(gridsListTables, { + databaseId, + parseOutput: false + }, 100, 'collections'); + + for (const table of tables) { + localConfig.addTable({ + ...table, + '$createdAt': undefined, + '$updatedAt': undefined + }); + } + } + + success(`Successfully pulled ${chalk.bold(total)} tables.`); +} + const pullBucket = async () => { log("Fetching buckets ..."); let total = 0; @@ -450,6 +503,12 @@ pull .description("Pull your {{ spec.title|caseUcfirst }} collections") .action(actionRunner(pullCollection)) +pull + .command("table") + .alias("tables") + .description("Pull your {{ spec.title|caseUcfirst }} tables") + .action(actionRunner(pullTable)) + pull .command("bucket") .alias("buckets") diff --git a/templates/cli/lib/commands/push.js.twig b/templates/cli/lib/commands/push.js.twig index d52a65fca..fae0ebf4f 100644 --- a/templates/cli/lib/commands/push.js.twig +++ b/templates/cli/lib/commands/push.js.twig @@ -9,7 +9,7 @@ const ID = require("../id"); const { localConfig, globalConfig, KeysAttributes, KeysFunction, KeysSite, whitelistKeys, KeysTopics, KeysStorage, KeysTeams, KeysCollection } = require("../config"); const { Spinner, SPINNER_ARC, SPINNER_DOTS } = require('../spinner'); const { paginate } = require('../paginate'); -const { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsPushSites, questionsGetEntrypoint, questionsPushCollections, questionPushChanges, questionPushChangesConfirmation, questionsPushMessagingTopics, questionsPushResources } = require("../questions"); +const { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsPushSites, questionsGetEntrypoint, questionsPushCollections, questionsPushTables, questionPushChanges, questionPushChangesConfirmation, questionsPushMessagingTopics, questionsPushResources } = require("../questions"); const { cliConfig, actionRunner, success, warn, log, hint, error, commandDescriptions, drawTable } = require("../parser"); const { proxyCreateFunctionRule, proxyCreateSiteRule, proxyListRules } = require('./proxy'); const { consoleVariables } = require('./console'); @@ -49,6 +49,9 @@ const { databasesListIndexes, databasesUpdateCollection } = require("./databases"); +const { + gridsGetDatabase +} = require("./grids"); const { storageGetBucket, storageUpdateBucket, storageCreateBucket } = require("./storage"); @@ -1672,7 +1675,150 @@ const pushFunction = async ({ functionId, async, code, withVariables } = { retur } } +const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) => { + const tables = []; + + if (attempts) { + pollMaxDebounces = attempts; + } + + if (cliConfig.all) { + checkDeployConditions(localConfig); + tables.push(...localConfig.getTables()); + } else { + const answers = await inquirer.prompt(questionsPushTables) + if (answers.tables) { + const configTables = new Map(); + localConfig.getTables().forEach((c) => { + configTables.set(`${c['databaseId']}|${c['$id']}`, c); + }); + answers.tables.forEach((a) => { + const table = configTables.get(a); + tables.push(table); + }) + } + } + + if (tables.length === 0) { + log("No tables found."); + hint("Use 'appwrite pull tables' to synchronize existing one, or use 'appwrite init table' to create a new one."); + return; + } + + const databases = Array.from(new Set(tables.map(table => table['databaseId']))); + + // Parallel db actions + await Promise.all(databases.map(async (databaseId) => { + const localDatabase = localConfig.getDatabase(databaseId); + + try { + const database = await gridsGetDatabase({ + databaseId: databaseId, + parseOutput: false, + }); + + if (database.name !== (localDatabase.name ?? databaseId)) { + await databasesUpdate({ + databaseId: databaseId, + name: localDatabase.name ?? databaseId, + parseOutput: false + }) + + success(`Updated ${localDatabase.name} ( ${databaseId} ) name`); + } + } catch (err) { + log(`Database ${databaseId} not found. Creating it now ...`); + + await databasesCreate({ + databaseId: databaseId, + name: localDatabase.name ?? databaseId, + parseOutput: false, + }); + } + })); + + + if (!(await approveChanges(tables, databasesGetTable, KeysTable, 'tableId', 'tables', ['attributes', 'indexes'], 'databaseId', 'databaseId',))) { + return; + } + // Parallel collection actions + await Promise.all(tables.map(async (table) => { + try { + const remoteTable = await databasesGetTable({ + databaseId: table['databaseId'], + tableId: table['$id'], + parseOutput: false, + }); + + if (remoteTable.name !== table.name) { + await databasesUpdateTable({ + databaseId: table['databaseId'], + tableId: table['$id'], + name: table.name, + name: table.name, + parseOutput: false + }) + + success(`Updated ${table.name} ( ${table['$id']} ) name`); + } + table.remoteVersion = remoteTable; + + table.isExisted = true; + } catch + (e) { + if (Number(e.code) === 404) { + log(`Table ${table.name} does not exist in the project. Creating ... `); + await databasesCreateTable({ + databaseId: table['databaseId'], + tableId: table['$id'], + name: table.name, + documentSecurity: table.documentSecurity, + permissions: table['$permissions'], + parseOutput: false + }) + } else { + throw e; + } + } + })) + let numberOfTables = 0; + // Serialize attribute actions + for (let table of tables) { + let attributes = table.attributes; + let indexes = table.indexes; + + if (table.isExisted) { + attributes = await attributesToCreate(table.remoteVersion.attributes, table.attributes, table); + indexes = await attributesToCreate(table.remoteVersion.indexes, table.indexes, table, true); + + if ((Array.isArray(attributes) && attributes.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) { + continue; + } + + } + + log(`Pushing table ${table.name} ( ${table['databaseId']} - ${table['$id']} ) attributes`) + + try { + await createAttributes(attributes, table) + } catch (e) { + throw e; + } + + try { + await createIndexes(indexes, table); + } catch (e) { + throw e; + } + numberOfTables++; + success(`Successfully pushed ${table.name} ( ${table['$id']} )`); + } + + success(`Successfully pushed ${numberOfTables} tables`); +} + const pushCollection = async ({ returnOnZero, attempts } = { returnOnZero: false }) => { + warn("⚠️ DEPRECATED: Use 'appwrite push table' instead. This command might be removed in the future"); const collections = []; if (attempts) { @@ -2080,6 +2226,13 @@ push .option("--with-variables", `Push site variables.`) .action(actionRunner(pushSite)); +push + .command("table") + .alias("tables") + .description("Push tables in the current project.") + .option(`-a, --attempts `, `Max number of attempts before timing out. default: 30.`) + .action(actionRunner(pushTable)); + push .command("collection") .alias("collections") diff --git a/templates/cli/lib/config.js.twig b/templates/cli/lib/config.js.twig index 548274183..46d7d1585 100644 --- a/templates/cli/lib/config.js.twig +++ b/templates/cli/lib/config.js.twig @@ -9,6 +9,7 @@ const KeysSite = new Set(["path", "$id", "name", "enabled", "logging", "timeout" const KeysFunction = new Set(["path", "$id", "execute", "name", "enabled", "logging", "runtime", "specification", "scopes", "events", "schedule", "timeout", "entrypoint", "commands", "vars"]); const KeysDatabase = new Set(["$id", "name", "enabled"]); const KeysCollection = new Set(["$id", "$permissions", "databaseId", "name", "enabled", "documentSecurity", "attributes", "indexes"]); +const KeysTable = new Set(["$id", "$permissions", "databaseId", "name", "enabled", "documentSecurity", "attributes", "indexes"]); const KeysStorage = new Set(["$id", "$permissions", "fileSecurity", "name", "enabled", "maximumFileSize", "allowedFileExtensions", "compression", "encryption", "antivirus"]); const KeysTopics = new Set(["$id", "name", "subscribe"]); const KeysTeams = new Set(["$id", "name"]); @@ -310,6 +311,50 @@ class Local extends Config { this.set("collections", collections); } + getTables() { + if (!this.has("tables")) { + return []; + } + return this.get("tables"); + } + + getTable($id) { + if (!this.has("tables")) { + return {}; + } + + let tables = this.get("tables"); + for (let i = 0; i < tables.length; i++) { + if (tables[i]['$id'] == $id) { + return tables[i]; + } + } + + return {}; + } + + addTable(props) { + props = whitelistKeys(props, KeysTable, { + attributes: KeysAttributes, + indexes: KeyIndexes + }); + + if (!this.has("tables")) { + this.set("tables", []); + } + + let tables = this.get("tables"); + for (let i = 0; i < tables.length; i++) { + if (tables[i]['$id'] == props['$id'] && tables[i]['databaseId'] == props['databaseId']) { + tables[i] = props; + this.set("tables", tables); + return; + } + } + tables.push(props); + this.set("tables", tables); + } + getBuckets() { if (!this.has("buckets")) { return []; @@ -713,5 +758,6 @@ module.exports = { KeysStorage, KeysTeams, KeysCollection, + KeysTable, whitelistKeys }; diff --git a/templates/cli/lib/questions.js.twig b/templates/cli/lib/questions.js.twig index a9ce99f6e..7574eace7 100644 --- a/templates/cli/lib/questions.js.twig +++ b/templates/cli/lib/questions.js.twig @@ -255,7 +255,7 @@ const questionsPullResources = [ choices: [ { name: `Settings ${chalk.blackBright(`(Project)`)}`, value: 'settings' }, { name: `Functions ${chalk.blackBright(`(Deployment)`)}`, value: 'functions' }, - { name: `Collections ${chalk.blackBright(`(Databases)`)}`, value: 'collections' }, + { name: `Tables ${chalk.blackBright(`(Grids)`)}`, value: 'tables' }, { name: `Buckets ${chalk.blackBright(`(Storage)`)}`, value: 'buckets' }, { name: `Teams ${chalk.blackBright(`(Auth)`)}`, value: 'teams' }, { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: 'messages' } @@ -666,7 +666,7 @@ const questionsPushResources = [ choices: [ { name: `Settings ${chalk.blackBright(`(Project)`)}`, value: 'settings' }, { name: `Functions ${chalk.blackBright(`(Deployment)`)}`, value: 'functions' }, - { name: `Collections ${chalk.blackBright(`(Databases)`)}`, value: 'collections' }, + { name: `Tables ${chalk.blackBright(`(Grids)`)}`, value: 'tables' }, { name: `Buckets ${chalk.blackBright(`(Storage)`)}`, value: 'buckets' }, { name: `Teams ${chalk.blackBright(`(Auth)`)}`, value: 'teams' }, { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: 'messages' } @@ -682,7 +682,7 @@ const questionsInitResources = [ choices: [ { name: 'Function', value: 'function' }, { name: 'Site', value: 'site' }, - { name: 'Collection', value: 'collection' }, + { name: 'Table', value: 'table' }, { name: 'Bucket', value: 'bucket' }, { name: 'Team', value: 'team' }, { name: 'Topic', value: 'message' } @@ -753,6 +753,27 @@ const questionsPushCollections = [ } ]; +const questionsPushTables = [ + { + type: "checkbox", + name: "tables", + message: "Which tables would you like to push?", + validate: (value) => validateRequired('table', value), + when: () => localConfig.getTables().length > 0, + choices: () => { + let tables = localConfig.getTables(); + checkDeployConditions(localConfig) + + return tables.map(table => { + return { + name: `${table.name} (${table['databaseId']} - ${table['$id']})`, + value: `${table['databaseId']}|${table['$id']}` + } + }); + } + } +]; + const questionPushChanges = [ { type: "input", @@ -1002,5 +1023,6 @@ module.exports = { questionsCreateTeam, questionPushChanges, questionPushChangesConfirmation, - questionsCreateSite + questionsCreateSite, + questionsPushTables }; From d69c482135b3141f7c2ca96eb52ce9f0ca587884 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Fri, 8 Aug 2025 14:10:41 +0530 Subject: [PATCH 2/6] finish push pull --- templates/cli/lib/commands/pull.js.twig | 2 +- templates/cli/lib/commands/push.js.twig | 19 ++++++++------- templates/cli/lib/config.js.twig | 31 +++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/templates/cli/lib/commands/pull.js.twig b/templates/cli/lib/commands/pull.js.twig index 3e449522b..c3f49a654 100644 --- a/templates/cli/lib/commands/pull.js.twig +++ b/templates/cli/lib/commands/pull.js.twig @@ -375,7 +375,7 @@ const pullTable = async () => { const { tables } = await paginate(gridsListTables, { databaseId, parseOutput: false - }, 100, 'collections'); + }, 100, 'tables'); for (const table of tables) { localConfig.addTable({ diff --git a/templates/cli/lib/commands/push.js.twig b/templates/cli/lib/commands/push.js.twig index fae0ebf4f..888a2464d 100644 --- a/templates/cli/lib/commands/push.js.twig +++ b/templates/cli/lib/commands/push.js.twig @@ -6,7 +6,7 @@ const inquirer = require("inquirer"); const JSONbig = require("json-bigint")({ storeAsString: false }); const { Command } = require("commander"); const ID = require("../id"); -const { localConfig, globalConfig, KeysAttributes, KeysFunction, KeysSite, whitelistKeys, KeysTopics, KeysStorage, KeysTeams, KeysCollection } = require("../config"); +const { localConfig, globalConfig, KeysAttributes, KeysFunction, KeysSite, whitelistKeys, KeysTopics, KeysStorage, KeysTeams, KeysCollection, KeysTable } = require("../config"); const { Spinner, SPINNER_ARC, SPINNER_DOTS } = require('../spinner'); const { paginate } = require('../paginate'); const { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsPushSites, questionsGetEntrypoint, questionsPushCollections, questionsPushTables, questionPushChanges, questionPushChangesConfirmation, questionsPushMessagingTopics, questionsPushResources } = require("../questions"); @@ -50,7 +50,8 @@ const { databasesUpdateCollection } = require("./databases"); const { - gridsGetDatabase + gridsGetDatabase, + gridsGetTable } = require("./grids"); const { storageGetBucket, storageUpdateBucket, storageCreateBucket @@ -1738,13 +1739,13 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) = })); - if (!(await approveChanges(tables, databasesGetTable, KeysTable, 'tableId', 'tables', ['attributes', 'indexes'], 'databaseId', 'databaseId',))) { + if (!(await approveChanges(tables, gridsGetTable, KeysTable, 'tableId', 'tables', ['columns', 'indexes'], 'databaseId', 'databaseId',))) { return; } // Parallel collection actions await Promise.all(tables.map(async (table) => { try { - const remoteTable = await databasesGetTable({ + const remoteTable = await gridsGetTable({ databaseId: table['databaseId'], tableId: table['$id'], parseOutput: false, @@ -1784,14 +1785,14 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) = let numberOfTables = 0; // Serialize attribute actions for (let table of tables) { - let attributes = table.attributes; + let columns = table.columns; let indexes = table.indexes; if (table.isExisted) { - attributes = await attributesToCreate(table.remoteVersion.attributes, table.attributes, table); + columns = await attributesToCreate(table.remoteVersion.columns, table.columns, table); indexes = await attributesToCreate(table.remoteVersion.indexes, table.indexes, table, true); - if ((Array.isArray(attributes) && attributes.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) { + if ((Array.isArray(columns) && columns.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) { continue; } @@ -1800,7 +1801,7 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) = log(`Pushing table ${table.name} ( ${table['databaseId']} - ${table['$id']} ) attributes`) try { - await createAttributes(attributes, table) + await createAttributes(columns, table) } catch (e) { throw e; } @@ -1881,7 +1882,7 @@ const pushCollection = async ({ returnOnZero, attempts } = { returnOnZero: false })); - if (!(await approveChanges(collections, databasesGetCollection, KeysCollection, 'collectionId', 'collections', ['attributes', 'indexes'], 'databaseId', 'databaseId',))) { + if (!(await approveChanges(collections, databasesGetCollection, KeysCollection, 'collectionId', 'collections', ['columns', 'indexes'], 'databaseId', 'databaseId',))) { return; } // Parallel collection actions diff --git a/templates/cli/lib/config.js.twig b/templates/cli/lib/config.js.twig index 46d7d1585..326a217ae 100644 --- a/templates/cli/lib/config.js.twig +++ b/templates/cli/lib/config.js.twig @@ -9,7 +9,7 @@ const KeysSite = new Set(["path", "$id", "name", "enabled", "logging", "timeout" const KeysFunction = new Set(["path", "$id", "execute", "name", "enabled", "logging", "runtime", "specification", "scopes", "events", "schedule", "timeout", "entrypoint", "commands", "vars"]); const KeysDatabase = new Set(["$id", "name", "enabled"]); const KeysCollection = new Set(["$id", "$permissions", "databaseId", "name", "enabled", "documentSecurity", "attributes", "indexes"]); -const KeysTable = new Set(["$id", "$permissions", "databaseId", "name", "enabled", "documentSecurity", "attributes", "indexes"]); +const KeysTable = new Set(["$id", "$permissions", "databaseId", "name", "enabled", "documentSecurity", "columns", "indexes"]); const KeysStorage = new Set(["$id", "$permissions", "fileSecurity", "name", "enabled", "maximumFileSize", "allowedFileExtensions", "compression", "encryption", "antivirus"]); const KeysTopics = new Set(["$id", "name", "subscribe"]); const KeysTeams = new Set(["$id", "name"]); @@ -40,6 +40,33 @@ const KeysAttributes = new Set([ // Strings "encrypt", ]); +const KeysColumns = new Set([ + "key", + "type", + "required", + "array", + "size", + "default", + // integer and float + "min", + "max", + // email, enum, URL, IP, and datetime + "format", + // enum + "elements", + // relationship + "relatedCollection", + "relationType", + "twoWay", + "twoWayKey", + "onDelete", + "side", + // Indexes + "attributes", + "orders", + // Strings + "encrypt", +]); const KeyIndexes = new Set(["key", "type", "status", "attributes", "orders"]); function whitelistKeys(value, keys, nestedKeys = {}) { @@ -335,7 +362,7 @@ class Local extends Config { addTable(props) { props = whitelistKeys(props, KeysTable, { - attributes: KeysAttributes, + columns: KeysColumns, indexes: KeyIndexes }); From 96c8dadc56398b53fb170c47238e681519f7df32 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Fri, 8 Aug 2025 14:24:07 +0530 Subject: [PATCH 3/6] fix: warnings --- templates/cli/lib/client.js.twig | 5 ----- templates/cli/lib/commands/pull.js.twig | 5 +++-- templates/cli/lib/commands/push.js.twig | 18 +++++++++--------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/templates/cli/lib/client.js.twig b/templates/cli/lib/client.js.twig index 110673e73..44c06630b 100644 --- a/templates/cli/lib/client.js.twig +++ b/templates/cli/lib/client.js.twig @@ -136,11 +136,6 @@ class Client { }, }), }); - - const warnings = response.headers.get('x-{{ spec.title | lower }}-warning'); - if (warnings) { - warnings.split(';').forEach((warning) => console.log(`${chalk.yellow.bold("ℹ Warning:")} ${chalk.yellow(warning)}`)); - } } catch (error) { throw new {{spec.title | caseUcfirst}}Exception(error.message); } diff --git a/templates/cli/lib/commands/pull.js.twig b/templates/cli/lib/commands/pull.js.twig index c3f49a654..40262a6c3 100644 --- a/templates/cli/lib/commands/pull.js.twig +++ b/templates/cli/lib/commands/pull.js.twig @@ -21,7 +21,7 @@ const pullResources = async () => { settings: pullSettings, functions: pullFunctions, sites: pullSites, - collections: pullCollection, + tables: pullTable, buckets: pullBucket, teams: pullTeam, messages: pullMessagingTopic @@ -286,6 +286,7 @@ const pullSites = async ({ code, withVariables }) => { } const pullCollection = async () => { + warn("appwrite push collection has been deprecated. Please consider using 'appwrite push tables' instead"); log("Fetching collections ..."); let total = 0; @@ -500,7 +501,7 @@ pull pull .command("collection") .alias("collections") - .description("Pull your {{ spec.title|caseUcfirst }} collections") + .description("Pull your {{ spec.title|caseUcfirst }} collections (deprecated, please use 'pull tables' instead)") .action(actionRunner(pullCollection)) pull diff --git a/templates/cli/lib/commands/push.js.twig b/templates/cli/lib/commands/push.js.twig index 888a2464d..31b91be6c 100644 --- a/templates/cli/lib/commands/push.js.twig +++ b/templates/cli/lib/commands/push.js.twig @@ -1819,7 +1819,7 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) = } const pushCollection = async ({ returnOnZero, attempts } = { returnOnZero: false }) => { - warn("⚠️ DEPRECATED: Use 'appwrite push table' instead. This command might be removed in the future"); + warn("appwrite push collection has been deprecated. Please consider using 'appwrite push tables' instead"); const collections = []; if (attempts) { @@ -1882,7 +1882,7 @@ const pushCollection = async ({ returnOnZero, attempts } = { returnOnZero: false })); - if (!(await approveChanges(collections, databasesGetCollection, KeysCollection, 'collectionId', 'collections', ['columns', 'indexes'], 'databaseId', 'databaseId',))) { + if (!(await approveChanges(collections, databasesGetCollection, KeysCollection, 'collectionId', 'collections', ['attributes', 'indexes'], 'databaseId', 'databaseId',))) { return; } // Parallel collection actions @@ -2227,6 +2227,13 @@ push .option("--with-variables", `Push site variables.`) .action(actionRunner(pushSite)); +push + .command("collection") + .alias("collections") + .description("Push collections in the current project. (deprecated, please use 'push tables' instead)") + .option(`-a, --attempts `, `Max number of attempts before timing out. default: 30.`) + .action(actionRunner(pushCollection)); + push .command("table") .alias("tables") @@ -2234,13 +2241,6 @@ push .option(`-a, --attempts `, `Max number of attempts before timing out. default: 30.`) .action(actionRunner(pushTable)); -push - .command("collection") - .alias("collections") - .description("Push collections in the current project.") - .option(`-a, --attempts `, `Max number of attempts before timing out. default: 30.`) - .action(actionRunner(pushCollection)); - push .command("bucket") .alias("buckets") From 8401fbbaf881de67c9709e691e35f57bcaae0043 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 11 Aug 2025 13:35:37 +0530 Subject: [PATCH 4/6] chore: add collections option as well at bottom --- templates/cli/lib/commands/pull.js.twig | 1 + templates/cli/lib/commands/push.js.twig | 1 + templates/cli/lib/questions.js.twig | 6 ++++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/templates/cli/lib/commands/pull.js.twig b/templates/cli/lib/commands/pull.js.twig index 40262a6c3..c3ea68fb9 100644 --- a/templates/cli/lib/commands/pull.js.twig +++ b/templates/cli/lib/commands/pull.js.twig @@ -21,6 +21,7 @@ const pullResources = async () => { settings: pullSettings, functions: pullFunctions, sites: pullSites, + collections: pullCollection, tables: pullTable, buckets: pullBucket, teams: pullTeam, diff --git a/templates/cli/lib/commands/push.js.twig b/templates/cli/lib/commands/push.js.twig index 31b91be6c..87a7b5f5e 100644 --- a/templates/cli/lib/commands/push.js.twig +++ b/templates/cli/lib/commands/push.js.twig @@ -923,6 +923,7 @@ const pushResources = async () => { functions: pushFunction, sites: pushSite, collections: pushCollection, + tables: pushTable, buckets: pushBucket, teams: pushTeam, messages: pushMessagingTopic diff --git a/templates/cli/lib/questions.js.twig b/templates/cli/lib/questions.js.twig index 7574eace7..411702941 100644 --- a/templates/cli/lib/questions.js.twig +++ b/templates/cli/lib/questions.js.twig @@ -258,7 +258,8 @@ const questionsPullResources = [ { name: `Tables ${chalk.blackBright(`(Grids)`)}`, value: 'tables' }, { name: `Buckets ${chalk.blackBright(`(Storage)`)}`, value: 'buckets' }, { name: `Teams ${chalk.blackBright(`(Auth)`)}`, value: 'teams' }, - { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: 'messages' } + { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: 'messages' }, + { name: `Collections ${chalk.blackBright(`(Database)`)}`, value: 'collections' } ] } ] @@ -669,7 +670,8 @@ const questionsPushResources = [ { name: `Tables ${chalk.blackBright(`(Grids)`)}`, value: 'tables' }, { name: `Buckets ${chalk.blackBright(`(Storage)`)}`, value: 'buckets' }, { name: `Teams ${chalk.blackBright(`(Auth)`)}`, value: 'teams' }, - { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: 'messages' } + { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: 'messages' }, + { name: `Collections ${chalk.blackBright(`(Database)`)}`, value: 'collections' } ] } ]; From b605a163f102fd085777f7ebecaf1b71c1b85657 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 11 Aug 2025 13:37:04 +0530 Subject: [PATCH 5/6] fix warning --- templates/cli/lib/commands/pull.js.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/cli/lib/commands/pull.js.twig b/templates/cli/lib/commands/pull.js.twig index c3ea68fb9..612a566ea 100644 --- a/templates/cli/lib/commands/pull.js.twig +++ b/templates/cli/lib/commands/pull.js.twig @@ -287,7 +287,7 @@ const pullSites = async ({ code, withVariables }) => { } const pullCollection = async () => { - warn("appwrite push collection has been deprecated. Please consider using 'appwrite push tables' instead"); + warn("appwrite pull collection has been deprecated. Please consider using 'appwrite pull tables' instead"); log("Fetching collections ..."); let total = 0; From b5da13b6b3306dd509271dfd63783a73e504c579 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 11 Aug 2025 14:14:30 +0530 Subject: [PATCH 6/6] add missing --- templates/cli/lib/questions.js.twig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/cli/lib/questions.js.twig b/templates/cli/lib/questions.js.twig index 411702941..6b9df0e80 100644 --- a/templates/cli/lib/questions.js.twig +++ b/templates/cli/lib/questions.js.twig @@ -687,7 +687,8 @@ const questionsInitResources = [ { name: 'Table', value: 'table' }, { name: 'Bucket', value: 'bucket' }, { name: 'Team', value: 'team' }, - { name: 'Topic', value: 'message' } + { name: 'Topic', value: 'message' }, + { name: 'Collection', value: 'collection' } ] } ];