UNPKG

appwrite-utils-cli

Version:

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.

215 lines (188 loc) 6.62 kB
import type { AppwriteConfig, Attribute, RelationshipAttribute } from "appwrite-utils"; /** * Represents detailed information about a two-way relationship between collections */ export interface RelationshipDetail { parentCollection: string; childCollection: string; parentKey: string; childKey: string; isArray: boolean; isChild: boolean; } /** * Represents basic relationship information for JSON schema generation */ export interface SimpleRelationship { attributeKey: string; relatedCollection: string; relationType: string; isArray: boolean; } /** * Helper function to resolve collection name from ID or name * @param config - Appwrite configuration containing collections * @param idOrName - Collection ID or name to resolve * @returns Resolved collection name, or the original input if not found */ export function resolveCollectionName(config: AppwriteConfig, idOrName: string): string { const col = config.collections?.find( (c) => c.$id === (idOrName as any) || c.name === idOrName ); return col?.name ?? idOrName; } /** * Determines if a relationship type results in an array * @param relationType - The type of relationship (oneToOne, oneToMany, manyToOne, manyToMany) * @returns true if the relationship results in an array */ export function isArrayRelationship(relationType: string): boolean { return relationType === "oneToMany" || relationType === "manyToMany"; } /** * Extracts two-way relationship details from collections for Zod schema generation * This handles complex bidirectional relationships with parent-child tracking * * @param config - Appwrite configuration containing collections * @returns Map of collection names to their relationship details */ export function extractTwoWayRelationships( config: AppwriteConfig ): Map<string, RelationshipDetail[]> { const relationshipMap = new Map<string, RelationshipDetail[]>(); if (!config.collections) { return relationshipMap; } config.collections.forEach((collection) => { if (!collection.attributes) { return; } collection.attributes.forEach((attr) => { if (attr.type === "relationship" && attr.twoWay && attr.twoWayKey) { const relationshipAttr = attr as RelationshipAttribute; let isArrayParent = false; let isArrayChild = false; switch (relationshipAttr.relationType) { case "oneToMany": isArrayParent = true; isArrayChild = false; break; case "manyToMany": isArrayParent = true; isArrayChild = true; break; case "oneToOne": isArrayParent = false; isArrayChild = false; break; case "manyToOne": isArrayParent = false; isArrayChild = true; break; default: break; } const relatedCollectionName = resolveCollectionName( config, relationshipAttr.relatedCollection ); addTwoWayRelationship( relationshipMap, collection.name, relatedCollectionName, attr.key, relationshipAttr.twoWayKey!, isArrayParent, isArrayChild ); console.log( `Extracted relationship: ${attr.key}\n\t${collection.name} -> ${relationshipAttr.relatedCollection}, databaseId: ${collection.databaseId}` ); } }); }); return relationshipMap; } /** * Helper to add two-way relationship details to both parent and child collections * @param relationshipMap - The map to add relationships to * @param parentCollection - Parent collection name * @param childCollection - Child collection name * @param parentKey - Attribute key in parent collection * @param childKey - Attribute key in child collection * @param isArrayParent - Whether parent side is an array * @param isArrayChild - Whether child side is an array */ function addTwoWayRelationship( relationshipMap: Map<string, RelationshipDetail[]>, parentCollection: string, childCollection: string, parentKey: string, childKey: string, isArrayParent: boolean, isArrayChild: boolean ): void { const relationshipsChild = relationshipMap.get(childCollection) || []; const relationshipsParent = relationshipMap.get(parentCollection) || []; relationshipsParent.push({ parentCollection, childCollection, parentKey, childKey, isArray: isArrayParent, isChild: false, }); relationshipsChild.push({ parentCollection, childCollection, parentKey, childKey, isArray: isArrayChild, isChild: true, }); relationshipMap.set(childCollection, relationshipsChild); relationshipMap.set(parentCollection, relationshipsParent); } /** * Extracts simple relationship information from collections for JSON schema generation * This handles one-way and basic relationship tracking * * @param config - Appwrite configuration containing collections * @returns Map of collection names to their simple relationships */ export function extractSimpleRelationships( config: AppwriteConfig ): Map<string, SimpleRelationship[]> { const relationshipMap = new Map<string, SimpleRelationship[]>(); if (!config.collections) { return relationshipMap; } config.collections.forEach((collection) => { if (!collection.attributes) { return; } collection.attributes.forEach((attr) => { if (attr.type === "relationship" && attr.relatedCollection) { const relationships = relationshipMap.get(collection.name) || []; relationships.push({ attributeKey: attr.key, relatedCollection: resolveCollectionName(config, attr.relatedCollection), relationType: attr.relationType || "oneToOne", isArray: isArrayRelationship(attr.relationType || "oneToOne") }); relationshipMap.set(collection.name, relationships); } }); }); return relationshipMap; } /** * Extracts all relationship attributes from a collection's attributes * @param attributes - Array of collection attributes * @returns Array of relationship attributes only */ export function filterRelationshipAttributes(attributes: Attribute[]): RelationshipAttribute[] { return attributes.filter( (attr): attr is RelationshipAttribute => attr.type === "relationship" ); }