@manic.code/schema

1.2.1 • Public • Published

🧠 @manic.code/schema

npm version Build Status Coverage License

A powerful, flexible schema definition and validation system for TypeScript with seamless multi-database support.

SAGE Schema

🔥 Overview

MANIC Schema is a revolutionary TypeScript-first ORM/ODM that lets you define your data model once and seamlessly use it across multiple databases — MongoDB, Neo4j, PostgreSQL, and more. Built from the ground up with modern best practices:

✨ Key Features

  • Define Once, Use Anywhere: Define schema in TypeScript, deploy to any supported database
  • Multi-Database Architecture: Mix and match databases for optimal performance
  • Cross-Database Relationships: Maintain relationships between entities in different databases
  • GraphQL Ready: Auto-generate GraphQL schema from your entities
  • Database-Specific Optimizations: Leverage native database features when needed
  • Type-Safe: Full TypeScript support with proper types throughout

🏗️ Core Architecture

  • Clean Design: Explicit dependencies, no global state, no magic
  • Adapter Pattern: Extensible adapter system for database integrations
  • Decorator-Based: Intuitive TypeScript decorators for schema definition
  • 100% Test Coverage: Comprehensive test suite with property-based testing

🗄️ Supported Databases

Database Status Features
MongoDB ✅ Stable Collections, indexes, embedding
Neo4j ✅ Stable Node labels, relationship types, Cypher queries
PostgreSQL ✅ Stable Tables, columns, indexes, joins
SQLite 🚧 In Progress Basic functionality
Redis 🚧 In Progress Basic functionality
DynamoDB 🗓️ Planned -
Firestore 🗓️ Planned -

🧩 Key Components

Decorators

Define your entities with TypeScript decorators:

@Entity()
class Post {
  @Id()
  id: string;

  @Property({ required: true })
  title: string;

  @Property()
  content: string;

  @Property()
  createdAt: Date;

  @ManyToOne({
    target: () => User,
    inverse: "posts",
    name: "AUTHORED",
  })
  author: User;

  @ManyToMany({
    target: () => Tag,
    inverse: "posts",
    name: "HAS_TAG",
  })
  tags: Tag[] = [];
}

Database-Specific Decorators

Optimize for specific databases when needed:

// MongoDB specific
@Collection("blog_posts")
@MongoIndex({ title: "text", content: "text" })
class Post {
  /* ... */
}

// Neo4j specific
@Labels(["Content", "BlogPost"])
@RelationshipType("TAGGED_WITH")
class Post {
  /* ... */
}

// PostgreSQL specific
@Table("blog_posts")
@Column({ name: "post_content", type: "text" })
@PgIndex({ name: "idx_post_title", columns: ["title"] })
class Post {
  /* ... */
}

SchemaBuilder & Registry

Explicit dependencies, no global state:

// Create registry and builder
const registry = new MetadataRegistry();
const builder = new SchemaBuilder(registry);

// Register your entities
builder.registerEntities([User, Post, Comment, Tag]);

Multi-Database Adapters

Use different databases for different entity types:

// Create adapters for different databases
const mongoAdapter = new MongoDBAdapter(
  registry,
  "mongodb://localhost:27017/blog"
);
const neo4jAdapter = new Neo4jAdapter(registry, "bolt://localhost:7687");
const pgAdapter = new PostgreSQLAdapter(
  registry,
  "postgres://localhost:5432/blog"
);

// Create repositories with appropriate adapters
const userRepo = new Repository<User>(User, mongoAdapter);
const postRepo = new Repository<Post>(Post, neo4jAdapter);
const tagRepo = new Repository<Tag>(Tag, pgAdapter);

Repositories

Consistent interface across all databases:

// Find by ID
const user = await userRepo.findById("user123");

// Query by criteria
const posts = await postRepo.find({ completed: true });

// Create and save
const tag = new Tag();
tag.name = "TypeScript";
await tagRepo.save(tag);

// Delete
await userRepo.delete("user123");

📊 GraphQL Integration

Automatic GraphQL schema generation:

// Generate GraphQL schema from entities
import { generateGraphQLSchema } from "@manic.codes/schema/graphql";

const typeDefs = generateGraphQLSchema(registry);
const resolvers = generateResolvers(registry, {
  User: userRepo,
  Post: postRepo,
  Tag: tagRepo,
});

// Create Apollo Server
const server = new ApolloServer({
  typeDefs,
  resolvers,
});

🚀 Complete Multi-Database Example

import {
  Entity,
  Id,
  Property,
  ManyToOne,
  ManyToMany,
  MetadataRegistry,
  SchemaBuilder,
  MongoDBAdapter,
  Neo4jAdapter,
  PostgreSQLAdapter,
  Repository,
} from "@manic.code/schema";

// Define entities
@Entity()
class User {
  @Id()
  id: string;

  @Property({ required: true })
  name: string;

  @Property({ required: true, unique: true })
  email: string;

  @OneToMany({ target: () => Post, inverse: "author" })
  posts: Post[] = [];
}

@Entity()
class Post {
  @Id()
  id: string;

  @Property({ required: true })
  title: string;

  @Property()
  content: string;

  @Property()
  createdAt: Date = new Date();

  @ManyToOne({ target: () => User, inverse: "posts" })
  author: User;

  @ManyToMany({ target: () => Tag, inverse: "posts" })
  tags: Tag[] = [];
}

@Entity()
class Tag {
  @Id()
  id: string;

  @Property({ required: true, unique: true })
  name: string;

  @ManyToMany({ target: () => Post, inverse: "tags" })
  posts: Post[] = [];
}

// Set up the registry and builder
const registry = new MetadataRegistry();
const builder = new SchemaBuilder(registry);
builder.registerEntities([User, Post, Tag]);

// Create database adapters
const mongoAdapter = new MongoDBAdapter(
  registry,
  "mongodb://localhost:27017/blog"
);
const neo4jAdapter = new Neo4jAdapter(registry, "bolt://localhost:7687");
const pgAdapter = new PostgreSQLAdapter(
  registry,
  "postgres://localhost:5432/blog"
);

// Create repositories with different adapters
const userRepo = new Repository<User>(User, mongoAdapter);
const postRepo = new Repository<Post>(Post, neo4jAdapter);
const tagRepo = new Repository<Tag>(Tag, pgAdapter);

// Create entities with relationships across databases
async function createBlogPost() {
  // Create user in MongoDB
  const user = new User();
  user.id = "user1";
  user.name = "John Doe";
  user.email = "john@example.com";
  await userRepo.save(user);

  // Create tags in PostgreSQL
  const tag1 = new Tag();
  tag1.id = "tag1";
  tag1.name = "TypeScript";
  await tagRepo.save(tag1);

  const tag2 = new Tag();
  tag2.id = "tag2";
  tag2.name = "ORM";
  await tagRepo.save(tag2);

  // Create post in Neo4j with relationships to MongoDB and PostgreSQL
  const post = new Post();
  post.id = "post1";
  post.title = "Multi-Database ORM with TypeScript";
  post.content = "This is amazing...";
  post.author = user;
  post.tags.push(tag1, tag2);
  await postRepo.save(post);

  return post;
}

🔧 Installation

npm install @manic.code/schema

📄 License

MIT © Zach Winter

Package Sidebar

Install

npm i @manic.code/schema

Weekly Downloads

8

Version

1.2.1

License

ISC

Unpacked Size

929 kB

Total Files

115

Last publish

Collaborators

  • zach.winter