appwrite-cli 9.0.2 → 10.0.0

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +2 -2
  3. package/docs/examples/databases/create-line-attribute.md +5 -0
  4. package/docs/examples/databases/create-point-attribute.md +5 -0
  5. package/docs/examples/databases/create-polygon-attribute.md +5 -0
  6. package/docs/examples/databases/update-line-attribute.md +5 -0
  7. package/docs/examples/databases/update-point-attribute.md +5 -0
  8. package/docs/examples/databases/update-polygon-attribute.md +5 -0
  9. package/docs/examples/tablesdb/create-line-column.md +5 -0
  10. package/docs/examples/tablesdb/create-point-column.md +5 -0
  11. package/docs/examples/tablesdb/create-polygon-column.md +5 -0
  12. package/docs/examples/tablesdb/update-line-column.md +5 -0
  13. package/docs/examples/tablesdb/update-point-column.md +5 -0
  14. package/docs/examples/tablesdb/update-polygon-column.md +5 -0
  15. package/index.js +0 -2
  16. package/install.ps1 +2 -2
  17. package/install.sh +1 -1
  18. package/lib/client.js +2 -2
  19. package/lib/commands/databases.js +336 -0
  20. package/lib/commands/functions.js +2 -2
  21. package/lib/commands/generic.js +5 -5
  22. package/lib/commands/init.js +3 -1
  23. package/lib/commands/pull.js +24 -12
  24. package/lib/commands/push.js +27 -9
  25. package/lib/commands/tables-db.js +338 -2
  26. package/lib/commands/types.js +54 -15
  27. package/lib/config.js +57 -33
  28. package/lib/parser.js +5 -2
  29. package/lib/questions.js +6 -6
  30. package/lib/type-generation/languages/csharp.js +170 -0
  31. package/lib/type-generation/languages/javascript.js +2 -2
  32. package/lib/type-generation/languages/typescript.js +4 -2
  33. package/package.json +1 -1
  34. package/scoop/appwrite.config.json +3 -3
  35. package/docs/examples/avatars/get-browser.md +0 -2
  36. package/docs/examples/avatars/get-credit-card.md +0 -2
  37. package/docs/examples/avatars/get-favicon.md +0 -2
  38. package/docs/examples/avatars/get-flag.md +0 -2
  39. package/docs/examples/avatars/get-image.md +0 -2
  40. package/docs/examples/avatars/get-initials.md +0 -1
  41. package/docs/examples/avatars/get-qr.md +0 -2
  42. package/lib/commands/avatars.js +0 -484
@@ -12,6 +12,7 @@ const { Swift } = require("../type-generation/languages/swift");
12
12
  const { Java } = require("../type-generation/languages/java");
13
13
  const { Dart } = require("../type-generation/languages/dart");
14
14
  const { JavaScript } = require("../type-generation/languages/javascript");
15
+ const { CSharp } = require("../type-generation/languages/csharp");
15
16
 
16
17
  /**
17
18
  * @param {string} language
@@ -33,6 +34,8 @@ function createLanguageMeta(language) {
33
34
  return new Java();
34
35
  case "dart":
35
36
  return new Dart();
37
+ case "cs":
38
+ return new CSharp();
36
39
  default:
37
40
  throw new Error(`Language '${language}' is not supported`);
38
41
  }
@@ -55,7 +58,7 @@ const typesLanguageOption = new Option(
55
58
  "-l, --language <language>",
56
59
  "The language of the types"
57
60
  )
58
- .choices(["auto", "ts", "js", "php", "kotlin", "swift", "java", "dart"])
61
+ .choices(["auto", "ts", "js", "php", "kotlin", "swift", "java", "dart", "cs"])
59
62
  .default("auto");
60
63
 
61
64
  const typesStrictOption = new Option(
@@ -97,22 +100,58 @@ const typesCommand = actionRunner(async (rawOutputDirectory, {language, strict})
97
100
  fs.mkdirSync(outputDirectory, { recursive: true });
98
101
  }
99
102
 
100
- const collections = localConfig.getCollections();
101
- if (collections.length === 0) {
102
- const configFileName = path.basename(localConfig.path);
103
- throw new Error(`No collections found in configuration. Make sure ${configFileName} exists and contains collections.`);
103
+ // Try tables first, fallback to collections
104
+ let tables = localConfig.getTables();
105
+ let collections = [];
106
+ let dataSource = 'tables';
107
+
108
+ if (tables.length === 0) {
109
+ collections = localConfig.getCollections();
110
+ dataSource = 'collections';
111
+
112
+ if (collections.length === 0) {
113
+ const configFileName = path.basename(localConfig.path);
114
+ throw new Error(`No tables or collections found in configuration. Make sure ${configFileName} exists and contains tables or collections.`);
115
+ }
116
+ }
117
+
118
+ // Use tables if available, otherwise use collections
119
+ let dataItems = tables.length > 0 ? tables : collections;
120
+ const itemType = tables.length > 0 ? 'tables' : 'collections';
121
+
122
+ // Normalize tables data: rename 'columns' to 'attributes' for template compatibility
123
+ if (tables.length > 0) {
124
+ dataItems = dataItems.map(table => {
125
+ const { columns, ...rest } = table;
126
+ return {
127
+ ...rest,
128
+ attributes: (columns || []).map(column => {
129
+ if (column.relatedTable) {
130
+ const { relatedTable, ...columnRest } = column;
131
+ return {
132
+ ...columnRest,
133
+ relatedCollection: relatedTable
134
+ };
135
+ }
136
+ return column;
137
+ })
138
+ };
139
+ });
104
140
  }
105
141
 
106
- log(`Found ${collections.length} collections: ${collections.map(c => c.name).join(", ")}`);
142
+ log(`Found ${dataItems.length} ${itemType}: ${dataItems.map(c => c.name).join(", ")}`);
143
+
144
+ // Use columns if available, otherwise use attributes
145
+ const resourceType = tables.length > 0 ? 'columns' : 'attributes';
107
146
 
108
- const totalAttributes = collections.reduce((count, collection) => count + collection.attributes.length, 0);
109
- log(`Found ${totalAttributes} attributes across all collections`);
147
+ const totalAttributes = dataItems.reduce((count, item) => count + (item.attributes || []).length, 0);
148
+ log(`Found ${totalAttributes} ${resourceType} across all ${itemType}`);
110
149
 
111
150
  const templater = ejs.compile(meta.getTemplate());
112
151
 
113
152
  if (meta.isSingleFile()) {
114
153
  const content = templater({
115
- collections,
154
+ collections: dataItems,
116
155
  strict,
117
156
  ...templateHelpers,
118
157
  getType: meta.getType,
@@ -123,23 +162,23 @@ const typesCommand = actionRunner(async (rawOutputDirectory, {language, strict})
123
162
  fs.writeFileSync(destination, content);
124
163
  log(`Added types to ${destination}`);
125
164
  } else {
126
- for (const collection of collections) {
165
+ for (const item of dataItems) {
127
166
  const content = templater({
128
- collections,
129
- collection,
167
+ collections: dataItems,
168
+ collection: item,
130
169
  strict,
131
170
  ...templateHelpers,
132
171
  getType: meta.getType,
133
172
  });
134
173
 
135
- const destination = path.join(outputDirectory, meta.getFileName(collection));
174
+ const destination = path.join(outputDirectory, meta.getFileName(item));
136
175
 
137
176
  fs.writeFileSync(destination, content);
138
- log(`Added types for ${collection.name} to ${destination}`);
177
+ log(`Added types for ${item.name} to ${destination}`);
139
178
  }
140
179
  }
141
180
 
142
- success(`Generated types for all the listed collections`);
181
+ success(`Generated types for all the listed ${itemType}`);
143
182
  });
144
183
 
145
184
  const types = new Command("types")
package/lib/config.js CHANGED
@@ -55,7 +55,7 @@ const KeysColumns = new Set([
55
55
  // enum
56
56
  "elements",
57
57
  // relationship
58
- "relatedCollection",
58
+ "relatedTable",
59
59
  "relationType",
60
60
  "twoWay",
61
61
  "twoWayKey",
@@ -150,6 +150,47 @@ class Config {
150
150
  toString() {
151
151
  return JSONbig.stringify(this.data, null, 4);
152
152
  }
153
+
154
+ _getDBEntities(entityType) {
155
+ if (!this.has(entityType)) {
156
+ return [];
157
+ }
158
+ return this.get(entityType);
159
+ }
160
+
161
+ _getDBEntity(entityType, $id) {
162
+ if (!this.has(entityType)) {
163
+ return {};
164
+ }
165
+
166
+ let entities = this.get(entityType);
167
+ for (let i = 0; i < entities.length; i++) {
168
+ if (entities[i]['$id'] == $id) {
169
+ return entities[i];
170
+ }
171
+ }
172
+
173
+ return {};
174
+ }
175
+
176
+ _addDBEntity(entityType, props, keysSet, nestedKeys = {}) {
177
+ props = whitelistKeys(props, keysSet, nestedKeys);
178
+
179
+ if (!this.has(entityType)) {
180
+ this.set(entityType, []);
181
+ }
182
+
183
+ let entities = this.get(entityType);
184
+ for (let i = 0; i < entities.length; i++) {
185
+ if (entities[i]['$id'] == props['$id']) {
186
+ entities[i] = props;
187
+ this.set(entityType, entities);
188
+ return;
189
+ }
190
+ }
191
+ entities.push(props);
192
+ this.set(entityType, entities);
193
+ }
153
194
  }
154
195
 
155
196
  class Local extends Config {
@@ -464,45 +505,28 @@ class Local extends Config {
464
505
  this.set("topics", topics);
465
506
  }
466
507
 
467
- getDatabases() {
468
- if (!this.has("databases")) {
469
- return [];
470
- }
471
- return this.get("databases");
508
+ getTablesDBs() {
509
+ return this._getDBEntities("tablesDB");
472
510
  }
473
511
 
474
- getDatabase($id) {
475
- if (!this.has("databases")) {
476
- return {};
477
- }
512
+ getTablesDB($id) {
513
+ return this._getDBEntity("tablesDB", $id);
514
+ }
515
+
516
+ addTablesDB(props) {
517
+ this._addDBEntity("tablesDB", props, KeysDatabase);
518
+ }
478
519
 
479
- let databases = this.get("databases");
480
- for (let i = 0; i < databases.length; i++) {
481
- if (databases[i]['$id'] == $id) {
482
- return databases[i];
483
- }
484
- }
520
+ getDatabases() {
521
+ return this._getDBEntities("databases");
522
+ }
485
523
 
486
- return {};
524
+ getDatabase($id) {
525
+ return this._getDBEntity("databases", $id);
487
526
  }
488
527
 
489
528
  addDatabase(props) {
490
- props = whitelistKeys(props, KeysDatabase);
491
-
492
- if (!this.has("databases")) {
493
- this.set("databases", []);
494
- }
495
-
496
- let databases = this.get("databases");
497
- for (let i = 0; i < databases.length; i++) {
498
- if (databases[i]['$id'] == props['$id']) {
499
- databases[i] = props;
500
- this.set("databases", databases);
501
- return;
502
- }
503
- }
504
- databases.push(props);
505
- this.set("databases", databases);
529
+ this._addDBEntity("databases", props, KeysDatabase);
506
530
  }
507
531
 
508
532
  getTeams() {
package/lib/parser.js CHANGED
@@ -122,7 +122,7 @@ const parseError = (err) => {
122
122
  } catch {
123
123
  }
124
124
 
125
- const version = '9.0.2';
125
+ const version = '10.0.0';
126
126
  const stepsToReproduce = `Running \`appwrite ${cliConfig.reportData.data.args.join(' ')}\``;
127
127
  const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud()}`;
128
128
 
@@ -205,7 +205,8 @@ const commandDescriptions = {
205
205
  "account": `The account command allows you to authenticate and manage a user account.`,
206
206
  "graphql": `The graphql command allows you to query and mutate any resource type on your Appwrite server.`,
207
207
  "avatars": `The avatars command aims to help you complete everyday tasks related to your app image, icons, and avatars.`,
208
- "databases": `The databases command allows you to create structured collections of documents and query and filter lists of documents.`,
208
+ "databases": `(Legacy) The databases command allows you to create structured collections of documents and query and filter lists of documents.`,
209
+ 'tables-db': `The tables-db command allows you to create structured tables of columns and query and filter lists of rows.`,
209
210
  "init": `The init command provides a convenient wrapper for creating and initializing projects, functions, collections, buckets, teams, and messaging-topics in Appwrite.`,
210
211
  "push": `The push command provides a convenient wrapper for pushing your functions, collections, buckets, teams, and messaging-topics.`,
211
212
  "run": `The run command allows you to run the project locally to allow easy development and quick debugging.`,
@@ -218,6 +219,8 @@ const commandDescriptions = {
218
219
  "teams": `The teams command allows you to group users of your project to enable them to share read and write access to your project resources.`,
219
220
  "update": `The update command allows you to update the Appwrite CLI to the latest version.`,
220
221
  "users": `The users command allows you to manage your project users.`,
222
+ "projects": `The projects command allows you to manage your projects, add platforms, manage API keys, Dev Keys etc.`,
223
+ "project": `The project command allows you to manage project related resources like usage, variables, etc.`,
221
224
  "client": `The client command allows you to configure your CLI`,
222
225
  "login": `The login command allows you to authenticate and manage a user account.`,
223
226
  "logout": `The logout command allows you to log out of your Appwrite account.`,
package/lib/questions.js CHANGED
@@ -5,7 +5,7 @@ const { projectsList } = require('./commands/projects');
5
5
  const { organizationsList } = require('./commands/organizations');
6
6
  const { teamsList } = require('./commands/teams');
7
7
  const { functionsListRuntimes, functionsListSpecifications, functionsList } = require('./commands/functions');
8
- const { accountListMfaFactors } = require("./commands/account");
8
+ const { accountListMFAFactors } = require("./commands/account");
9
9
  const { sdkForConsole } = require("./sdks");
10
10
  const { validateRequired } = require("./validations");
11
11
  const { paginate } = require('./paginate');
@@ -259,7 +259,7 @@ const questionsPullResources = [
259
259
  { name: `Buckets ${chalk.blackBright(`(Storage)`)}`, value: 'buckets' },
260
260
  { name: `Teams ${chalk.blackBright(`(Auth)`)}`, value: 'teams' },
261
261
  { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: 'messages' },
262
- { name: `Collections ${chalk.blackBright(`(Database)`)}`, value: 'collections' }
262
+ { name: `Collections ${chalk.blackBright(`(Legacy Databases)`)}`, value: 'collections' }
263
263
  ]
264
264
  }
265
265
  ]
@@ -671,7 +671,7 @@ const questionsPushResources = [
671
671
  { name: `Buckets ${chalk.blackBright(`(Storage)`)}`, value: 'buckets' },
672
672
  { name: `Teams ${chalk.blackBright(`(Auth)`)}`, value: 'teams' },
673
673
  { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: 'messages' },
674
- { name: `Collections ${chalk.blackBright(`(Database)`)}`, value: 'collections' }
674
+ { name: `Collections ${chalk.blackBright(`(Legacy Databases)`)}`, value: 'collections' }
675
675
  ]
676
676
  }
677
677
  ];
@@ -877,7 +877,7 @@ const questionsListFactors = [
877
877
  message: "Your account is protected by multi-factor authentication. Please choose one for verification.",
878
878
  choices: async () => {
879
879
  let client = await sdkForConsole(false);
880
- const factors = await accountListMfaFactors({
880
+ const factors = await accountListMFAFactors({
881
881
  sdk: client,
882
882
  parseOutput: false
883
883
  });
@@ -906,7 +906,7 @@ const questionsListFactors = [
906
906
  }
907
907
  ];
908
908
 
909
- const questionsMfaChallenge = [
909
+ const questionsMFAChallenge = [
910
910
  {
911
911
  type: "input",
912
912
  name: "otp",
@@ -1019,7 +1019,7 @@ module.exports = {
1019
1019
  questionsPushTeams,
1020
1020
  questionsGetEntrypoint,
1021
1021
  questionsListFactors,
1022
- questionsMfaChallenge,
1022
+ questionsMFAChallenge,
1023
1023
  questionsRunFunctions,
1024
1024
  questionGetEndpoint,
1025
1025
  questionsInitResources,
@@ -0,0 +1,170 @@
1
+ /** @typedef {import('../attribute').Attribute} Attribute */
2
+ const { AttributeType } = require('../attribute');
3
+ const { LanguageMeta } = require("./language");
4
+
5
+ class CSharp extends LanguageMeta {
6
+ getType(attribute, collections) {
7
+ let type = "";
8
+ switch (attribute.type) {
9
+ case AttributeType.STRING:
10
+ case AttributeType.EMAIL:
11
+ case AttributeType.DATETIME:
12
+ type = "string";
13
+ if (attribute.format === AttributeType.ENUM) {
14
+ type = LanguageMeta.toPascalCase(attribute.key);
15
+ }
16
+ break;
17
+ case AttributeType.INTEGER:
18
+ type = "long";
19
+ break;
20
+ case AttributeType.FLOAT:
21
+ type = "double";
22
+ break;
23
+ case AttributeType.BOOLEAN:
24
+ type = "bool";
25
+ break;
26
+ case AttributeType.RELATIONSHIP:
27
+ const relatedCollection = collections.find(c => c.$id === attribute.relatedCollection);
28
+ if (!relatedCollection) {
29
+ throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
30
+ }
31
+ type = LanguageMeta.toPascalCase(relatedCollection.name);
32
+ if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') {
33
+ type = `List<${type}>`;
34
+ }
35
+ break;
36
+ default:
37
+ throw new Error(`Unknown attribute type: ${attribute.type}`);
38
+ }
39
+ if (attribute.array) {
40
+ type = `List<${type}>`;
41
+ }
42
+ if (!attribute.required) {
43
+ type += "?";
44
+ }
45
+ return type;
46
+ }
47
+
48
+ getTemplate() {
49
+ return `/// This file is auto-generated by the Appwrite CLI.
50
+ /// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`.
51
+
52
+ #nullable enable
53
+ using System;
54
+ using System.Collections.Generic;
55
+ using System.Linq;
56
+ using System.Text.Json.Serialization;
57
+
58
+ namespace Appwrite.Models
59
+ {
60
+ <% for (const attribute of collection.attributes) { -%>
61
+ <% if (attribute.format === 'enum') { -%>
62
+
63
+ public enum <%- toPascalCase(attribute.key) %> {
64
+ <% for (const [index, element] of Object.entries(attribute.elements) ) { -%>
65
+ [JsonPropertyName("<%- element %>")]
66
+ <%- toPascalCase(element) %><% if (index < attribute.elements.length - 1) { %>,<% } %>
67
+ <% } -%>
68
+ }
69
+ <% } -%>
70
+ <% } %>
71
+ public class <%= toPascalCase(collection.name) %>
72
+ {
73
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
74
+ [JsonPropertyName("<%- attribute.key %>")]
75
+ public <%- getType(attribute, collections) %> <%= toPascalCase(attribute.key) %> { get; private set; }
76
+
77
+ <% } -%>
78
+
79
+ public <%= toPascalCase(collection.name) %>(
80
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
81
+ <%- getType(attribute, collections) %> <%= toCamelCase(attribute.key) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
82
+ <% } -%>
83
+ )
84
+ {
85
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
86
+ <%= toPascalCase(attribute.key) %> = <%= toCamelCase(attribute.key) %>;
87
+ <% } -%>
88
+ }
89
+
90
+ public static <%= toPascalCase(collection.name) %> From(Dictionary<string, object> map) => new <%= toPascalCase(collection.name) %>(
91
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
92
+ <%- toCamelCase(attribute.key) %>: <%
93
+ // ENUM
94
+ if (attribute.format === 'enum') {
95
+ if (attribute.array) {
96
+ -%>((IEnumerable<object>)map["<%- attribute.key %>"]).Select(e => Enum.Parse<Models.<%- toPascalCase(attribute.key) %>>(e.ToString()!, true)).ToList()<%
97
+ } else {
98
+ -%>Enum.Parse<Models.<%- toPascalCase(attribute.key) %>>(map["<%- attribute.key %>"].ToString()!, true)<%
99
+ }
100
+ // RELATIONSHIP
101
+ } else if (attribute.type === 'relationship') {
102
+ const relatedClass = toPascalCase(collections.find(c => c.$id === attribute.relatedCollection).name);
103
+ if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany' || attribute.array) {
104
+ -%>((IEnumerable<object>)map["<%- attribute.key %>"]).Select(it => Models.<%- relatedClass %>.From((Dictionary<string, object>)it)).ToList()<%
105
+ } else {
106
+ -%>Models.<%- relatedClass %>.From((Dictionary<string, object>)map["<%- attribute.key %>"])<%
107
+ }
108
+ // ARRAY TYPES
109
+ } else if (attribute.array) {
110
+ if (attribute.type === 'string' || attribute.type === 'datetime' || attribute.type === 'email') {
111
+ -%>((IEnumerable<object>)map["<%- attribute.key %>"]).Select(x => x?.ToString())<%- attribute.required ? '.Where(x => x != null)' : '' %>.ToList()!<%
112
+ } else if (attribute.type === 'integer') {
113
+ -%>((IEnumerable<object>)map["<%- attribute.key %>"]).Select(x => <%- !attribute.required ? 'x == null ? (long?)null : ' : '' %>Convert.ToInt64(x)).ToList()<%
114
+ } else if (attribute.type === 'double') {
115
+ -%>((IEnumerable<object>)map["<%- attribute.key %>"]).Select(x => <%- !attribute.required ? 'x == null ? (double?)null : ' : '' %>Convert.ToDouble(x)).ToList()<%
116
+ } else if (attribute.type === 'boolean') {
117
+ -%>((IEnumerable<object>)map["<%- attribute.key %>"]).Select(x => <%- !attribute.required ? 'x == null ? (bool?)null : ' : '' %>(bool)x).ToList()<%
118
+ }
119
+ // SINGLE VALUE TYPES
120
+ } else if (attribute.type === 'integer') {
121
+ -%><%- !attribute.required ? 'map["' + attribute.key + '"] == null ? null : ' : '' %>Convert.ToInt64(map["<%- attribute.key %>"])<%
122
+ } else if (attribute.type === 'double') {
123
+ -%><%- !attribute.required ? 'map["' + attribute.key + '"] == null ? null : ' : '' %>Convert.ToDouble(map["<%- attribute.key %>"])<%
124
+ } else if (attribute.type === 'boolean') {
125
+ -%>(<%- getType(attribute, collections) %>)map["<%- attribute.key %>"]<%
126
+ } else if (attribute.type === 'string' || attribute.type === 'datetime' || attribute.type === 'email') {
127
+ -%>map["<%- attribute.key %>"]<%- !attribute.required ? '?' : '' %>.ToString()<%- attribute.required ? '!' : ''%><%
128
+ } else {
129
+ -%>default<%
130
+ }
131
+ -%><% if (index < collection.attributes.length - 1) { %>,<% } %>
132
+ <% } -%>
133
+ );
134
+
135
+ public Dictionary<string, object?> ToMap() => new Dictionary<string, object?>()
136
+ {
137
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
138
+ { "<%- attribute.key %>", <%
139
+ // ENUM
140
+ if (attribute.format === 'enum') {
141
+ if (attribute.array) {
142
+ -%><%= toPascalCase(attribute.key) %>?.Select(e => e.ToString()).ToList()<%
143
+ } else {
144
+ -%><%= toPascalCase(attribute.key) %>?.ToString()<%
145
+ }
146
+ // RELATIONSHIP
147
+ } else if (attribute.type === 'relationship') {
148
+ if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany' || attribute.array) {
149
+ -%><%= toPascalCase(attribute.key) %>?.Select(e => e.ToMap()).ToList()<%
150
+ } else {
151
+ -%><%= toPascalCase(attribute.key) %>?.ToMap()<%
152
+ }
153
+ // OTHER
154
+ } else {
155
+ -%><%= toPascalCase(attribute.key) %><%
156
+ }
157
+ -%> }<% if (index < collection.attributes.length - 1) { %>,<% } %>
158
+ <% } -%>
159
+ };
160
+ }
161
+ }
162
+ `;
163
+ }
164
+
165
+ getFileName(collection) {
166
+ return LanguageMeta.toPascalCase(collection.name) + ".cs";
167
+ }
168
+ }
169
+
170
+ module.exports = { CSharp };
@@ -66,7 +66,7 @@ class JavaScript extends LanguageMeta {
66
66
 
67
67
  getTemplate() {
68
68
  return `/**
69
- * @typedef {import('${this._getAppwriteDependency()}').Models.Document} Document
69
+ * @typedef {import('${this._getAppwriteDependency()}').Models.Row} Row
70
70
  */
71
71
 
72
72
  // This file is auto-generated by the Appwrite CLI.
@@ -83,7 +83,7 @@ class JavaScript extends LanguageMeta {
83
83
  <% } -%>
84
84
  <% } -%>
85
85
  <% for (const [index, collection] of Object.entries(collections)) { %>/**
86
- * @typedef {Document & {
86
+ * @typedef {Row & {
87
87
  <% for (const attribute of collection.attributes) { -%>
88
88
  * <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute, collections) %>;
89
89
  <% } -%>
@@ -88,9 +88,11 @@ export enum <%- toPascalCase(attribute.key) %> {
88
88
  <% } -%>
89
89
  <% } -%>
90
90
  <% for (const [index, collection] of Object.entries(collections)) { -%>
91
- export type <%- toPascalCase(collection.name) %> = Models.Document & {
91
+ export type <%- toPascalCase(collection.name) %> = Models.Row & {
92
92
  <% for (const attribute of collection.attributes) { -%>
93
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute, collections) %>;
93
+ <% const propertyName = strict ? toCamelCase(attribute.key) : attribute.key; -%>
94
+ <% const isValidIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(propertyName); -%>
95
+ <% if (isValidIdentifier) { %><%- propertyName %><% } else { %>"<%- propertyName %>"<% } %>: <%- getType(attribute, collections) %>;
94
96
  <% } -%>
95
97
  }<% if (index < collections.length - 1) { %>
96
98
  <% } %>
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "appwrite-cli",
3
3
  "homepage": "https://appwrite.io/support",
4
4
  "description": "Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API",
5
- "version": "9.0.2",
5
+ "version": "10.0.0",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "index.js",
8
8
  "bin": {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/ScoopInstaller/Scoop/master/schema.json",
3
- "version": "9.0.2",
3
+ "version": "10.0.0",
4
4
  "description": "The Appwrite CLI is a command-line application that allows you to interact with Appwrite and perform server-side tasks using your terminal.",
5
5
  "homepage": "https://github.com/appwrite/sdk-for-cli",
6
6
  "license": "BSD-3-Clause",
7
7
  "architecture": {
8
8
  "64bit": {
9
- "url": "https://github.com/appwrite/sdk-for-cli/releases/download/9.0.2/appwrite-cli-win-x64.exe",
9
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/10.0.0/appwrite-cli-win-x64.exe",
10
10
  "bin": [
11
11
  [
12
12
  "appwrite-cli-win-x64.exe",
@@ -15,7 +15,7 @@
15
15
  ]
16
16
  },
17
17
  "arm64": {
18
- "url": "https://github.com/appwrite/sdk-for-cli/releases/download/9.0.2/appwrite-cli-win-arm64.exe",
18
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/10.0.0/appwrite-cli-win-arm64.exe",
19
19
  "bin": [
20
20
  [
21
21
  "appwrite-cli-win-arm64.exe",
@@ -1,2 +0,0 @@
1
- appwrite avatars get-browser \
2
- --code aa
@@ -1,2 +0,0 @@
1
- appwrite avatars get-credit-card \
2
- --code amex
@@ -1,2 +0,0 @@
1
- appwrite avatars get-favicon \
2
- --url https://example.com
@@ -1,2 +0,0 @@
1
- appwrite avatars get-flag \
2
- --code af
@@ -1,2 +0,0 @@
1
- appwrite avatars get-image \
2
- --url https://example.com
@@ -1 +0,0 @@
1
- appwrite avatars get-initials
@@ -1,2 +0,0 @@
1
- appwrite avatars get-qr \
2
- --text <TEXT>