appwrite-cli 13.0.0 → 13.1.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +3 -3
- package/cli.ts +2 -0
- package/dist/bundle.cjs +52800 -50718
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +3 -4
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/commands/config-validations.d.ts +53 -0
- package/dist/lib/commands/config-validations.d.ts.map +1 -0
- package/dist/lib/commands/config-validations.js +130 -0
- package/dist/lib/commands/config-validations.js.map +1 -0
- package/dist/lib/commands/config.d.ts +241 -236
- package/dist/lib/commands/config.d.ts.map +1 -1
- package/dist/lib/commands/config.js +85 -105
- package/dist/lib/commands/config.js.map +1 -1
- package/dist/lib/commands/generate.d.ts +7 -0
- package/dist/lib/commands/generate.d.ts.map +1 -0
- package/dist/lib/commands/generate.js +92 -0
- package/dist/lib/commands/generate.js.map +1 -0
- package/dist/lib/commands/generators/base.d.ts +58 -0
- package/dist/lib/commands/generators/base.d.ts.map +1 -0
- package/dist/lib/commands/generators/base.js +27 -0
- package/dist/lib/commands/generators/base.js.map +1 -0
- package/dist/lib/commands/generators/index.d.ts +26 -0
- package/dist/lib/commands/generators/index.d.ts.map +1 -0
- package/dist/lib/commands/generators/index.js +55 -0
- package/dist/lib/commands/generators/index.js.map +1 -0
- package/dist/lib/commands/generators/language-detector.d.ts +42 -0
- package/dist/lib/commands/generators/language-detector.d.ts.map +1 -0
- package/dist/lib/commands/generators/language-detector.js +127 -0
- package/dist/lib/commands/generators/language-detector.js.map +1 -0
- package/dist/lib/commands/generators/typescript/databases.d.ts +36 -0
- package/dist/lib/commands/generators/typescript/databases.d.ts.map +1 -0
- package/dist/lib/commands/generators/typescript/databases.js +489 -0
- package/dist/lib/commands/generators/typescript/databases.js.map +1 -0
- package/dist/lib/commands/pull.d.ts.map +1 -1
- package/dist/lib/commands/pull.js +15 -9
- package/dist/lib/commands/pull.js.map +1 -1
- package/dist/lib/commands/push.d.ts +6 -3
- package/dist/lib/commands/push.d.ts.map +1 -1
- package/dist/lib/commands/push.js +64 -41
- package/dist/lib/commands/push.js.map +1 -1
- package/dist/lib/commands/schema.d.ts +2 -2
- package/dist/lib/commands/schema.d.ts.map +1 -1
- package/dist/lib/commands/schema.js +2 -2
- package/dist/lib/commands/schema.js.map +1 -1
- package/dist/lib/commands/services/projects.js +7 -1
- package/dist/lib/commands/services/projects.js.map +1 -1
- package/dist/lib/commands/services/storage.js +2 -2
- package/dist/lib/commands/services/storage.js.map +1 -1
- package/dist/lib/commands/utils/attributes.d.ts +10 -2
- package/dist/lib/commands/utils/attributes.d.ts.map +1 -1
- package/dist/lib/commands/utils/attributes.js +35 -16
- package/dist/lib/commands/utils/attributes.js.map +1 -1
- package/dist/lib/commands/utils/pools.d.ts +0 -3
- package/dist/lib/commands/utils/pools.d.ts.map +1 -1
- package/dist/lib/commands/utils/pools.js +0 -34
- package/dist/lib/commands/utils/pools.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +37 -141
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/constants.d.ts +1 -1
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +1 -1
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/json.d.ts +8 -0
- package/dist/lib/json.d.ts.map +1 -0
- package/dist/lib/json.js +25 -0
- package/dist/lib/json.js.map +1 -0
- package/dist/lib/utils.d.ts +13 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +45 -177
- package/dist/lib/utils.js.map +1 -1
- package/dist/package.json +3 -2
- package/docs/examples/projects/update-labels.md +3 -0
- package/install.ps1 +2 -2
- package/install.sh +1 -1
- package/lib/client.ts +3 -5
- package/lib/commands/config-validations.ts +199 -0
- package/lib/commands/config.ts +93 -120
- package/lib/commands/generate.ts +142 -0
- package/lib/commands/generators/base.ts +91 -0
- package/lib/commands/generators/index.ts +87 -0
- package/lib/commands/generators/language-detector.ts +163 -0
- package/lib/commands/generators/typescript/databases.ts +590 -0
- package/lib/commands/pull.ts +30 -9
- package/lib/commands/push.ts +105 -62
- package/lib/commands/schema.ts +3 -3
- package/lib/commands/services/projects.ts +13 -1
- package/lib/commands/services/storage.ts +2 -2
- package/lib/commands/utils/attributes.ts +49 -18
- package/lib/commands/utils/pools.ts +0 -67
- package/lib/config.ts +52 -142
- package/lib/constants.ts +1 -1
- package/lib/json.ts +28 -0
- package/lib/utils.ts +46 -221
- package/package.json +3 -2
- package/scoop/appwrite.config.json +3 -3
- package/dist/lib/commands/db.d.ts +0 -34
- package/dist/lib/commands/db.d.ts.map +0 -1
- package/dist/lib/commands/db.js +0 -247
- package/dist/lib/commands/db.js.map +0 -1
- package/lib/commands/db.ts +0 -324
package/lib/commands/push.ts
CHANGED
|
@@ -17,7 +17,12 @@ import {
|
|
|
17
17
|
KeysCollection,
|
|
18
18
|
KeysTable,
|
|
19
19
|
} from "../config.js";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
ConfigSchema,
|
|
22
|
+
type SettingsType,
|
|
23
|
+
type ConfigType,
|
|
24
|
+
type CollectionType,
|
|
25
|
+
} from "./config.js";
|
|
21
26
|
import { parseWithBetterErrors } from "./utils/error-formatter.js";
|
|
22
27
|
import { createSettingsObject } from "../utils.js";
|
|
23
28
|
import { Spinner, SPINNER_DOTS } from "../spinner.js";
|
|
@@ -127,6 +132,20 @@ interface PushTableOptions {
|
|
|
127
132
|
skipConfirmation?: boolean;
|
|
128
133
|
}
|
|
129
134
|
|
|
135
|
+
interface PushCollectionInput extends CollectionType {
|
|
136
|
+
databaseName?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
interface PushCollectionState extends PushCollectionInput {
|
|
140
|
+
remoteVersion?: {
|
|
141
|
+
name: string;
|
|
142
|
+
attributes: object[];
|
|
143
|
+
indexes: object[];
|
|
144
|
+
};
|
|
145
|
+
isExisted?: boolean;
|
|
146
|
+
isNewlyCreated?: boolean;
|
|
147
|
+
}
|
|
148
|
+
|
|
130
149
|
export class Push {
|
|
131
150
|
private projectClient: Client;
|
|
132
151
|
private consoleClient: Client;
|
|
@@ -1414,26 +1433,26 @@ export class Push {
|
|
|
1414
1433
|
for (let table of tables) {
|
|
1415
1434
|
let columns = table.columns;
|
|
1416
1435
|
let indexes = table.indexes;
|
|
1436
|
+
let hadChanges = false;
|
|
1417
1437
|
|
|
1418
1438
|
if (table.isExisted) {
|
|
1419
|
-
|
|
1439
|
+
const columnsResult = await attributes.attributesToCreate(
|
|
1420
1440
|
table.remoteVersion.columns,
|
|
1421
1441
|
table.columns,
|
|
1422
1442
|
table as Collection,
|
|
1423
1443
|
);
|
|
1424
|
-
|
|
1444
|
+
const indexesResult = await attributes.attributesToCreate(
|
|
1425
1445
|
table.remoteVersion.indexes,
|
|
1426
1446
|
table.indexes,
|
|
1427
1447
|
table as Collection,
|
|
1428
1448
|
true,
|
|
1429
1449
|
);
|
|
1430
1450
|
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
) {
|
|
1451
|
+
columns = columnsResult.attributes;
|
|
1452
|
+
indexes = indexesResult.attributes;
|
|
1453
|
+
hadChanges = columnsResult.hasChanges || indexesResult.hasChanges;
|
|
1454
|
+
|
|
1455
|
+
if (!hadChanges && columns.length <= 0 && indexes.length <= 0) {
|
|
1437
1456
|
continue;
|
|
1438
1457
|
}
|
|
1439
1458
|
}
|
|
@@ -1466,25 +1485,28 @@ export class Push {
|
|
|
1466
1485
|
}
|
|
1467
1486
|
|
|
1468
1487
|
public async pushCollections(
|
|
1469
|
-
collections:
|
|
1488
|
+
collections: PushCollectionInput[],
|
|
1470
1489
|
options: { skipConfirmation?: boolean } = {},
|
|
1471
1490
|
): Promise<{
|
|
1472
1491
|
successfullyPushed: number;
|
|
1473
|
-
errors:
|
|
1492
|
+
errors: Error[];
|
|
1474
1493
|
}> {
|
|
1475
1494
|
const { skipConfirmation = false } = options;
|
|
1476
1495
|
const pools = new Pools(POLL_DEFAULT_VALUE);
|
|
1477
|
-
const
|
|
1496
|
+
const attributesHelper = new Attributes(pools, skipConfirmation);
|
|
1478
1497
|
|
|
1479
|
-
const errors:
|
|
1498
|
+
const errors: Error[] = [];
|
|
1499
|
+
|
|
1500
|
+
// Cast to state type since we'll be adding state properties
|
|
1501
|
+
const collectionsWithState = collections as PushCollectionState[];
|
|
1480
1502
|
|
|
1481
1503
|
const databases = Array.from(
|
|
1482
|
-
new Set(
|
|
1504
|
+
new Set(collectionsWithState.map((collection) => collection.databaseId)),
|
|
1483
1505
|
);
|
|
1484
1506
|
|
|
1485
1507
|
// Parallel db actions
|
|
1486
1508
|
await Promise.all(
|
|
1487
|
-
databases.map(async (databaseId
|
|
1509
|
+
databases.map(async (databaseId) => {
|
|
1488
1510
|
const databasesService = await getDatabasesService(this.projectClient);
|
|
1489
1511
|
try {
|
|
1490
1512
|
const database = await databasesService.get(databaseId);
|
|
@@ -1492,7 +1514,7 @@ export class Push {
|
|
|
1492
1514
|
// Note: We can't get the local database name here since we don't have access to localConfig
|
|
1493
1515
|
// This will need to be handled by the caller if needed
|
|
1494
1516
|
const localDatabaseName =
|
|
1495
|
-
|
|
1517
|
+
collectionsWithState.find((c) => c.databaseId === databaseId)
|
|
1496
1518
|
?.databaseName ?? databaseId;
|
|
1497
1519
|
|
|
1498
1520
|
if (database.name !== localDatabaseName) {
|
|
@@ -1500,12 +1522,12 @@ export class Push {
|
|
|
1500
1522
|
|
|
1501
1523
|
this.success(`Updated ${localDatabaseName} ( ${databaseId} ) name`);
|
|
1502
1524
|
}
|
|
1503
|
-
} catch (err:
|
|
1504
|
-
if (Number(err.code) === 404) {
|
|
1525
|
+
} catch (err: unknown) {
|
|
1526
|
+
if (err instanceof AppwriteException && Number(err.code) === 404) {
|
|
1505
1527
|
this.log(`Database ${databaseId} not found. Creating it now ...`);
|
|
1506
1528
|
|
|
1507
1529
|
const localDatabaseName =
|
|
1508
|
-
|
|
1530
|
+
collectionsWithState.find((c) => c.databaseId === databaseId)
|
|
1509
1531
|
?.databaseName ?? databaseId;
|
|
1510
1532
|
|
|
1511
1533
|
await databasesService.create(databaseId, localDatabaseName);
|
|
@@ -1518,32 +1540,32 @@ export class Push {
|
|
|
1518
1540
|
|
|
1519
1541
|
// Parallel collection actions
|
|
1520
1542
|
await Promise.all(
|
|
1521
|
-
|
|
1543
|
+
collectionsWithState.map(async (collection) => {
|
|
1522
1544
|
try {
|
|
1523
1545
|
const databasesService = await getDatabasesService(
|
|
1524
1546
|
this.projectClient,
|
|
1525
1547
|
);
|
|
1526
1548
|
const remoteCollection = await databasesService.getCollection(
|
|
1527
|
-
collection
|
|
1528
|
-
collection
|
|
1549
|
+
collection.databaseId,
|
|
1550
|
+
collection.$id,
|
|
1529
1551
|
);
|
|
1530
1552
|
|
|
1531
1553
|
if (remoteCollection.name !== collection.name) {
|
|
1532
|
-
await databasesService.updateCollection(
|
|
1533
|
-
collection
|
|
1534
|
-
collection
|
|
1535
|
-
collection.name,
|
|
1536
|
-
);
|
|
1554
|
+
await databasesService.updateCollection({
|
|
1555
|
+
databaseId: collection.databaseId,
|
|
1556
|
+
collectionId: collection.$id,
|
|
1557
|
+
name: collection.name,
|
|
1558
|
+
});
|
|
1537
1559
|
|
|
1538
1560
|
this.success(
|
|
1539
|
-
`Updated ${collection.name} ( ${collection
|
|
1561
|
+
`Updated ${collection.name} ( ${collection.$id} ) name`,
|
|
1540
1562
|
);
|
|
1541
1563
|
}
|
|
1542
1564
|
collection.remoteVersion = remoteCollection;
|
|
1543
1565
|
|
|
1544
1566
|
collection.isExisted = true;
|
|
1545
|
-
} catch (e:
|
|
1546
|
-
if (Number(e.code) === 404) {
|
|
1567
|
+
} catch (e: unknown) {
|
|
1568
|
+
if (e instanceof AppwriteException && Number(e.code) === 404) {
|
|
1547
1569
|
this.log(
|
|
1548
1570
|
`Collection ${collection.name} does not exist in the project. Creating ... `,
|
|
1549
1571
|
);
|
|
@@ -1551,14 +1573,19 @@ export class Push {
|
|
|
1551
1573
|
this.projectClient,
|
|
1552
1574
|
);
|
|
1553
1575
|
await databasesService.createCollection({
|
|
1554
|
-
databaseId: collection
|
|
1555
|
-
collectionId: collection
|
|
1576
|
+
databaseId: collection.databaseId,
|
|
1577
|
+
collectionId: collection.$id,
|
|
1556
1578
|
name: collection.name,
|
|
1557
1579
|
documentSecurity: collection.documentSecurity,
|
|
1558
|
-
permissions: collection
|
|
1580
|
+
permissions: collection.$permissions,
|
|
1581
|
+
attributes: collection.attributes,
|
|
1582
|
+
indexes: collection.indexes,
|
|
1559
1583
|
});
|
|
1584
|
+
collection.isNewlyCreated = true;
|
|
1560
1585
|
} else {
|
|
1561
|
-
|
|
1586
|
+
if (e instanceof Error) {
|
|
1587
|
+
errors.push(e);
|
|
1588
|
+
}
|
|
1562
1589
|
throw e;
|
|
1563
1590
|
}
|
|
1564
1591
|
}
|
|
@@ -1567,56 +1594,72 @@ export class Push {
|
|
|
1567
1594
|
|
|
1568
1595
|
let numberOfCollections = 0;
|
|
1569
1596
|
// Serialize attribute actions
|
|
1570
|
-
for (
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
collection.remoteVersion.attributes,
|
|
1577
|
-
collection.attributes,
|
|
1578
|
-
collection as Collection,
|
|
1597
|
+
for (const collection of collectionsWithState) {
|
|
1598
|
+
// Skip newly created collections - their attributes and indexes were already created
|
|
1599
|
+
if (collection.isNewlyCreated) {
|
|
1600
|
+
numberOfCollections++;
|
|
1601
|
+
this.success(
|
|
1602
|
+
`Successfully pushed ${collection.name} ( ${collection.$id} )`,
|
|
1579
1603
|
);
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1604
|
+
continue;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
if (!collection.isExisted) {
|
|
1608
|
+
continue;
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
const collectionAttributesResult =
|
|
1612
|
+
await attributesHelper.attributesToCreate(
|
|
1613
|
+
collection.remoteVersion!.attributes,
|
|
1614
|
+
collection.attributes ?? [],
|
|
1583
1615
|
collection as Collection,
|
|
1584
|
-
true,
|
|
1585
1616
|
);
|
|
1617
|
+
const indexesResult = await attributesHelper.attributesToCreate(
|
|
1618
|
+
collection.remoteVersion!.indexes,
|
|
1619
|
+
collection.indexes ?? [],
|
|
1620
|
+
collection as Collection,
|
|
1621
|
+
true,
|
|
1622
|
+
);
|
|
1586
1623
|
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1624
|
+
const collectionAttributes = collectionAttributesResult.attributes;
|
|
1625
|
+
const indexes = indexesResult.attributes;
|
|
1626
|
+
|
|
1627
|
+
if (
|
|
1628
|
+
collectionAttributes.length <= 0 &&
|
|
1629
|
+
indexes.length <= 0 &&
|
|
1630
|
+
!collectionAttributesResult.hasChanges &&
|
|
1631
|
+
!indexesResult.hasChanges
|
|
1632
|
+
) {
|
|
1633
|
+
continue;
|
|
1595
1634
|
}
|
|
1596
1635
|
|
|
1597
1636
|
this.log(
|
|
1598
|
-
`Pushing collection ${collection.name} ( ${collection
|
|
1637
|
+
`Pushing collection ${collection.name} ( ${collection.databaseId} - ${collection.$id} ) attributes`,
|
|
1599
1638
|
);
|
|
1600
1639
|
|
|
1601
1640
|
try {
|
|
1602
|
-
await
|
|
1641
|
+
await attributesHelper.createAttributes(
|
|
1603
1642
|
collectionAttributes,
|
|
1604
1643
|
collection as Collection,
|
|
1605
1644
|
);
|
|
1606
1645
|
} catch (e) {
|
|
1607
|
-
|
|
1646
|
+
if (e instanceof Error) {
|
|
1647
|
+
errors.push(e);
|
|
1648
|
+
}
|
|
1608
1649
|
throw e;
|
|
1609
1650
|
}
|
|
1610
1651
|
|
|
1611
1652
|
try {
|
|
1612
|
-
await
|
|
1653
|
+
await attributesHelper.createIndexes(indexes, collection as Collection);
|
|
1613
1654
|
} catch (e) {
|
|
1614
|
-
|
|
1655
|
+
if (e instanceof Error) {
|
|
1656
|
+
errors.push(e);
|
|
1657
|
+
}
|
|
1615
1658
|
throw e;
|
|
1616
1659
|
}
|
|
1617
1660
|
numberOfCollections++;
|
|
1618
1661
|
this.success(
|
|
1619
|
-
`Successfully pushed ${collection.name} ( ${collection
|
|
1662
|
+
`Successfully pushed ${collection.name} ( ${collection.$id} )`,
|
|
1620
1663
|
);
|
|
1621
1664
|
}
|
|
1622
1665
|
|
|
@@ -2193,7 +2236,7 @@ const pushTable = async ({
|
|
|
2193
2236
|
const { successfullyPushed, errors } = result;
|
|
2194
2237
|
|
|
2195
2238
|
if (successfullyPushed === 0) {
|
|
2196
|
-
|
|
2239
|
+
warn("No tables were pushed.");
|
|
2197
2240
|
} else {
|
|
2198
2241
|
success(`Successfully pushed ${successfullyPushed} tables.`);
|
|
2199
2242
|
}
|
package/lib/commands/schema.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { parseWithBetterErrors } from "./utils/error-formatter.js";
|
|
|
7
7
|
import JSONbig from "json-bigint";
|
|
8
8
|
import * as fs from "fs";
|
|
9
9
|
import * as path from "path";
|
|
10
|
-
import {
|
|
10
|
+
import { TypeScriptDatabasesGenerator } from "./generators/typescript/databases.js";
|
|
11
11
|
|
|
12
12
|
const JSONBig = JSONbig({ useNativeBigInt: true });
|
|
13
13
|
|
|
@@ -17,7 +17,7 @@ export class Schema {
|
|
|
17
17
|
|
|
18
18
|
private pullCommandSilent: Pull;
|
|
19
19
|
|
|
20
|
-
public db:
|
|
20
|
+
public db: TypeScriptDatabasesGenerator;
|
|
21
21
|
|
|
22
22
|
constructor({
|
|
23
23
|
projectClient,
|
|
@@ -31,7 +31,7 @@ export class Schema {
|
|
|
31
31
|
|
|
32
32
|
this.pullCommandSilent = new Pull(projectClient, consoleClient, true);
|
|
33
33
|
|
|
34
|
-
this.db = new
|
|
34
|
+
this.db = new TypeScriptDatabasesGenerator();
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
@@ -42,7 +42,7 @@ export const projects = new Command("projects")
|
|
|
42
42
|
projects
|
|
43
43
|
.command(`list`)
|
|
44
44
|
.description(`Get a list of all projects. You can use the query params to filter your results. `)
|
|
45
|
-
.option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId`)
|
|
45
|
+
.option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId, labels, search`)
|
|
46
46
|
.option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`)
|
|
47
47
|
.option(
|
|
48
48
|
`--total [value]`,
|
|
@@ -429,6 +429,18 @@ projects
|
|
|
429
429
|
),
|
|
430
430
|
);
|
|
431
431
|
|
|
432
|
+
projects
|
|
433
|
+
.command(`update-labels`)
|
|
434
|
+
.description(`Update the project labels by its unique ID. Labels can be used to easily filter projects in an organization.`)
|
|
435
|
+
.requiredOption(`--project-id <project-id>`, `Project unique ID.`)
|
|
436
|
+
.requiredOption(`--labels [labels...]`, `Array of project labels. Replaces the previous labels. Maximum of 1000 labels are allowed, each up to 36 alphanumeric characters long.`)
|
|
437
|
+
.action(
|
|
438
|
+
actionRunner(
|
|
439
|
+
async ({ projectId, labels }) =>
|
|
440
|
+
parse(await (await getProjectsClient()).updateLabels(projectId, labels)),
|
|
441
|
+
),
|
|
442
|
+
);
|
|
443
|
+
|
|
432
444
|
projects
|
|
433
445
|
.command(`update-o-auth-2`)
|
|
434
446
|
.description(`Update the OAuth2 provider configurations. Use this endpoint to set up or update the OAuth2 provider credentials or enable/disable providers. `)
|
|
@@ -71,7 +71,7 @@ storage
|
|
|
71
71
|
)
|
|
72
72
|
.option(`--maximum-file-size <maximum-file-size>`, `Maximum file size allowed in bytes. Maximum allowed value is 30MB.`, parseInteger)
|
|
73
73
|
.option(`--allowed-file-extensions [allowed-file-extensions...]`, `Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.`)
|
|
74
|
-
.option(`--compression <compression>`, `Compression algorithm
|
|
74
|
+
.option(`--compression <compression>`, `Compression algorithm chosen for compression. Can be one of none, [gzip](https://en.wikipedia.org/wiki/Gzip), or [zstd](https://en.wikipedia.org/wiki/Zstd), For file size above 20MB compression is skipped even if it's enabled`)
|
|
75
75
|
.option(
|
|
76
76
|
`--encryption [value]`,
|
|
77
77
|
`Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled`,
|
|
@@ -128,7 +128,7 @@ storage
|
|
|
128
128
|
)
|
|
129
129
|
.option(`--maximum-file-size <maximum-file-size>`, `Maximum file size allowed in bytes. Maximum allowed value is 30MB.`, parseInteger)
|
|
130
130
|
.option(`--allowed-file-extensions [allowed-file-extensions...]`, `Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.`)
|
|
131
|
-
.option(`--compression <compression>`, `Compression algorithm
|
|
131
|
+
.option(`--compression <compression>`, `Compression algorithm chosen for compression. Can be one of none, [gzip](https://en.wikipedia.org/wiki/Gzip), or [zstd](https://en.wikipedia.org/wiki/Zstd), For file size above 20MB compression is skipped even if it's enabled`)
|
|
132
132
|
.option(
|
|
133
133
|
`--encryption [value]`,
|
|
134
134
|
`Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled`,
|
|
@@ -480,40 +480,59 @@ export class Attributes {
|
|
|
480
480
|
);
|
|
481
481
|
};
|
|
482
482
|
|
|
483
|
+
/**
|
|
484
|
+
* Check if attribute is a child-side relationship
|
|
485
|
+
* Child-side relationships are auto-generated by Appwrite and should be skipped
|
|
486
|
+
*/
|
|
487
|
+
private isChildSideRelationship = (attribute: any): boolean =>
|
|
488
|
+
attribute.type === "relationship" && attribute.side === "child";
|
|
489
|
+
|
|
483
490
|
/**
|
|
484
491
|
* Filter deleted and recreated attributes,
|
|
485
|
-
* return list of attributes to create
|
|
492
|
+
* return list of attributes to create and whether any changes were made
|
|
486
493
|
*/
|
|
487
494
|
public attributesToCreate = async (
|
|
488
495
|
remoteAttributes: any[],
|
|
489
496
|
localAttributes: any[],
|
|
490
497
|
collection: Collection,
|
|
491
498
|
isIndex: boolean = false,
|
|
492
|
-
): Promise<any[]> => {
|
|
493
|
-
|
|
499
|
+
): Promise<{ attributes: any[]; hasChanges: boolean }> => {
|
|
500
|
+
// Filter out child-side relationships from both local and remote attributes for comparison
|
|
501
|
+
// Child-side relationships are auto-generated by Appwrite when creating two-way relationships
|
|
502
|
+
// from the parent side, so we should not compare or try to create them directly
|
|
503
|
+
const filteredLocalAttributes = localAttributes.filter(
|
|
504
|
+
(attr) => !this.isChildSideRelationship(attr),
|
|
505
|
+
);
|
|
506
|
+
let filteredRemoteAttributes = remoteAttributes.filter(
|
|
507
|
+
(attr) => !this.isChildSideRelationship(attr),
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
const deleting = filteredRemoteAttributes
|
|
494
511
|
.filter(
|
|
495
|
-
(attribute) =>
|
|
512
|
+
(attribute) =>
|
|
513
|
+
!this.attributesContains(attribute, filteredLocalAttributes),
|
|
496
514
|
)
|
|
497
515
|
.map((attr) => this.generateChangesObject(attr, collection, false));
|
|
498
|
-
const adding =
|
|
516
|
+
const adding = filteredLocalAttributes
|
|
499
517
|
.filter(
|
|
500
|
-
(attribute) =>
|
|
518
|
+
(attribute) =>
|
|
519
|
+
!this.attributesContains(attribute, filteredRemoteAttributes),
|
|
501
520
|
)
|
|
502
521
|
.map((attr) => this.generateChangesObject(attr, collection, true));
|
|
503
|
-
const conflicts =
|
|
522
|
+
const conflicts = filteredRemoteAttributes
|
|
504
523
|
.map((attribute) =>
|
|
505
524
|
this.checkAttributeChanges(
|
|
506
525
|
attribute,
|
|
507
|
-
this.attributesContains(attribute,
|
|
526
|
+
this.attributesContains(attribute, filteredLocalAttributes),
|
|
508
527
|
collection,
|
|
509
528
|
),
|
|
510
529
|
)
|
|
511
530
|
.filter((attribute) => attribute !== undefined) as AttributeChange[];
|
|
512
|
-
const changes =
|
|
531
|
+
const changes = filteredRemoteAttributes
|
|
513
532
|
.map((attribute) =>
|
|
514
533
|
this.checkAttributeChanges(
|
|
515
534
|
attribute,
|
|
516
|
-
this.attributesContains(attribute,
|
|
535
|
+
this.attributesContains(attribute, filteredLocalAttributes),
|
|
517
536
|
collection,
|
|
518
537
|
false,
|
|
519
538
|
),
|
|
@@ -527,7 +546,7 @@ export class Attributes {
|
|
|
527
546
|
let changedAttributes: any[] = [];
|
|
528
547
|
const changing = [...deleting, ...adding, ...conflicts, ...changes];
|
|
529
548
|
if (changing.length === 0) {
|
|
530
|
-
return changedAttributes;
|
|
549
|
+
return { attributes: changedAttributes, hasChanges: false };
|
|
531
550
|
}
|
|
532
551
|
|
|
533
552
|
log(
|
|
@@ -573,7 +592,7 @@ export class Attributes {
|
|
|
573
592
|
}
|
|
574
593
|
|
|
575
594
|
if ((await this.getConfirmation()) !== true) {
|
|
576
|
-
return changedAttributes;
|
|
595
|
+
return { attributes: changedAttributes, hasChanges: false };
|
|
577
596
|
}
|
|
578
597
|
}
|
|
579
598
|
|
|
@@ -584,7 +603,7 @@ export class Attributes {
|
|
|
584
603
|
this.deleteAttribute(collection, changed, isIndex),
|
|
585
604
|
),
|
|
586
605
|
);
|
|
587
|
-
|
|
606
|
+
filteredRemoteAttributes = filteredRemoteAttributes.filter(
|
|
588
607
|
(attribute) => !this.attributesContains(attribute, changedAttributes),
|
|
589
608
|
);
|
|
590
609
|
}
|
|
@@ -631,9 +650,11 @@ export class Attributes {
|
|
|
631
650
|
}
|
|
632
651
|
}
|
|
633
652
|
|
|
634
|
-
|
|
635
|
-
(attribute) =>
|
|
653
|
+
const newAttributes = filteredLocalAttributes.filter(
|
|
654
|
+
(attribute) =>
|
|
655
|
+
!this.attributesContains(attribute, filteredRemoteAttributes),
|
|
636
656
|
);
|
|
657
|
+
return { attributes: newAttributes, hasChanges: true };
|
|
637
658
|
};
|
|
638
659
|
|
|
639
660
|
public createIndexes = async (
|
|
@@ -664,13 +685,17 @@ export class Attributes {
|
|
|
664
685
|
throw new Error("Index creation timed out.");
|
|
665
686
|
}
|
|
666
687
|
|
|
667
|
-
|
|
688
|
+
if (indexes.length > 0) {
|
|
689
|
+
success(`Created ${indexes.length} indexes`);
|
|
690
|
+
}
|
|
668
691
|
};
|
|
669
692
|
|
|
670
693
|
public createAttributes = async (
|
|
671
694
|
attributes: any[],
|
|
672
695
|
collection: Collection,
|
|
673
696
|
): Promise<void> => {
|
|
697
|
+
log(`Creating attributes ...`);
|
|
698
|
+
|
|
674
699
|
for (let attribute of attributes) {
|
|
675
700
|
if (attribute.side !== "child") {
|
|
676
701
|
await this.createAttribute(
|
|
@@ -694,13 +719,17 @@ export class Attributes {
|
|
|
694
719
|
}
|
|
695
720
|
|
|
696
721
|
const createdCount = attributes.filter((a) => a.side !== "child").length;
|
|
697
|
-
|
|
722
|
+
if (createdCount > 0) {
|
|
723
|
+
success(`Created ${createdCount} attributes`);
|
|
724
|
+
}
|
|
698
725
|
};
|
|
699
726
|
|
|
700
727
|
public createColumns = async (
|
|
701
728
|
columns: any[],
|
|
702
729
|
table: Collection,
|
|
703
730
|
): Promise<void> => {
|
|
731
|
+
log(`Creating columns ...`);
|
|
732
|
+
|
|
704
733
|
for (let column of columns) {
|
|
705
734
|
if (column.side !== "child") {
|
|
706
735
|
await this.createAttribute(table["databaseId"], table["$id"], column);
|
|
@@ -720,6 +749,8 @@ export class Attributes {
|
|
|
720
749
|
}
|
|
721
750
|
|
|
722
751
|
const createdCount = columns.filter((c) => c.side !== "child").length;
|
|
723
|
-
|
|
752
|
+
if (createdCount > 0) {
|
|
753
|
+
success(`Created ${createdCount} columns`);
|
|
754
|
+
}
|
|
724
755
|
};
|
|
725
756
|
}
|
|
@@ -14,14 +14,6 @@ export class Pools {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
public setPollMaxDebounces(value: number): void {
|
|
18
|
-
this.pollMaxDebounces = value;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
public getPollMaxDebounces(): number {
|
|
22
|
-
return this.pollMaxDebounces;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
17
|
public wipeAttributes = async (
|
|
26
18
|
databaseId: string,
|
|
27
19
|
collectionId: string,
|
|
@@ -226,65 +218,6 @@ export class Pools {
|
|
|
226
218
|
);
|
|
227
219
|
};
|
|
228
220
|
|
|
229
|
-
public deleteIndexes = async (
|
|
230
|
-
databaseId: string,
|
|
231
|
-
collectionId: string,
|
|
232
|
-
indexesKeys: any[],
|
|
233
|
-
iteration: number = 1,
|
|
234
|
-
): Promise<boolean> => {
|
|
235
|
-
if (iteration > this.pollMaxDebounces) {
|
|
236
|
-
return false;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (this.pollMaxDebounces === this.POLL_DEFAULT_VALUE) {
|
|
240
|
-
let steps = Math.max(1, Math.ceil(indexesKeys.length / this.STEP_SIZE));
|
|
241
|
-
if (steps > 1 && iteration === 1) {
|
|
242
|
-
this.pollMaxDebounces *= steps;
|
|
243
|
-
|
|
244
|
-
log(
|
|
245
|
-
"Found a large number of indexes to be deleted. Increasing timeout to " +
|
|
246
|
-
(this.pollMaxDebounces * this.POLL_DEBOUNCE) / 1000 / 60 +
|
|
247
|
-
" minutes",
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const { indexes } = await paginate(
|
|
253
|
-
async (args: any) => {
|
|
254
|
-
const databasesService = await getDatabasesService();
|
|
255
|
-
return await databasesService.listIndexes(
|
|
256
|
-
args.databaseId,
|
|
257
|
-
args.collectionId,
|
|
258
|
-
args.queries || [],
|
|
259
|
-
);
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
databaseId,
|
|
263
|
-
collectionId,
|
|
264
|
-
},
|
|
265
|
-
100,
|
|
266
|
-
"indexes",
|
|
267
|
-
);
|
|
268
|
-
|
|
269
|
-
const indexKeySet = new Set(indexes.map((i: any) => i.key));
|
|
270
|
-
const ready = indexesKeys.filter((index: any) =>
|
|
271
|
-
indexKeySet.has(index.key),
|
|
272
|
-
);
|
|
273
|
-
|
|
274
|
-
if (ready.length === 0) {
|
|
275
|
-
return true;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
await new Promise((resolve) => setTimeout(resolve, this.POLL_DEBOUNCE));
|
|
279
|
-
|
|
280
|
-
return await this.deleteIndexes(
|
|
281
|
-
databaseId,
|
|
282
|
-
collectionId,
|
|
283
|
-
indexesKeys,
|
|
284
|
-
iteration + 1,
|
|
285
|
-
);
|
|
286
|
-
};
|
|
287
|
-
|
|
288
221
|
public expectIndexes = async (
|
|
289
222
|
databaseId: string,
|
|
290
223
|
collectionId: string,
|