Skip to content

Commit 61037c1

Browse files
Merge pull request #1095 from appwrite/fix-attribute-creation-errors
fix: add unsupported attribute error
2 parents 93ffb24 + a94668e commit 61037c1

File tree

12 files changed

+106
-21
lines changed

12 files changed

+106
-21
lines changed

src/SDK/Language/CLI.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ public function getFiles(): array
125125
'destination' => 'README.md',
126126
'template' => 'cli/README.md.twig',
127127
],
128+
[
129+
'scope' => 'default',
130+
'destination' => 'CHANGELOG.md',
131+
'template' => 'cli/CHANGELOG.md.twig',
132+
],
128133
[
129134
'scope' => 'default',
130135
'destination' => 'package.json',

templates/cli/CHANGELOG.md.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{sdk.changelog}}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const ID = require("../id");
99
const { questionsLogin, questionsLogout, questionsListFactors, questionsMfaChallenge } = require("../questions");
1010
const { accountUpdateMfaChallenge, accountCreateMfaChallenge, accountGet, accountCreateEmailPasswordSession, accountDeleteSession } = require("./account");
1111

12-
const DEFAULT_ENDPOINT = 'https://cloud.appwrite.io/v1';
12+
const DEFAULT_ENDPOINT = '{{ spec.endpoint }}';
1313

1414
const loginCommand = async ({ email, password, endpoint, mfa, code }) => {
1515
const oldCurrent = globalConfig.getCurrentSession();

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const { cliConfig, success, log, hint, error, actionRunner, commandDescriptions
2828
const { accountGet } = require("./account");
2929
const { sitesListTemplates } = require("./sites");
3030
const { sdkForConsole } = require("../sdks");
31+
const { isCloud } = require('../utils');
3132

3233
const initResources = async () => {
3334
const actions = {
@@ -94,6 +95,9 @@ const initProject = async ({ organizationId, projectId, projectName } = {}) => {
9495
}
9596
}
9697

98+
localConfig.clear(); // Clear the config to avoid any conflicts
99+
const url = new URL("{{ spec.endpoint }}");
100+
97101
if (answers.start === 'new') {
98102
response = await projectsCreate({
99103
projectId: answers.id,
@@ -103,8 +107,14 @@ const initProject = async ({ organizationId, projectId, projectName } = {}) => {
103107
})
104108

105109
localConfig.setProject(response['$id']);
110+
if (answers.region) {
111+
localConfig.setEndpoint(`https://${answers.region}.${url.host}${url.pathname}`);
112+
}
106113
} else {
107-
localConfig.setProject(answers.project);
114+
localConfig.setProject(answers.project["$id"]);
115+
if(isCloud()) {
116+
localConfig.setEndpoint(`https://${answers.project["region"]}.${url.host}${url.pathname}`);
117+
}
108118
}
109119

110120
success(`Project successfully ${answers.start === 'existing' ? 'linked' : 'created'}. Details are now stored in appwrite.json file.`);

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

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,8 @@ const createAttribute = (databaseId, collectionId, attribute) => {
568568
onDelete: attribute.onDelete,
569569
parseOutput: false
570570
})
571+
default:
572+
throw new Error(`Unsupported attribute type: ${attribute.type}`);
571573
}
572574
}
573575

@@ -685,6 +687,8 @@ const updateAttribute = (databaseId, collectionId, attribute) => {
685687
onDelete: attribute.onDelete,
686688
parseOutput: false
687689
})
690+
default:
691+
throw new Error(`Unsupported attribute type: ${attribute.type}`);
688692
}
689693
}
690694
const deleteAttribute = async (collection, attribute, isIndex = false) => {
@@ -708,6 +712,33 @@ const deleteAttribute = async (collection, attribute, isIndex = false) => {
708712
});
709713
}
710714

715+
const isEqual = (a, b) => {
716+
if (a === b) return true;
717+
718+
if (a && b && typeof a === 'object' && typeof b === 'object') {
719+
if (a.constructor && a.constructor.name === 'BigNumber' &&
720+
b.constructor && b.constructor.name === 'BigNumber') {
721+
return a.eq(b);
722+
}
723+
724+
if (typeof a.equals === 'function') {
725+
return a.equals(b);
726+
}
727+
728+
if (typeof a.eq === 'function') {
729+
return a.eq(b);
730+
}
731+
}
732+
733+
if (typeof a === 'number' && typeof b === 'number') {
734+
if (isNaN(a) && isNaN(b)) return true;
735+
if (!isFinite(a) && !isFinite(b)) return a === b;
736+
return Math.abs(a - b) < Number.EPSILON;
737+
}
738+
739+
return false;
740+
};
741+
711742
const compareAttribute = (remote, local, reason, key) => {
712743
if (isEmpty(remote) && isEmpty(local)) {
713744
return reason;
@@ -718,7 +749,7 @@ const compareAttribute = (remote, local, reason, key) => {
718749
const bol = reason === '' ? '' : '\n';
719750
reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`;
720751
}
721-
} else if (remote !== local) {
752+
} else if (!isEqual(remote, local)) {
722753
const bol = reason === '' ? '' : '\n';
723754
reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`;
724755
}
@@ -733,16 +764,16 @@ const compareAttribute = (remote, local, reason, key) => {
733764
* @param remote
734765
* @param local
735766
* @param collection
736-
* @param recraeting when true will check only non-changeable keys
767+
* @param recreating when true will check only non-changeable keys
737768
* @returns {undefined|{reason: string, action: *, attribute, key: string}}
738769
*/
739-
const checkAttributeChanges = (remote, local, collection, recraeting = true) => {
770+
const checkAttributeChanges = (remote, local, collection, recreating = true) => {
740771
if (local === undefined) {
741772
return undefined;
742773
}
743774

744775
const keyName = `${chalk.yellow(local.key)} in ${collection.name} (${collection['$id']})`;
745-
const action = chalk.cyan(recraeting ? 'recreating' : 'changing');
776+
const action = chalk.cyan(recreating ? 'recreating' : 'changing');
746777
let reason = '';
747778
let attribute = remote;
748779

@@ -752,17 +783,17 @@ const checkAttributeChanges = (remote, local, collection, recraeting = true) =>
752783
}
753784

754785
if (changeableKeys.includes(key)) {
755-
if (!recraeting) {
756-
reason += compareAttribute(remote[key], local[key], reason, key)
786+
if (!recreating) {
787+
reason = compareAttribute(remote[key], local[key], reason, key)
757788
}
758789
continue;
759790
}
760791

761-
if (!recraeting) {
792+
if (!recreating) {
762793
continue;
763794
}
764795

765-
reason += compareAttribute(remote[key], local[key], reason, key)
796+
reason = compareAttribute(remote[key], local[key], reason, key)
766797
}
767798

768799
return reason === '' ? undefined : { key: keyName, attribute, reason, action };

templates/cli/lib/config.js.twig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@ class Local extends Config {
150150
return _path.dirname(this.path)
151151
}
152152

153+
getEndpoint() {
154+
return this.get('endpoint') || '';
155+
}
156+
157+
setEndpoint(endpoint) {
158+
this.set('endpoint', endpoint);
159+
}
160+
153161
getSites() {
154162
if (!this.has("sites")) {
155163
return [];

templates/cli/lib/parser.js.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const { description } = require('../package.json');
55
const { globalConfig } = require("./config.js");
66
const os = require('os');
77
const Client = require("./client");
8+
const { isCloud } = require("./utils");
89

910
const cliConfig = {
1011
verbose: false,
@@ -111,7 +112,6 @@ const parseError = (err) => {
111112
(async () => {
112113
let appwriteVersion = 'unknown';
113114
const endpoint = globalConfig.getEndpoint();
114-
const isCloud = endpoint.includes('cloud.appwrite.io') ? 'Yes' : 'No';
115115

116116
try {
117117
const client = new Client().setEndpoint(endpoint);
@@ -122,7 +122,7 @@ const parseError = (err) => {
122122

123123
const version = '{{ sdk.version }}';
124124
const stepsToReproduce = `Running \`appwrite ${cliConfig.reportData.data.args.join(' ')}\``;
125-
const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud}`;
125+
const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud()}`;
126126

127127
const stack = '```\n' + err.stack + '\n```';
128128

templates/cli/lib/questions.js.twig

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const { validateRequired } = require("./validations");
1111
const { paginate } = require('./paginate');
1212
const { isPortTaken } = require('./utils');
1313
const { databasesList } = require('./commands/databases');
14-
const { checkDeployConditions } = require('./utils');
14+
const { checkDeployConditions, isCloud } = require('./utils');
1515
const JSONbig = require("json-bigint")({ storeAsString: false });
1616
const { sitesListFrameworks, sitesListSpecifications, sitesList } = require('./commands/sites');
1717

@@ -154,8 +154,7 @@ const questionsInitProject = [
154154
message: "Choose your organization",
155155
choices: async () => {
156156
let client = await sdkForConsole(true);
157-
const hostname = new URL(client.endpoint).hostname;
158-
const { teams } = hostname.endsWith('appwrite.io')
157+
const { teams } = isCloud()
159158
? await paginate(organizationsList, { parseOutput: false, sdk: client }, 100, 'teams')
160159
: await paginate(teamsList, { parseOutput: false, sdk: client }, 100, 'teams');
161160

@@ -203,17 +202,41 @@ const questionsInitProject = [
203202
let choices = projects.map((project) => {
204203
return {
205204
name: `${project.name} (${project['$id']})`,
206-
value: project['$id']
205+
value: {
206+
"$id": project['$id'],
207+
"region": project.region || ''
208+
}
207209
}
208210
})
209211

210-
if (choices.length == 0) {
212+
if (choices.length === 0) {
211213
throw new Error("No projects found. Please create a new project.")
212214
}
213215

214216
return choices;
215217
},
216218
when: (answer) => answer.start === 'existing'
219+
},
220+
{
221+
type: "list",
222+
name: "region",
223+
message: "Select your Appwrite Cloud region",
224+
choices: async () => {
225+
let client = await sdkForConsole(true);
226+
let response = await client.call("GET", "/console/regions");
227+
let regions = response.regions || [];
228+
if (!regions.length) {
229+
throw new Error("No regions found. Please check your network or Appwrite Cloud availability.");
230+
}
231+
return regions.filter(region => !region.disabled).map(region => ({
232+
name: `${region.name} (${region.$id})`,
233+
value: region.$id
234+
}));
235+
},
236+
when: (answer) => {
237+
if (answer.start === 'existing') return false;
238+
return isCloud();
239+
}
217240
}
218241
];
219242
const questionsInitProjectAutopull = [

templates/cli/lib/sdks.js.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const sdkForConsole = async (requiresAuth = true) => {
2323

2424
const sdkForProject = async () => {
2525
let client = new Client();
26-
let endpoint = globalConfig.getEndpoint();
26+
let endpoint = localConfig.getEndpoint() || globalConfig.getEndpoint();
2727
let project = localConfig.getProject().projectId ? localConfig.getProject().projectId : globalConfig.getProject();
2828
let key = globalConfig.getKey();
2929
let cookie = globalConfig.getCookie()

templates/cli/lib/type-generation/attribute.js.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const AttributeType = {
22
STRING: "string",
33
INTEGER: "integer",
4-
FLOAT: "float",
4+
FLOAT: "double",
55
BOOLEAN: "boolean",
66
DATETIME: "datetime",
77
EMAIL: "email",

0 commit comments

Comments
 (0)