Skip to content

Commit 0c4f514

Browse files
authored
Merge pull request #1222 from appwrite/sync-databases
2 parents 85f51dc + 3d18a1e commit 0c4f514

File tree

1 file changed

+164
-34
lines changed

1 file changed

+164
-34
lines changed

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

Lines changed: 164 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ const {
5555
tablesDBUpdate,
5656
tablesDBCreateTable,
5757
tablesDBGetTable,
58-
tablesDBUpdateTable
58+
tablesDBUpdateTable,
59+
tablesDBList,
60+
tablesDBDelete,
61+
tablesDBListTables
5962
} = require("./tables-db");
6063
const {
6164
storageGetBucket, storageUpdateBucket, storageCreateBucket
@@ -1700,13 +1703,173 @@ const pushFunction = async ({ functionId, async, code, withVariables } = { retur
17001703
}
17011704
}
17021705

1706+
const checkAndApplyTablesDBChanges = async () => {
1707+
log('Checking for tablesDB changes ...');
1708+
1709+
const localTablesDBs = localConfig.getTablesDBs();
1710+
const { databases: remoteTablesDBs } = await paginate(tablesDBList, { parseOutput: false }, 100, 'databases');
1711+
1712+
if (localTablesDBs.length === 0 && remoteTablesDBs.length === 0) {
1713+
return { applied: false, resyncNeeded: false };
1714+
}
1715+
1716+
const changes = [];
1717+
const toCreate = [];
1718+
const toUpdate = [];
1719+
const toDelete = [];
1720+
1721+
// Check for deletions - remote DBs that aren't in local config
1722+
for (const remoteDB of remoteTablesDBs) {
1723+
const localDB = localTablesDBs.find(db => db.$id === remoteDB.$id);
1724+
if (!localDB) {
1725+
toDelete.push(remoteDB);
1726+
changes.push({
1727+
id: remoteDB.$id,
1728+
key: 'Database',
1729+
remote: chalk.red(`${remoteDB.name} (${remoteDB.$id})`),
1730+
local: chalk.green('(deleted locally)')
1731+
});
1732+
}
1733+
}
1734+
1735+
// Check for additions and updates
1736+
for (const localDB of localTablesDBs) {
1737+
const remoteDB = remoteTablesDBs.find(db => db.$id === localDB.$id);
1738+
1739+
if (!remoteDB) {
1740+
toCreate.push(localDB);
1741+
changes.push({
1742+
id: localDB.$id,
1743+
key: 'Database',
1744+
remote: chalk.red('(does not exist)'),
1745+
local: chalk.green(`${localDB.name} (${localDB.$id})`)
1746+
});
1747+
} else {
1748+
let hasChanges = false;
1749+
1750+
if (remoteDB.name !== localDB.name) {
1751+
hasChanges = true;
1752+
changes.push({
1753+
id: localDB.$id,
1754+
key: 'Name',
1755+
remote: chalk.red(remoteDB.name),
1756+
local: chalk.green(localDB.name)
1757+
});
1758+
}
1759+
1760+
if (remoteDB.enabled !== localDB.enabled) {
1761+
hasChanges = true;
1762+
changes.push({
1763+
id: localDB.$id,
1764+
key: 'Enabled?',
1765+
remote: chalk.red(remoteDB.enabled),
1766+
local: chalk.green(localDB.enabled)
1767+
});
1768+
}
1769+
1770+
if (hasChanges) {
1771+
toUpdate.push(localDB);
1772+
}
1773+
}
1774+
}
1775+
1776+
if (changes.length === 0) {
1777+
return { applied: false, resyncNeeded: false };
1778+
}
1779+
1780+
log('Found changes in tablesDB resources:');
1781+
drawTable(changes);
1782+
1783+
if (toDelete.length > 0) {
1784+
console.log(`${chalk.red('-------------------------------------------------------------------')}`);
1785+
console.log(`${chalk.red('| WARNING: Database deletion will also delete all related tables |')}`);
1786+
console.log(`${chalk.red('-------------------------------------------------------------------')}`);
1787+
}
1788+
1789+
if ((await getConfirmation()) !== true) {
1790+
return { applied: false, resyncNeeded: false };
1791+
}
1792+
1793+
// Apply deletions first
1794+
let needsResync = false;
1795+
for (const db of toDelete) {
1796+
try {
1797+
log(`Deleting database ${db.name} ( ${db.$id} ) ...`);
1798+
await tablesDBDelete({
1799+
databaseId: db.$id,
1800+
parseOutput: false
1801+
});
1802+
success(`Deleted ${db.name} ( ${db.$id} )`);
1803+
needsResync = true;
1804+
} catch (e) {
1805+
error(`Failed to delete database ${db.name} ( ${db.$id} ): ${e.message}`);
1806+
throw new Error(`Database sync failed during deletion of ${db.$id}. Some changes may have been applied.`);
1807+
}
1808+
}
1809+
1810+
// Apply creations
1811+
for (const db of toCreate) {
1812+
try {
1813+
log(`Creating database ${db.name} ( ${db.$id} ) ...`);
1814+
await tablesDBCreate({
1815+
databaseId: db.$id,
1816+
name: db.name,
1817+
enabled: db.enabled,
1818+
parseOutput: false
1819+
});
1820+
success(`Created ${db.name} ( ${db.$id} )`);
1821+
} catch (e) {
1822+
error(`Failed to create database ${db.name} ( ${db.$id} ): ${e.message}`);
1823+
throw new Error(`Database sync failed during creation of ${db.$id}. Some changes may have been applied.`);
1824+
}
1825+
}
1826+
1827+
// Apply updates
1828+
for (const db of toUpdate) {
1829+
try {
1830+
log(`Updating database ${db.name} ( ${db.$id} ) ...`);
1831+
await tablesDBUpdate({
1832+
databaseId: db.$id,
1833+
name: db.name,
1834+
enabled: db.enabled,
1835+
parseOutput: false
1836+
});
1837+
success(`Updated ${db.name} ( ${db.$id} )`);
1838+
} catch (e) {
1839+
error(`Failed to update database ${db.name} ( ${db.$id} ): ${e.message}`);
1840+
throw new Error(`Database sync failed during update of ${db.$id}. Some changes may have been applied.`);
1841+
}
1842+
}
1843+
1844+
return { applied: true, resyncNeeded: needsResync };
1845+
};
1846+
17031847
const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) => {
17041848
const tables = [];
17051849

17061850
if (attempts) {
17071851
pollMaxDebounces = attempts;
17081852
}
17091853

1854+
const { applied: tablesDBApplied, resyncNeeded } = await checkAndApplyTablesDBChanges();
1855+
if (resyncNeeded) {
1856+
log('Resyncing configuration due to tablesDB deletions ...');
1857+
1858+
const remoteTablesDBs = (await paginate(tablesDBList, { parseOutput: false }, 100, 'databases')).databases;
1859+
const localTablesDBs = localConfig.getTablesDBs();
1860+
1861+
const remoteDatabaseIds = new Set(remoteTablesDBs.map(db => db.$id));
1862+
const localTables = localConfig.getTables();
1863+
const validTables = localTables.filter(table => remoteDatabaseIds.has(table.databaseId));
1864+
1865+
localConfig.set('tables', validTables);
1866+
1867+
const validTablesDBs = localTablesDBs.filter(db => remoteDatabaseIds.has(db.$id));
1868+
localConfig.set('tablesDB', validTablesDBs);
1869+
1870+
success('Configuration resynced successfully.');
1871+
}
1872+
17101873
if (cliConfig.all) {
17111874
checkDeployConditions(localConfig);
17121875
tables.push(...localConfig.getTables());
@@ -1730,39 +1893,6 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) =
17301893
return;
17311894
}
17321895

1733-
const databases = Array.from(new Set(tables.map(table => table['databaseId'])));
1734-
1735-
// Parallel tablesDB actions
1736-
await Promise.all(databases.map(async (databaseId) => {
1737-
const localDatabase = localConfig.getTablesDB(databaseId);
1738-
1739-
try {
1740-
const database = await tablesDBGet({
1741-
databaseId: databaseId,
1742-
parseOutput: false,
1743-
});
1744-
1745-
if (database.name !== (localDatabase.name ?? databaseId)) {
1746-
await tablesDBUpdate({
1747-
databaseId: databaseId,
1748-
name: localDatabase.name ?? databaseId,
1749-
parseOutput: false
1750-
})
1751-
1752-
success(`Updated ${localDatabase.name} ( ${databaseId} ) name`);
1753-
}
1754-
} catch (err) {
1755-
log(`Database ${databaseId} not found. Creating it now ...`);
1756-
1757-
await tablesDBCreate({
1758-
databaseId: databaseId,
1759-
name: localDatabase.name ?? databaseId,
1760-
parseOutput: false,
1761-
});
1762-
}
1763-
}));
1764-
1765-
17661896
if (!(await approveChanges(tables, tablesDBGetTable, KeysTable, 'tableId', 'tables', ['columns', 'indexes'], 'databaseId', 'databaseId'))) {
17671897
return;
17681898
}

0 commit comments

Comments
 (0)