Skip to content

Commit 51dac6e

Browse files
authored
Merge pull request #1140 from appwrite/feat-tables-commands
feat: introduce tables commands and deprecate collections commands
2 parents 81509c3 + b5da13b commit 51dac6e

File tree

5 files changed

+325
-16
lines changed

5 files changed

+325
-16
lines changed

templates/cli/lib/client.js.twig

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,6 @@ class Client {
136136
},
137137
}),
138138
});
139-
140-
const warnings = response.headers.get('x-{{ spec.title | lower }}-warning');
141-
if (warnings) {
142-
warnings.split(';').forEach((warning) => console.log(`${chalk.yellow.bold("ℹ Warning:")} ${chalk.yellow(warning)}`));
143-
}
144139
} catch (error) {
145140
throw new {{spec.title | caseUcfirst}}Exception(error.message);
146141
}

templates/cli/lib/commands/pull.js.twig

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const { projectsGet } = require("./projects");
99
const { functionsList, functionsGetDeploymentDownload, functionsListDeployments } = require("./functions");
1010
const { sitesList, sitesGetDeploymentDownload, sitesListDeployments } = require("./sites");
1111
const { databasesGet, databasesListCollections, databasesList } = require("./databases");
12+
const { gridsListDatabases, gridsGetDatabase, gridsListTables } = require("./grids");
1213
const { storageListBuckets } = require("./storage");
1314
const { localConfig } = require("../config");
1415
const { paginate } = require("../paginate");
@@ -21,6 +22,7 @@ const pullResources = async () => {
2122
functions: pullFunctions,
2223
sites: pullSites,
2324
collections: pullCollection,
25+
tables: pullTable,
2426
buckets: pullBucket,
2527
teams: pullTeam,
2628
messages: pullMessagingTopic
@@ -285,6 +287,7 @@ const pullSites = async ({ code, withVariables }) => {
285287
}
286288

287289
const pullCollection = async () => {
290+
warn("appwrite pull collection has been deprecated. Please consider using 'appwrite pull tables' instead");
288291
log("Fetching collections ...");
289292
let total = 0;
290293

@@ -336,6 +339,58 @@ const pullCollection = async () => {
336339
success(`Successfully pulled ${chalk.bold(total)} collections.`);
337340
}
338341

342+
const pullTable = async () => {
343+
log("Fetching tables ...");
344+
let total = 0;
345+
346+
const fetchResponse = await gridsListDatabases({
347+
queries: [JSON.stringify({ method: 'limit', values: [1] })],
348+
parseOutput: false
349+
});
350+
if (fetchResponse["databases"].length <= 0) {
351+
log("No tables found.");
352+
success(`Successfully pulled ${chalk.bold(total)} tables.`);
353+
return;
354+
}
355+
356+
let databases = cliConfig.ids;
357+
358+
if (databases.length === 0) {
359+
if (cliConfig.all) {
360+
databases = (await paginate(gridsListDatabases, { parseOutput: false }, 100, 'databases')).databases.map(database => database.$id);
361+
} else {
362+
databases = (await inquirer.prompt(questionsPullCollection)).databases;
363+
}
364+
}
365+
366+
for (const databaseId of databases) {
367+
const database = await gridsGetDatabase({
368+
databaseId,
369+
parseOutput: false
370+
});
371+
372+
total++;
373+
log(`Pulling all tables from ${chalk.bold(database['name'])} database ...`);
374+
375+
localConfig.addDatabase(database);
376+
377+
const { tables } = await paginate(gridsListTables, {
378+
databaseId,
379+
parseOutput: false
380+
}, 100, 'tables');
381+
382+
for (const table of tables) {
383+
localConfig.addTable({
384+
...table,
385+
'$createdAt': undefined,
386+
'$updatedAt': undefined
387+
});
388+
}
389+
}
390+
391+
success(`Successfully pulled ${chalk.bold(total)} tables.`);
392+
}
393+
339394
const pullBucket = async () => {
340395
log("Fetching buckets ...");
341396
let total = 0;
@@ -447,9 +502,15 @@ pull
447502
pull
448503
.command("collection")
449504
.alias("collections")
450-
.description("Pull your {{ spec.title|caseUcfirst }} collections")
505+
.description("Pull your {{ spec.title|caseUcfirst }} collections (deprecated, please use 'pull tables' instead)")
451506
.action(actionRunner(pullCollection))
452507

508+
pull
509+
.command("table")
510+
.alias("tables")
511+
.description("Pull your {{ spec.title|caseUcfirst }} tables")
512+
.action(actionRunner(pullTable))
513+
453514
pull
454515
.command("bucket")
455516
.alias("buckets")

templates/cli/lib/commands/push.js.twig

Lines changed: 158 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ const inquirer = require("inquirer");
66
const JSONbig = require("json-bigint")({ storeAsString: false });
77
const { Command } = require("commander");
88
const ID = require("../id");
9-
const { localConfig, globalConfig, KeysAttributes, KeysFunction, KeysSite, whitelistKeys, KeysTopics, KeysStorage, KeysTeams, KeysCollection } = require("../config");
9+
const { localConfig, globalConfig, KeysAttributes, KeysFunction, KeysSite, whitelistKeys, KeysTopics, KeysStorage, KeysTeams, KeysCollection, KeysTable } = require("../config");
1010
const { Spinner, SPINNER_ARC, SPINNER_DOTS } = require('../spinner');
1111
const { paginate } = require('../paginate');
12-
const { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsPushSites, questionsGetEntrypoint, questionsPushCollections, questionPushChanges, questionPushChangesConfirmation, questionsPushMessagingTopics, questionsPushResources } = require("../questions");
12+
const { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsPushSites, questionsGetEntrypoint, questionsPushCollections, questionsPushTables, questionPushChanges, questionPushChangesConfirmation, questionsPushMessagingTopics, questionsPushResources } = require("../questions");
1313
const { cliConfig, actionRunner, success, warn, log, hint, error, commandDescriptions, drawTable } = require("../parser");
1414
const { proxyCreateFunctionRule, proxyCreateSiteRule, proxyListRules } = require('./proxy');
1515
const { consoleVariables } = require('./console');
@@ -49,6 +49,10 @@ const {
4949
databasesListIndexes,
5050
databasesUpdateCollection
5151
} = require("./databases");
52+
const {
53+
gridsGetDatabase,
54+
gridsGetTable
55+
} = require("./grids");
5256
const {
5357
storageGetBucket, storageUpdateBucket, storageCreateBucket
5458
} = require("./storage");
@@ -919,6 +923,7 @@ const pushResources = async () => {
919923
functions: pushFunction,
920924
sites: pushSite,
921925
collections: pushCollection,
926+
tables: pushTable,
922927
buckets: pushBucket,
923928
teams: pushTeam,
924929
messages: pushMessagingTopic
@@ -1672,7 +1677,150 @@ const pushFunction = async ({ functionId, async, code, withVariables } = { retur
16721677
}
16731678
}
16741679

1680+
const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) => {
1681+
const tables = [];
1682+
1683+
if (attempts) {
1684+
pollMaxDebounces = attempts;
1685+
}
1686+
1687+
if (cliConfig.all) {
1688+
checkDeployConditions(localConfig);
1689+
tables.push(...localConfig.getTables());
1690+
} else {
1691+
const answers = await inquirer.prompt(questionsPushTables)
1692+
if (answers.tables) {
1693+
const configTables = new Map();
1694+
localConfig.getTables().forEach((c) => {
1695+
configTables.set(`${c['databaseId']}|${c['$id']}`, c);
1696+
});
1697+
answers.tables.forEach((a) => {
1698+
const table = configTables.get(a);
1699+
tables.push(table);
1700+
})
1701+
}
1702+
}
1703+
1704+
if (tables.length === 0) {
1705+
log("No tables found.");
1706+
hint("Use 'appwrite pull tables' to synchronize existing one, or use 'appwrite init table' to create a new one.");
1707+
return;
1708+
}
1709+
1710+
const databases = Array.from(new Set(tables.map(table => table['databaseId'])));
1711+
1712+
// Parallel db actions
1713+
await Promise.all(databases.map(async (databaseId) => {
1714+
const localDatabase = localConfig.getDatabase(databaseId);
1715+
1716+
try {
1717+
const database = await gridsGetDatabase({
1718+
databaseId: databaseId,
1719+
parseOutput: false,
1720+
});
1721+
1722+
if (database.name !== (localDatabase.name ?? databaseId)) {
1723+
await databasesUpdate({
1724+
databaseId: databaseId,
1725+
name: localDatabase.name ?? databaseId,
1726+
parseOutput: false
1727+
})
1728+
1729+
success(`Updated ${localDatabase.name} ( ${databaseId} ) name`);
1730+
}
1731+
} catch (err) {
1732+
log(`Database ${databaseId} not found. Creating it now ...`);
1733+
1734+
await databasesCreate({
1735+
databaseId: databaseId,
1736+
name: localDatabase.name ?? databaseId,
1737+
parseOutput: false,
1738+
});
1739+
}
1740+
}));
1741+
1742+
1743+
if (!(await approveChanges(tables, gridsGetTable, KeysTable, 'tableId', 'tables', ['columns', 'indexes'], 'databaseId', 'databaseId',))) {
1744+
return;
1745+
}
1746+
// Parallel collection actions
1747+
await Promise.all(tables.map(async (table) => {
1748+
try {
1749+
const remoteTable = await gridsGetTable({
1750+
databaseId: table['databaseId'],
1751+
tableId: table['$id'],
1752+
parseOutput: false,
1753+
});
1754+
1755+
if (remoteTable.name !== table.name) {
1756+
await databasesUpdateTable({
1757+
databaseId: table['databaseId'],
1758+
tableId: table['$id'],
1759+
name: table.name,
1760+
name: table.name,
1761+
parseOutput: false
1762+
})
1763+
1764+
success(`Updated ${table.name} ( ${table['$id']} ) name`);
1765+
}
1766+
table.remoteVersion = remoteTable;
1767+
1768+
table.isExisted = true;
1769+
} catch
1770+
(e) {
1771+
if (Number(e.code) === 404) {
1772+
log(`Table ${table.name} does not exist in the project. Creating ... `);
1773+
await databasesCreateTable({
1774+
databaseId: table['databaseId'],
1775+
tableId: table['$id'],
1776+
name: table.name,
1777+
documentSecurity: table.documentSecurity,
1778+
permissions: table['$permissions'],
1779+
parseOutput: false
1780+
})
1781+
} else {
1782+
throw e;
1783+
}
1784+
}
1785+
}))
1786+
let numberOfTables = 0;
1787+
// Serialize attribute actions
1788+
for (let table of tables) {
1789+
let columns = table.columns;
1790+
let indexes = table.indexes;
1791+
1792+
if (table.isExisted) {
1793+
columns = await attributesToCreate(table.remoteVersion.columns, table.columns, table);
1794+
indexes = await attributesToCreate(table.remoteVersion.indexes, table.indexes, table, true);
1795+
1796+
if ((Array.isArray(columns) && columns.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) {
1797+
continue;
1798+
}
1799+
1800+
}
1801+
1802+
log(`Pushing table ${table.name} ( ${table['databaseId']} - ${table['$id']} ) attributes`)
1803+
1804+
try {
1805+
await createAttributes(columns, table)
1806+
} catch (e) {
1807+
throw e;
1808+
}
1809+
1810+
try {
1811+
await createIndexes(indexes, table);
1812+
} catch (e) {
1813+
throw e;
1814+
}
1815+
numberOfTables++;
1816+
success(`Successfully pushed ${table.name} ( ${table['$id']} )`);
1817+
}
1818+
1819+
success(`Successfully pushed ${numberOfTables} tables`);
1820+
}
1821+
16751822
const pushCollection = async ({ returnOnZero, attempts } = { returnOnZero: false }) => {
1823+
warn("appwrite push collection has been deprecated. Please consider using 'appwrite push tables' instead");
16761824
const collections = [];
16771825

16781826
if (attempts) {
@@ -2083,10 +2231,17 @@ push
20832231
push
20842232
.command("collection")
20852233
.alias("collections")
2086-
.description("Push collections in the current project.")
2234+
.description("Push collections in the current project. (deprecated, please use 'push tables' instead)")
20872235
.option(`-a, --attempts <numberOfAttempts>`, `Max number of attempts before timing out. default: 30.`)
20882236
.action(actionRunner(pushCollection));
20892237

2238+
push
2239+
.command("table")
2240+
.alias("tables")
2241+
.description("Push tables in the current project.")
2242+
.option(`-a, --attempts <numberOfAttempts>`, `Max number of attempts before timing out. default: 30.`)
2243+
.action(actionRunner(pushTable));
2244+
20902245
push
20912246
.command("bucket")
20922247
.alias("buckets")

0 commit comments

Comments
 (0)