Skip to content

feat: introduce tables commands and deprecate collections commands #1140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
5 changes: 0 additions & 5 deletions templates/cli/lib/client.js.twig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
64 changes: 62 additions & 2 deletions templates/cli/lib/commands/pull.js.twig
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -20,7 +21,7 @@ const pullResources = async () => {
settings: pullSettings,
functions: pullFunctions,
sites: pullSites,
collections: pullCollection,
tables: pullTable,
buckets: pullBucket,
teams: pullTeam,
messages: pullMessagingTopic
Expand Down Expand Up @@ -285,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;

Expand Down Expand Up @@ -336,6 +338,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, 'tables');

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;
Expand Down Expand Up @@ -447,9 +501,15 @@ 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
.command("table")
.alias("tables")
.description("Pull your {{ spec.title|caseUcfirst }} tables")
.action(actionRunner(pullTable))

pull
.command("bucket")
.alias("buckets")
Expand Down
160 changes: 157 additions & 3 deletions templates/cli/lib/commands/push.js.twig
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ 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, 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');
Expand Down Expand Up @@ -49,6 +49,10 @@ const {
databasesListIndexes,
databasesUpdateCollection
} = require("./databases");
const {
gridsGetDatabase,
gridsGetTable
} = require("./grids");
const {
storageGetBucket, storageUpdateBucket, storageCreateBucket
} = require("./storage");
Expand Down Expand Up @@ -1672,7 +1676,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, gridsGetTable, KeysTable, 'tableId', 'tables', ['columns', 'indexes'], 'databaseId', 'databaseId',))) {
return;
}
// Parallel collection actions
await Promise.all(tables.map(async (table) => {
try {
const remoteTable = await gridsGetTable({
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 columns = table.columns;
let indexes = table.indexes;

if (table.isExisted) {
columns = await attributesToCreate(table.remoteVersion.columns, table.columns, table);
indexes = await attributesToCreate(table.remoteVersion.indexes, table.indexes, table, true);

if ((Array.isArray(columns) && columns.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) {
continue;
}

}

log(`Pushing table ${table.name} ( ${table['databaseId']} - ${table['$id']} ) attributes`)

try {
await createAttributes(columns, 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("appwrite push collection has been deprecated. Please consider using 'appwrite push tables' instead");
const collections = [];

if (attempts) {
Expand Down Expand Up @@ -2083,10 +2230,17 @@ push
push
.command("collection")
.alias("collections")
.description("Push collections in the current project.")
.description("Push collections in the current project. (deprecated, please use 'push tables' instead)")
.option(`-a, --attempts <numberOfAttempts>`, `Max number of attempts before timing out. default: 30.`)
.action(actionRunner(pushCollection));

push
.command("table")
.alias("tables")
.description("Push tables in the current project.")
.option(`-a, --attempts <numberOfAttempts>`, `Max number of attempts before timing out. default: 30.`)
.action(actionRunner(pushTable));

push
.command("bucket")
.alias("buckets")
Expand Down
Loading