Skip to content

Commit 8c5b2d7

Browse files
Merge remote-tracking branch 'origin' into spatial-type-queries
2 parents b759e2b + c514fe6 commit 8c5b2d7

File tree

48 files changed

+788
-236
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+788
-236
lines changed

composer.lock

Lines changed: 216 additions & 140 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/SDK/Language/CLI.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ public function getFiles(): array
231231
'destination' => 'lib/type-generation/languages/dart.js',
232232
'template' => 'cli/lib/type-generation/languages/dart.js.twig',
233233
],
234+
[
235+
'scope' => 'default',
236+
'destination' => 'lib/type-generation/languages/csharp.js',
237+
'template' => 'cli/lib/type-generation/languages/csharp.js.twig',
238+
],
234239
[
235240
'scope' => 'default',
236241
'destination' => 'lib/questions.js',

templates/android/library/src/main/java/io/package/Query.kt.twig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,15 @@ class Query(
254254
*/
255255
fun createdAfter(value: String) = Query("createdAfter", null, listOf(value)).toJson()
256256

257+
/**
258+
* Filter resources where document was created between start and end dates (inclusive).
259+
*
260+
* @param start The start date value.
261+
* @param end The end date value.
262+
* @returns The query string.
263+
*/
264+
fun createdBetween(start: String, end: String) = Query("createdBetween", null, listOf(start, end)).toJson()
265+
257266
/**
258267
* Filter resources where document was updated before date.
259268
*
@@ -270,6 +279,15 @@ class Query(
270279
*/
271280
fun updatedAfter(value: String) = Query("updatedAfter", null, listOf(value)).toJson()
272281

282+
/**
283+
* Filter resources where document was updated between start and end dates (inclusive).
284+
*
285+
* @param start The start date value.
286+
* @param end The end date value.
287+
* @returns The query string.
288+
*/
289+
fun updatedBetween(start: String, end: String) = Query("updatedBetween", null, listOf(start, end)).toJson()
290+
273291
/**
274292
* Combine multiple queries using logical OR operator.
275293
*

templates/cli/lib/client.js.twig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const os = require('os');
2+
const join = require('path').join;
23
const https = require("https");
34
const { fetch, FormData, Agent } = require("undici");
45
const JSONbig = require("json-bigint")({ storeAsString: false });
@@ -99,7 +100,7 @@ class Client {
99100

100101
async call(method, path = "", headers = {}, params = {}, responseType = "json") {
101102
headers = {...this.headers, ...headers};
102-
const url = new URL(this.endpoint + path);
103+
const url = new URL(join(this.endpoint + path));
103104

104105
let body = undefined;
105106

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ const { globalConfig, localConfig } = require("../config");
66
const { actionRunner, success, parseBool, commandDescriptions, error, parse, hint, log, drawTable, cliConfig } = require("../parser");
77
const ID = require("../id");
88
{% if sdk.test != "true" %}
9-
const { questionsLogin, questionsLogout, questionsListFactors, questionsMfaChallenge } = require("../questions");
10-
const { accountUpdateMfaChallenge, accountCreateMfaChallenge, accountGet, accountCreateEmailPasswordSession, accountDeleteSession } = require("./account");
9+
const { questionsLogin, questionsLogout, questionsListFactors, questionsMFAChallenge } = require("../questions");
10+
const { accountUpdateMFAChallenge, accountCreateMFAChallenge, accountGet, accountCreateEmailPasswordSession, accountDeleteSession } = require("./account");
1111

1212
const DEFAULT_ENDPOINT = '{{ spec.endpoint }}';
1313

@@ -72,15 +72,15 @@ const loginCommand = async ({ email, password, endpoint, mfa, code }) => {
7272
if (error.response === 'user_more_factors_required') {
7373
const { factor } = mfa ? { factor: mfa } : await inquirer.prompt(questionsListFactors);
7474

75-
const challenge = await accountCreateMfaChallenge({
75+
const challenge = await accountCreateMFAChallenge({
7676
factor,
7777
parseOutput: false,
7878
sdk: client
7979
});
8080

81-
const { otp } = code ? { otp: code } : await inquirer.prompt(questionsMfaChallenge);
81+
const { otp } = code ? { otp: code } : await inquirer.prompt(questionsMFAChallenge);
8282

83-
await accountUpdateMfaChallenge({
83+
await accountUpdateMFAChallenge({
8484
challengeId: challenge.$id,
8585
otp,
8686
parseOutput: false,

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,9 @@ const initProject = async ({ organizationId, projectId, projectName } = {}) => {
124124
if(answers.autopull) {
125125
cliConfig.all = true;
126126
cliConfig.force = true;
127-
await pullResources();
127+
await pullResources({
128+
skipDeprecated: true
129+
});
128130
} else {
129131
log("You can run 'appwrite pull all' to synchronize all of your existing resources.");
130132
}

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ const { paginate } = require("../paginate");
1616
const { questionsPullCollection, questionsPullFunctions, questionsPullFunctionsCode, questionsPullSites, questionsPullSitesCode, questionsPullResources } = require("../questions");
1717
const { cliConfig, success, log, warn, actionRunner, commandDescriptions } = require("../parser");
1818

19-
const pullResources = async () => {
19+
const pullResources = async ({
20+
skipDeprecated = false
21+
} = {}) => {
2022
const actions = {
2123
settings: pullSettings,
2224
functions: pullFunctions,
@@ -28,6 +30,10 @@ const pullResources = async () => {
2830
messages: pullMessagingTopic
2931
}
3032

33+
if (skipDeprecated) {
34+
delete actions.collections;
35+
}
36+
3137
if (cliConfig.all) {
3238
for (let action of Object.values(actions)) {
3339
cliConfig.all = true;
@@ -372,7 +378,7 @@ const pullTable = async () => {
372378
total++;
373379
log(`Pulling all tables from ${chalk.bold(database['name'])} database ...`);
374380

375-
localConfig.addDatabase(database);
381+
localConfig.addTablesDB(database);
376382

377383
const { tables } = await paginate(tablesDBListTables, {
378384
databaseId,

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

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ const {
5151
} = require("./databases");
5252
const {
5353
tablesDBGet,
54-
tablesDBGetTable
54+
tablesDBGetTable,
55+
tablesDBUpdateTable,
56+
tablesDBCreateTable
5557
} = require("./tables-db");
5658
const {
5759
storageGetBucket, storageUpdateBucket, storageCreateBucket
@@ -892,7 +894,7 @@ const createIndexes = async (indexes, collection) => {
892894
);
893895

894896
if (!result) {
895-
throw new Error("Index creation timed out.");
897+
throw new Error('Index creation timed out.');
896898
}
897899

898900
success(`Created ${indexes.length} indexes`);
@@ -916,6 +918,25 @@ const createAttributes = async (attributes, collection) => {
916918

917919
success(`Created ${attributes.length} attributes`);
918920
}
921+
const createColumns = async (columns, table) => {
922+
for (let column of columns) {
923+
if (column.side !== 'child') {
924+
await createAttribute(table['databaseId'], table['$id'], column);
925+
}
926+
}
927+
928+
const result = await awaitPools.expectAttributes(
929+
table['databaseId'],
930+
table['$id'],
931+
table.columns.filter(column => column.side !== 'child').map(column => column.key)
932+
);
933+
934+
if (!result) {
935+
throw new Error(`Column creation timed out.`);
936+
}
937+
938+
success(`Created ${columns.length} columns`);
939+
}
919940

920941
const pushResources = async () => {
921942
const actions = {
@@ -1711,7 +1732,7 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) =
17111732

17121733
// Parallel db actions
17131734
await Promise.all(databases.map(async (databaseId) => {
1714-
const localDatabase = localConfig.getDatabase(databaseId);
1735+
const localDatabase = localConfig.getTablesDB(databaseId);
17151736

17161737
try {
17171738
const database = await tablesDBGet({
@@ -1753,11 +1774,10 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) =
17531774
});
17541775

17551776
if (remoteTable.name !== table.name) {
1756-
await databasesUpdateTable({
1777+
await tablesDBUpdateTable({
17571778
databaseId: table['databaseId'],
17581779
tableId: table['$id'],
17591780
name: table.name,
1760-
name: table.name,
17611781
parseOutput: false
17621782
})
17631783

@@ -1770,7 +1790,7 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) =
17701790
(e) {
17711791
if (Number(e.code) === 404) {
17721792
log(`Table ${table.name} does not exist in the project. Creating ... `);
1773-
await databasesCreateTable({
1793+
await tablesDBCreateTable({
17741794
databaseId: table['databaseId'],
17751795
tableId: table['$id'],
17761796
name: table.name,
@@ -1796,13 +1816,12 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) =
17961816
if ((Array.isArray(columns) && columns.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) {
17971817
continue;
17981818
}
1799-
18001819
}
18011820

18021821
log(`Pushing table ${table.name} ( ${table['databaseId']} - ${table['$id']} ) attributes`)
18031822

18041823
try {
1805-
await createAttributes(columns, table)
1824+
await createColumns(columns, table)
18061825
} catch (e) {
18071826
throw e;
18081827
}
@@ -1900,7 +1919,6 @@ const pushCollection = async ({ returnOnZero, attempts } = { returnOnZero: false
19001919
databaseId: collection['databaseId'],
19011920
collectionId: collection['$id'],
19021921
name: collection.name,
1903-
name: collection.name,
19041922
parseOutput: false
19051923
})
19061924

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

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const { Swift } = require("../type-generation/languages/swift");
1212
const { Java } = require("../type-generation/languages/java");
1313
const { Dart } = require("../type-generation/languages/dart");
1414
const { JavaScript } = require("../type-generation/languages/javascript");
15+
const { CSharp } = require("../type-generation/languages/csharp");
1516

1617
/**
1718
* @param {string} language
@@ -33,6 +34,8 @@ function createLanguageMeta(language) {
3334
return new Java();
3435
case "dart":
3536
return new Dart();
37+
case "cs":
38+
return new CSharp();
3639
default:
3740
throw new Error(`Language '${language}' is not supported`);
3841
}
@@ -55,7 +58,7 @@ const typesLanguageOption = new Option(
5558
"-l, --language <language>",
5659
"The language of the types"
5760
)
58-
.choices(["auto", "ts", "js", "php", "kotlin", "swift", "java", "dart"])
61+
.choices(["auto", "ts", "js", "php", "kotlin", "swift", "java", "dart", "cs"])
5962
.default("auto");
6063

6164
const typesStrictOption = new Option(
@@ -97,22 +100,58 @@ const typesCommand = actionRunner(async (rawOutputDirectory, {language, strict})
97100
fs.mkdirSync(outputDirectory, { recursive: true });
98101
}
99102

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+
});
104140
}
105141

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';
107146

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}`);
110149

111150
const templater = ejs.compile(meta.getTemplate());
112151

113152
if (meta.isSingleFile()) {
114153
const content = templater({
115-
collections,
154+
collections: dataItems,
116155
strict,
117156
...templateHelpers,
118157
getType: meta.getType,
@@ -123,23 +162,23 @@ const typesCommand = actionRunner(async (rawOutputDirectory, {language, strict})
123162
fs.writeFileSync(destination, content);
124163
log(`Added types to ${destination}`);
125164
} else {
126-
for (const collection of collections) {
165+
for (const item of dataItems) {
127166
const content = templater({
128-
collections,
129-
collection,
167+
collections: dataItems,
168+
collection: item,
130169
strict,
131170
...templateHelpers,
132171
getType: meta.getType,
133172
});
134173

135-
const destination = path.join(outputDirectory, meta.getFileName(collection));
174+
const destination = path.join(outputDirectory, meta.getFileName(item));
136175

137176
fs.writeFileSync(destination, content);
138-
log(`Added types for ${collection.name} to ${destination}`);
177+
log(`Added types for ${item.name} to ${destination}`);
139178
}
140179
}
141180

142-
success(`Generated types for all the listed collections`);
181+
success(`Generated types for all the listed ${itemType}`);
143182
});
144183

145184
const types = new Command("types")

0 commit comments

Comments
 (0)