Skip to content

Commit 07aaf74

Browse files
committed
feat: introduce tables commands and deprecate collections commands
1 parent 4af563f commit 07aaf74

File tree

5 files changed

+286
-6
lines changed

5 files changed

+286
-6
lines changed

example.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ function getSSLPage($url) {
4242
$platform = 'console';
4343
// $platform = 'server';
4444

45-
$version = '1.7.x';
45+
$version = '1.8.x';
4646
$spec = getSSLPage("https://raw.githubusercontent.com/appwrite/appwrite/{$version}/app/config/specs/swagger2-{$version}-{$platform}.json");
4747

4848
if(empty($spec)) {

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

Lines changed: 59 additions & 0 deletions
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");
@@ -336,6 +337,58 @@ const pullCollection = async () => {
336337
success(`Successfully pulled ${chalk.bold(total)} collections.`);
337338
}
338339

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

506+
pull
507+
.command("table")
508+
.alias("tables")
509+
.description("Pull your {{ spec.title|caseUcfirst }} tables")
510+
.action(actionRunner(pullTable))
511+
453512
pull
454513
.command("bucket")
455514
.alias("buckets")

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

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const ID = require("../id");
99
const { localConfig, globalConfig, KeysAttributes, KeysFunction, KeysSite, whitelistKeys, KeysTopics, KeysStorage, KeysTeams, KeysCollection } = 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,9 @@ const {
4949
databasesListIndexes,
5050
databasesUpdateCollection
5151
} = require("./databases");
52+
const {
53+
gridsGetDatabase
54+
} = require("./grids");
5255
const {
5356
storageGetBucket, storageUpdateBucket, storageCreateBucket
5457
} = require("./storage");
@@ -1672,7 +1675,150 @@ const pushFunction = async ({ functionId, async, code, withVariables } = { retur
16721675
}
16731676
}
16741677

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

16781824
if (attempts) {
@@ -2080,6 +2226,13 @@ push
20802226
.option("--with-variables", `Push site variables.`)
20812227
.action(actionRunner(pushSite));
20822228

2229+
push
2230+
.command("table")
2231+
.alias("tables")
2232+
.description("Push tables in the current project.")
2233+
.option(`-a, --attempts <numberOfAttempts>`, `Max number of attempts before timing out. default: 30.`)
2234+
.action(actionRunner(pushTable));
2235+
20832236
push
20842237
.command("collection")
20852238
.alias("collections")

templates/cli/lib/config.js.twig

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const KeysSite = new Set(["path", "$id", "name", "enabled", "logging", "timeout"
99
const KeysFunction = new Set(["path", "$id", "execute", "name", "enabled", "logging", "runtime", "specification", "scopes", "events", "schedule", "timeout", "entrypoint", "commands", "vars"]);
1010
const KeysDatabase = new Set(["$id", "name", "enabled"]);
1111
const KeysCollection = new Set(["$id", "$permissions", "databaseId", "name", "enabled", "documentSecurity", "attributes", "indexes"]);
12+
const KeysTable = new Set(["$id", "$permissions", "databaseId", "name", "enabled", "documentSecurity", "attributes", "indexes"]);
1213
const KeysStorage = new Set(["$id", "$permissions", "fileSecurity", "name", "enabled", "maximumFileSize", "allowedFileExtensions", "compression", "encryption", "antivirus"]);
1314
const KeysTopics = new Set(["$id", "name", "subscribe"]);
1415
const KeysTeams = new Set(["$id", "name"]);
@@ -310,6 +311,50 @@ class Local extends Config {
310311
this.set("collections", collections);
311312
}
312313

314+
getTables() {
315+
if (!this.has("tables")) {
316+
return [];
317+
}
318+
return this.get("tables");
319+
}
320+
321+
getTable($id) {
322+
if (!this.has("tables")) {
323+
return {};
324+
}
325+
326+
let tables = this.get("tables");
327+
for (let i = 0; i < tables.length; i++) {
328+
if (tables[i]['$id'] == $id) {
329+
return tables[i];
330+
}
331+
}
332+
333+
return {};
334+
}
335+
336+
addTable(props) {
337+
props = whitelistKeys(props, KeysTable, {
338+
attributes: KeysAttributes,
339+
indexes: KeyIndexes
340+
});
341+
342+
if (!this.has("tables")) {
343+
this.set("tables", []);
344+
}
345+
346+
let tables = this.get("tables");
347+
for (let i = 0; i < tables.length; i++) {
348+
if (tables[i]['$id'] == props['$id'] && tables[i]['databaseId'] == props['databaseId']) {
349+
tables[i] = props;
350+
this.set("tables", tables);
351+
return;
352+
}
353+
}
354+
tables.push(props);
355+
this.set("tables", tables);
356+
}
357+
313358
getBuckets() {
314359
if (!this.has("buckets")) {
315360
return [];
@@ -713,5 +758,6 @@ module.exports = {
713758
KeysStorage,
714759
KeysTeams,
715760
KeysCollection,
761+
KeysTable,
716762
whitelistKeys
717763
};

0 commit comments

Comments
 (0)