Skip to content

Commit 1ae4c27

Browse files
committed
schema validation
1 parent 957d233 commit 1ae4c27

File tree

4 files changed

+543
-30
lines changed

4 files changed

+543
-30
lines changed

index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ import { tokens } from "./lib/commands/services/tokens.js";
4646
import { users } from "./lib/commands/services/users.js";
4747
import { vcs } from "./lib/commands/services/vcs.js";
4848
import searchList from "inquirer-search-list";
49+
import { Push } from "./lib/commands/push.js";
50+
import { Pull } from "./lib/commands/pull.js";
51+
import { Schema } from "./lib/commands/schema.js";
4952

5053
inquirer.registerPrompt("search-list", searchList);
5154

@@ -166,3 +169,5 @@ if (process.argv.includes("-v") || process.argv.includes("--version")) {
166169

167170
process.stdout.columns = oldWidth;
168171
}
172+
173+
export { Schema, Push, Pull };

lib/commands/push.ts

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,18 @@ import { checkAndApplyTablesDBChanges } from "./utils/database-sync.js";
7575
const POLL_DEBOUNCE = 2000; // Milliseconds
7676
const POLL_DEFAULT_VALUE = 30;
7777

78-
interface PushResourcesOptions {
78+
export interface PushOptions {
7979
skipDeprecated?: boolean;
80+
functionOptions?: {
81+
async?: boolean;
82+
code?: boolean;
83+
withVariables?: boolean;
84+
};
85+
siteOptions?: {
86+
async?: boolean;
87+
code?: boolean;
88+
withVariables?: boolean;
89+
};
8090
}
8191

8292
interface PushSiteOptions {
@@ -108,20 +118,7 @@ export class Push {
108118

109119
public async pushResources(
110120
config: ConfigType,
111-
options: {
112-
skipDeprecated?: boolean;
113-
functionOptions?: {
114-
async?: boolean;
115-
code?: boolean;
116-
withVariables?: boolean;
117-
};
118-
siteOptions?: {
119-
async?: boolean;
120-
code?: boolean;
121-
withVariables?: boolean;
122-
};
123-
attempts?: number;
124-
} = { skipDeprecated: true },
121+
options: PushOptions = { skipDeprecated: true },
125122
): Promise<{
126123
results: Record<string, any>;
127124
errors: any[];
@@ -228,7 +225,7 @@ export class Push {
228225
if (config.tables && config.tables.length > 0) {
229226
try {
230227
log("Pushing tables ...");
231-
const result = await this.pushTables(config.tables, options.attempts);
228+
const result = await this.pushTables(config.tables);
232229
results.tables = result;
233230
allErrors.push(...result.errors);
234231
} catch (e: any) {
@@ -257,10 +254,7 @@ export class Push {
257254
};
258255
},
259256
);
260-
const result = await this.pushCollections(
261-
collectionsWithDbNames,
262-
options.attempts,
263-
);
257+
const result = await this.pushCollections(collectionsWithDbNames);
264258
results.collections = result;
265259
allErrors.push(...result.errors);
266260
} catch (e: any) {
@@ -1275,14 +1269,11 @@ export class Push {
12751269
};
12761270
}
12771271

1278-
public async pushCollections(
1279-
collections: any[],
1280-
attempts?: number,
1281-
): Promise<{
1272+
public async pushCollections(collections: any[]): Promise<{
12821273
successfullyPushed: number;
12831274
errors: any[];
12841275
}> {
1285-
const pools = new Pools(attempts ?? POLL_DEFAULT_VALUE);
1276+
const pools = new Pools(POLL_DEFAULT_VALUE);
12861277
const attributes = new Attributes(pools);
12871278

12881279
const errors: any[] = [];
@@ -1438,7 +1429,9 @@ async function createPushInstance(): Promise<Push> {
14381429

14391430
const pushResources = async ({
14401431
skipDeprecated = false,
1441-
}: PushResourcesOptions = {}): Promise<void> => {
1432+
}: {
1433+
skipDeprecated?: boolean;
1434+
} = {}): Promise<void> => {
14421435
if (cliConfig.all) {
14431436
checkDeployConditions(localConfig);
14441437

@@ -1966,9 +1959,7 @@ const pushTable = async ({
19661959
}
19671960
};
19681961

1969-
const pushCollection = async ({
1970-
attempts,
1971-
}: PushTableOptions = {}): Promise<void> => {
1962+
const pushCollection = async ({}: PushTableOptions = {}): Promise<void> => {
19721963
warn(
19731964
"appwrite push collection has been deprecated. Please consider using 'appwrite push tables' instead",
19741965
);
@@ -2029,7 +2020,7 @@ const pushCollection = async ({
20292020
log("Pushing collections ...");
20302021

20312022
const pushInstance = await createPushInstance();
2032-
const result = await pushInstance.pushCollections(collections, attempts);
2023+
const result = await pushInstance.pushCollections(collections);
20332024

20342025
const { successfullyPushed, errors } = result;
20352026

lib/commands/schema.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { Client } from "@appwrite.io/console";
2+
import type { ConfigType } from "./config.js";
3+
import { ConfigSchema } from "./config.js";
4+
import { Pull, PullOptions } from "./pull.js";
5+
import { Push, PushOptions } from "./push.js";
6+
import { parseWithBetterErrors } from "./utils/error-formatter.js";
7+
import JSONbig from "json-bigint";
8+
import * as fs from "fs";
9+
10+
const JSONBig = JSONbig({ storeAsString: false });
11+
12+
export class Schema {
13+
private pullCommand: Pull;
14+
private pushCommand: Push;
15+
16+
constructor({
17+
projectClient,
18+
consoleClient,
19+
}: {
20+
projectClient: Client;
21+
consoleClient: Client;
22+
}) {
23+
this.pullCommand = new Pull(projectClient, consoleClient);
24+
this.pushCommand = new Push(projectClient, consoleClient);
25+
}
26+
27+
/**
28+
* Validates the provided configuration object against the schema.
29+
*
30+
* @param config - The configuration object to validate.
31+
* @returns The validated and possibly transformed configuration object.
32+
* @throws If the configuration does not match the schema.
33+
*/
34+
public validate(config: ConfigType): ConfigType {
35+
return parseWithBetterErrors<ConfigType>(
36+
ConfigSchema,
37+
config,
38+
"Configuration schema validation",
39+
config,
40+
);
41+
}
42+
43+
/**
44+
* Pulls the current schema and resources from the remote Appwrite project.
45+
*
46+
* @param config - The local configuration object.
47+
* @param options - Optional settings for the pull operation.
48+
* @returns A Promise that resolves to the updated configuration object reflecting the remote state.
49+
*/
50+
public async pull(
51+
config: ConfigType,
52+
options: PullOptions = { all: true },
53+
): Promise<ConfigType> {
54+
return await this.pullCommand.pullResources(config, options);
55+
}
56+
57+
/**
58+
* Pushes the local configuration and schema to the remote Appwrite project.
59+
* Optionally syncs the config file by pulling the updated state from the server after push.
60+
*
61+
* @param config - The local configuration object to push.
62+
* @param options - Optional settings for the push operation. Use `force: true` to allow destructive changes.
63+
* @param configPath - Optional path to the config file. If provided, the config will be synced after push.
64+
* @returns A Promise that resolves when the push operation is complete.
65+
* @throws {DestructiveChangeError} When destructive changes are detected and force is not enabled.
66+
*/
67+
public async push(
68+
config: ConfigType,
69+
options: PushOptions,
70+
configPath?: string,
71+
): Promise<void> {
72+
await this.pushCommand.pushResources(config, options);
73+
74+
if (configPath) {
75+
const updatedConfig = await this.pullCommand.pullResources(config);
76+
this.write(updatedConfig, configPath);
77+
}
78+
}
79+
80+
/**
81+
* Reads the configuration object from a file.
82+
*
83+
* @param path - The path to the file to read.
84+
* @returns The configuration object.
85+
*/
86+
public read(path: string): ConfigType {
87+
return JSONBig.parse(fs.readFileSync(path, "utf8")) as ConfigType;
88+
}
89+
90+
/**
91+
* Writes the configuration object to a file.
92+
*
93+
* @param config - The configuration object to write.
94+
* @param path - The path to the file to write.
95+
* @returns void
96+
*/
97+
public write(config: ConfigType, path: string): void {
98+
fs.writeFileSync(path, JSONBig.stringify(config, null, 4));
99+
}
100+
}

0 commit comments

Comments
 (0)