UNPKG

@wearesage/schema

Version:

A flexible schema definition and validation system for TypeScript with multi-database support

191 lines (160 loc) 7.04 kB
import "reflect-metadata"; import { MetadataRegistry, SchemaBuilder, } from "../core"; import { SchemaReflector } from "../core/SchemaReflector"; import { MongoDBAdapter, Collection, MongoIndex } from "../adapters"; // Import example entities from e-commerce domain import { User } from "../examples/ecommerce/User"; import { Product } from "../examples/ecommerce/Product"; import { Category } from "../examples/ecommerce/Category"; import { Order } from "../examples/ecommerce/Order"; import { OrderItem } from "../examples/ecommerce/OrderItem"; import { Review } from "../examples/ecommerce/Review"; import { Cart } from "../examples/ecommerce/Cart"; import { CartItem } from "../examples/ecommerce/CartItem"; // Add MongoDB-specific decorators to some entities Collection("users")(User); MongoIndex({ email: 1 }, { unique: true })(User); describe("Integration Tests", () => { let registry: MetadataRegistry; let builder: SchemaBuilder; let reflector: SchemaReflector; let adapter: MongoDBAdapter; beforeEach(() => { // Set up the components registry = new MetadataRegistry(); builder = new SchemaBuilder(registry); reflector = new SchemaReflector(registry); // Register all entities builder.registerEntities([User, Product, Category, Order, OrderItem, Review, Cart, CartItem]); // Create adapter adapter = new MongoDBAdapter(registry, "mongodb://localhost:27017/test"); }); test("full schema registration and validation workflow", () => { // 1. Check entity registration expect(registry.getEntityMetadata(User)).toBeDefined(); expect(registry.getEntityMetadata(Order)).toBeDefined(); expect(registry.getEntityMetadata(Product)).toBeDefined(); // 2. Check properties registration expect(registry.getPropertyMetadata(User, "name")).toEqual({ required: true }); expect(registry.getPropertyMetadata(User, "email")).toEqual({ required: true, unique: true }); // 3. Check ID properties const userIdProps = registry.getIdProperties(User); expect(userIdProps).toBeDefined(); expect(userIdProps?.has("id")).toBe(true); // 4. Check relationships const userOrdersRel = registry.getRelationshipMetadata(User, "orders"); expect(userOrdersRel).toBeDefined(); expect(userOrdersRel?.cardinality).toBe("many"); expect(userOrdersRel?.target).toBe(Order); const orderUserRel = registry.getRelationshipMetadata(Order, "user"); expect(orderUserRel).toBeDefined(); expect(orderUserRel?.cardinality).toBe("one"); expect(orderUserRel?.name).toBe("BELONGS_TO"); // 5. Get complete schema for an entity const userSchema = reflector.getEntitySchema(User); expect(userSchema.name).toBeDefined(); expect(Object.keys(userSchema.properties)).toContain("name"); expect(Object.keys(userSchema.properties)).toContain("email"); expect(Object.keys(userSchema.relationships)).toContain("orders"); expect(Object.keys(userSchema.relationships)).toContain("reviews"); // 6. Entity validation const validUser = new User(); validUser.id = "u123"; validUser.name = "John Doe"; validUser.email = "john@example.com"; const validationResult = reflector.validateEntity(validUser); expect(validationResult.valid).toBe(true); // 7. Invalid entity const invalidUser = new User(); invalidUser.id = "u456"; // Missing required name and email const invalidValidationResult = reflector.validateEntity(invalidUser); expect(invalidValidationResult.valid).toBe(false); expect(invalidValidationResult.errors).toContain("Required property 'name' is missing"); expect(invalidValidationResult.errors).toContain("Required property 'email' is missing"); }); test("MongoDB specific functionality", () => { // Test MongoDB collection name lookup const getCollectionName = (adapter as any).getCollectionName.bind(adapter); expect(getCollectionName(User)).toBe("users"); // Uses @Collection decorator expect(getCollectionName(Product)).toBe("products"); // Uses default pluralization // Check MongoDB index registration const emailIndex = Reflect.getMetadata("mongodb:indexes", User) || []; expect(emailIndex.length).toBeGreaterThan(0); expect(emailIndex[0].keys).toEqual({ email: 1 }); expect(emailIndex[0].options).toEqual({ unique: true }); }); test("end-to-end entity example", () => { // Create complete object graph const user = new User(); user.id = "user001"; user.name = "Jane Smith"; user.email = "jane@example.com"; const product1 = new Product(); product1.id = "prod001"; product1.name = "Widget A"; product1.price = 19.99; const product2 = new Product(); product2.id = "prod002"; product2.name = "Widget B"; product2.price = 29.99; const category = new Category(); category.id = "cat001"; category.name = "Widgets"; category.products.push(product1, product2); product1.categories.push(category); product2.categories.push(category); const order = new Order(); order.id = "ord001"; order.orderNumber = "2025-0001"; order.createdAt = new Date(); order.user = user; user.orders.push(order); const item1 = new OrderItem(); item1.id = "item001"; item1.quantity = 2; item1.unitPrice = product1.price; item1.product = product1; item1.order = order; order.items.push(item1); const item2 = new OrderItem(); item2.id = "item002"; item2.quantity = 1; item2.unitPrice = product2.price; item2.product = product2; item2.order = order; order.items.push(item2); const review = new Review(); review.id = "rev001"; review.rating = 5; review.content = "Great product!"; review.author = user; review.product = product1; user.reviews.push(review); product1.reviews.push(review); // Validate all entities expect(reflector.validateEntity(user).valid).toBe(true); expect(reflector.validateEntity(product1).valid).toBe(true); expect(reflector.validateEntity(product2).valid).toBe(true); expect(reflector.validateEntity(category).valid).toBe(true); expect(reflector.validateEntity(order).valid).toBe(true); expect(reflector.validateEntity(item1).valid).toBe(true); expect(reflector.validateEntity(item2).valid).toBe(true); expect(reflector.validateEntity(review).valid).toBe(true); // Verify relationships were properly set up expect(order.user).toBe(user); expect(user.orders[0]).toBe(order); expect(item1.order).toBe(order); expect(order.items).toContain(item1); expect(item1.product).toBe(product1); expect(product1.categories[0]).toBe(category); expect(category.products).toContain(product1); expect(review.author).toBe(user); expect(user.reviews[0]).toBe(review); expect(review.product).toBe(product1); expect(product1.reviews[0]).toBe(review); }); });