appwrite-utils-cli 0.0.4 → 0.0.5

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/README.md CHANGED
@@ -77,4 +77,8 @@ This setup ensures that developers have robust tools at their fingertips to mana
77
77
 
78
78
  - Syncing configuration
79
79
  - Better file format for config (potentially)
80
- - Separation of collections and import configuration from main config
80
+ - Separation of collections and import configuration from main config
81
+
82
+ ### Changelog
83
+
84
+ - 0.0.5: Added `setFieldFromOtherCollectionDocuments` to set an array of ID's for instance from another collection as a `postImportAction`
@@ -7,6 +7,11 @@ export declare const afterImportActions: {
7
7
  updateCreatedDocument: (config: AppwriteConfig, dbId: string, collId: string, docId: string, data: any) => Promise<void>;
8
8
  checkAndUpdateFieldInDocument: (config: AppwriteConfig, dbId: string, collId: string, docId: string, fieldName: string, oldFieldValue: any, newFieldValue: any) => Promise<void>;
9
9
  setFieldFromOtherCollectionDocument: (config: AppwriteConfig, dbId: string, collIdOrName: string, docId: string, fieldName: string, otherCollIdOrName: string, otherDocId: string, otherFieldName: string) => Promise<void>;
10
+ /**
11
+ * Updates a field in a document by setting it with document IDs from another collection
12
+ * based on a matching field value.
13
+ */
14
+ setFieldFromOtherCollectionDocuments: (config: AppwriteConfig, dbId: string, collIdOrName: string, docId: string, fieldName: string, otherCollIdOrName: string, matchingFieldName: string, matchingFieldValue: any) => Promise<void>;
10
15
  createOrGetBucket: (config: AppwriteConfig, bucketName: string, bucketId?: string, permissions?: string[], fileSecurity?: boolean, enabled?: boolean, maxFileSize?: number, allowedExtensions?: string[], compression?: string, encryption?: boolean, antivirus?: boolean) => Promise<Models.Bucket | undefined>;
11
16
  createFileAndUpdateField: (config: AppwriteConfig, dbId: string, collId: string, docId: string, fieldName: string, bucketId: string, filePath: string, fileName: string) => Promise<void>;
12
17
  };
@@ -79,6 +79,67 @@ export const afterImportActions = {
79
79
  console.error("Error setting field from other collection document: ", error);
80
80
  }
81
81
  },
82
+ /**
83
+ * Updates a field in a document by setting it with document IDs from another collection
84
+ * based on a matching field value.
85
+ */
86
+ setFieldFromOtherCollectionDocuments: async (config, dbId, collIdOrName, docId, fieldName, otherCollIdOrName, matchingFieldName, matchingFieldValue) => {
87
+ const db = getDatabaseFromConfig(config);
88
+ // Helper function to find a collection ID by name or return the ID if given
89
+ const findCollectionId = async (collectionIdentifier) => {
90
+ const collections = await db.listCollections(dbId, [
91
+ Query.equal("name", collectionIdentifier),
92
+ Query.limit(1),
93
+ ]);
94
+ return collections.total > 0
95
+ ? collections.collections[0].$id
96
+ : collectionIdentifier;
97
+ };
98
+ // Function to check if the target field is an array
99
+ const isTargetFieldArray = async (collectionId, fieldName) => {
100
+ const collection = await db.getCollection(dbId, collectionId);
101
+ const attribute = collection.attributes.find((attr) => attr.key === fieldName);
102
+ // @ts-ignore
103
+ return attribute?.array === true;
104
+ };
105
+ try {
106
+ const targetCollectionId = await findCollectionId(collIdOrName);
107
+ const otherCollectionId = await findCollectionId(otherCollIdOrName);
108
+ const targetFieldIsArray = await isTargetFieldArray(targetCollectionId, fieldName);
109
+ // Function to recursively fetch all matching documents from the other collection
110
+ const fetchAllMatchingDocuments = async (cursor) => {
111
+ const docLimit = 100;
112
+ const queries = targetFieldIsArray
113
+ ? // @ts-ignore
114
+ [Query.contains(matchingFieldName, [matchingFieldValue])]
115
+ : [Query.equal(matchingFieldName, matchingFieldValue)];
116
+ if (cursor) {
117
+ queries.push(Query.cursorAfter(cursor));
118
+ }
119
+ queries.push(Query.limit(docLimit));
120
+ const response = await db.listDocuments(dbId, otherCollectionId, queries);
121
+ const documents = response.documents;
122
+ if (documents.length === 0 || documents.length < docLimit) {
123
+ return documents;
124
+ }
125
+ const nextCursor = documents[documents.length - 1].$id;
126
+ const nextBatch = await fetchAllMatchingDocuments(nextCursor);
127
+ return documents.concat(nextBatch);
128
+ };
129
+ const matchingDocuments = await fetchAllMatchingDocuments();
130
+ const documentIds = matchingDocuments.map((doc) => doc.$id);
131
+ if (documentIds.length > 0) {
132
+ const updatePayload = targetFieldIsArray
133
+ ? { [fieldName]: documentIds }
134
+ : { [fieldName]: documentIds[0] };
135
+ await db.updateDocument(dbId, targetCollectionId, docId, updatePayload);
136
+ console.log(`Field ${fieldName} updated successfully in document ${docId} with ${documentIds.length} document IDs.`);
137
+ }
138
+ }
139
+ catch (error) {
140
+ console.error("Error setting field from other collection documents: ", error);
141
+ }
142
+ },
82
143
  createOrGetBucket: async (config, bucketName, bucketId, permissions, fileSecurity, enabled, maxFileSize, allowedExtensions, compression, encryption, antivirus) => {
83
144
  try {
84
145
  const storage = getStorageFromConfig(config);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "appwrite-utils-cli",
3
3
  "description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
4
- "version": "0.0.4",
4
+ "version": "0.0.5",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -128,6 +128,101 @@ export const afterImportActions = {
128
128
  );
129
129
  }
130
130
  },
131
+ /**
132
+ * Updates a field in a document by setting it with document IDs from another collection
133
+ * based on a matching field value.
134
+ */
135
+ setFieldFromOtherCollectionDocuments: async (
136
+ config: AppwriteConfig,
137
+ dbId: string,
138
+ collIdOrName: string,
139
+ docId: string,
140
+ fieldName: string,
141
+ otherCollIdOrName: string,
142
+ matchingFieldName: string,
143
+ matchingFieldValue: any
144
+ ): Promise<void> => {
145
+ const db = getDatabaseFromConfig(config);
146
+
147
+ // Helper function to find a collection ID by name or return the ID if given
148
+ const findCollectionId = async (collectionIdentifier: string) => {
149
+ const collections = await db.listCollections(dbId, [
150
+ Query.equal("name", collectionIdentifier),
151
+ Query.limit(1),
152
+ ]);
153
+ return collections.total > 0
154
+ ? collections.collections[0].$id
155
+ : collectionIdentifier;
156
+ };
157
+
158
+ // Function to check if the target field is an array
159
+ const isTargetFieldArray = async (
160
+ collectionId: string,
161
+ fieldName: string
162
+ ) => {
163
+ const collection = await db.getCollection(dbId, collectionId);
164
+ const attribute = collection.attributes.find(
165
+ (attr: any) => attr.key === fieldName
166
+ );
167
+ // @ts-ignore
168
+ return attribute?.array === true;
169
+ };
170
+
171
+ try {
172
+ const targetCollectionId = await findCollectionId(collIdOrName);
173
+ const otherCollectionId = await findCollectionId(otherCollIdOrName);
174
+ const targetFieldIsArray = await isTargetFieldArray(
175
+ targetCollectionId,
176
+ fieldName
177
+ );
178
+
179
+ // Function to recursively fetch all matching documents from the other collection
180
+ const fetchAllMatchingDocuments = async (
181
+ cursor?: string
182
+ ): Promise<Models.Document[]> => {
183
+ const docLimit = 100;
184
+ const queries = targetFieldIsArray
185
+ ? // @ts-ignore
186
+ [Query.contains(matchingFieldName, [matchingFieldValue])]
187
+ : [Query.equal(matchingFieldName, matchingFieldValue)];
188
+ if (cursor) {
189
+ queries.push(Query.cursorAfter(cursor));
190
+ }
191
+ queries.push(Query.limit(docLimit));
192
+ const response = await db.listDocuments(
193
+ dbId,
194
+ otherCollectionId,
195
+ queries
196
+ );
197
+ const documents = response.documents;
198
+ if (documents.length === 0 || documents.length < docLimit) {
199
+ return documents;
200
+ }
201
+ const nextCursor = documents[documents.length - 1].$id;
202
+ const nextBatch = await fetchAllMatchingDocuments(nextCursor);
203
+ return documents.concat(nextBatch);
204
+ };
205
+
206
+ const matchingDocuments = await fetchAllMatchingDocuments();
207
+ const documentIds = matchingDocuments.map((doc) => doc.$id);
208
+
209
+ if (documentIds.length > 0) {
210
+ const updatePayload = targetFieldIsArray
211
+ ? { [fieldName]: documentIds }
212
+ : { [fieldName]: documentIds[0] };
213
+ await db.updateDocument(dbId, targetCollectionId, docId, updatePayload);
214
+
215
+ console.log(
216
+ `Field ${fieldName} updated successfully in document ${docId} with ${documentIds.length} document IDs.`
217
+ );
218
+ }
219
+ } catch (error) {
220
+ console.error(
221
+ "Error setting field from other collection documents: ",
222
+ error
223
+ );
224
+ }
225
+ },
131
226
  createOrGetBucket: async (
132
227
  config: AppwriteConfig,
133
228
  bucketName: string,