@@ -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");
6063const {
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+
17031847const 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