🚀 The most sophisticated code generation engine you've ever seen - automatically transforms your database schema into a complete, type-safe, full-stack application with AI-powered intelligence.
MemberJunction's CodeGen doesn't just generate boilerplate code. It's an AI-powered, metadata-driven architecture that creates bulletproof, production-ready applications from your database schema with zero manual intervention.
- CHECK Constraint Translation: Our AI automatically translates complex SQL CHECK constraints into perfect TypeScript union types and Zod validation schemas
- Smart Type Inference: Analyzes relationships and generates contextually appropriate Angular form controls (dropdowns, search boxes, checkboxes)
- Intelligent Naming: AI-driven naming conventions ensure your generated code follows best practices
Watch your database changes instantly propagate through your entire stack:
Database Schema Change → TypeScript Entities → Angular Forms → SQL Procedures → GraphQL Schema
One command. Complete synchronization. Zero breaking changes.
- TypeScript Entity Classes with full type safety and validation
- Angular Form Components with proper field types and validation
- SQL Stored Procedures for all CRUD operations
- Database Views with optimized joins and indexing
- GraphQL Schemas and resolvers
- Zod Validation Schemas from SQL constraints
- Complete API Endpoints with type-safe parameters
npm install @memberjunction/codegen-lib
ALTER TABLE [AIPrompt]
ADD [PromptRole] nvarchar(20) NOT NULL
CONSTRAINT [CK_AIPrompt_PromptRole] CHECK ([PromptRole] IN (N'System', N'User', N'Assistant', N'SystemOrUser'))
PromptRole: z.union([
z.literal('System'),
z.literal('User'),
z.literal('Assistant'),
z.literal('SystemOrUser')
]).describe('Determines how the prompt is used in conversation...')
<mj-form-field
[record]="record"
FieldName="PromptRole"
Type="dropdownlist" // AI chose dropdown based on constraint
[EditMode]="EditMode"
></mj-form-field>
CREATE PROCEDURE [spCreateAIPrompt]
@PromptRole nvarchar(20),
-- 20+ other parameters auto-generated
AS BEGIN
-- Complete CRUD logic with validation
END
All from ONE schema change. All type-safe. All production-ready.
import { initializeConfig, runCodeGen } from '@memberjunction/codegen-lib';
// Initialize configuration
await initializeConfig();
// Generate your entire application stack
await runCodeGen();
// That's it. Seriously.
Your database schema just became:
- ✅ 295+ TypeScript entity classes with full validation
- ✅ Complete Angular UI with smart form controls
- ✅ All SQL stored procedures for every operation
- ✅ GraphQL API with type-safe resolvers
- ✅ Perfect type safety across your entire stack
Generates bullet-proof TypeScript classes from your database schema:
// Auto-generated from your schema
export class AIPromptEntity extends BaseEntity {
// 30+ properties with perfect types
PromptRole: 'System' | 'User' | 'Assistant' | 'SystemOrUser';
// AI-powered validation from CHECK constraints
validate(): ValidationResult {
return this.validateWithZod(AIPromptSchema);
}
}
Creates production-ready Angular forms with intelligent field types:
// Auto-detects relationships and creates search components
<mj-form-field
FieldName="CategoryID"
Type="textbox" // Smart field type selection
LinkType="Record" // Auto-detected relationship
LinkComponentType="Search" // AI chose search over dropdown
></mj-form-field>
Generates optimized database objects with best practices:
-- Auto-generated indexes for performance
CREATE INDEX IDX_AUTO_MJ_FKEY_AIPrompt_CategoryID
ON [AIPrompt] ([CategoryID]);
-- Complete CRUD procedures with validation
CREATE PROCEDURE [spCreateAIPrompt]
@PromptRole nvarchar(20) -- Validated against CHECK constraint
-- Full implementation auto-generated
Our generated delete procedures are production-grade with intelligent handling of:
1. Result Feedback - Know What Happened
-- Returns NULL for all PKs when no record found
IF @@ROWCOUNT = 0
SELECT NULL AS [CustomerID], NULL AS [OrderID]
ELSE
SELECT @CustomerID AS [CustomerID], @OrderID AS [OrderID]
2. Cascade Deletes via Stored Procedure Calls
Instead of basic DELETE statements, we generate cursor-based cascade operations that respect your business logic:
-- BAD: Direct DELETE (bypasses business logic)
DELETE FROM OrderItems WHERE OrderID = @OrderID
-- GOOD: Cursor-based SP calls (respects custom logic)
DECLARE @RelatedItemID INT
DECLARE cascade_delete_OrderItem_cursor CURSOR FOR
SELECT [ItemID] FROM [OrderItems] WHERE [OrderID] = @OrderID
OPEN cascade_delete_OrderItem_cursor
FETCH NEXT FROM cascade_delete_OrderItem_cursor INTO @RelatedItemID
WHILE @@FETCH_STATUS = 0
BEGIN
-- Calls YOUR stored procedure, enabling N-level cascades
EXEC [spDeleteOrderItem] @RelatedItemID
FETCH NEXT FROM cascade_delete_OrderItem_cursor INTO @RelatedItemID
END
CLOSE cascade_delete_OrderItem_cursor
DEALLOCATE cascade_delete_OrderItem_cursor
Benefits:
- ✅ Respects custom delete logic in related entities
- ✅ Enables multi-level cascades (if OrderItem has its own cascades)
- ✅ Maintains referential integrity through proper SP calls
- ✅ Clear result feedback - NULL means no record deleted
3. Nullable Foreign Key Handling
For nullable FKs, we update via stored procedures too:
-- Fetch all fields, update only the FK to NULL
DECLARE cascade_update_Customer_cursor CURSOR FOR
SELECT * FROM [Customers] WHERE [RegionID] = @RegionID
-- In cursor loop:
SET @UpdateRegionID = NULL -- Only FK changes
EXEC [spUpdateCustomer] @CustomerID, @Name, @Email, @UpdateRegionID
4. Configuration Error Detection
CodeGen warns you about misconfigured cascade scenarios:
-- WARNING: Orders has non-nullable FK to Customer but doesn't allow delete API
-- This will cause a referential integrity violation
The warnings appear both in generated SQL and console output during generation.
Our update procedures also provide clear feedback when operating on non-existent records:
-- Check if update affected any rows
IF @@ROWCOUNT = 0
-- Return empty result set (maintains column structure)
SELECT TOP 0 * FROM [vwCustomer] WHERE 1=0
ELSE
-- Return the updated record with calculated fields
SELECT * FROM [vwCustomer] WHERE [CustomerID] = @CustomerID
Why This Matters:
- Empty result set = Record not found (update failed)
- Record returned = Update successful
- Maintains schema = Calling code doesn't break
- Includes calculated fields = Get the latest computed values
Creates type-safe GraphQL APIs from your entities:
type AIPrompt {
id: ID!
promptRole: PromptRoleEnum! # Auto-generated from CHECK constraint
category: AIPromptCategory # Auto-resolved relationships
}
enum PromptRoleEnum {
SYSTEM
USER
ASSISTANT
SYSTEMORUSER
}
Reverse-engineers your entire database into metadata:
const schemaInfo = await analyzeSchema(connection);
// Discovers tables, relationships, constraints, indexes
// Feeds AI engine for intelligent code generation
Our AI doesn't just copy constraints - it understands intent:
-- Complex constraint
CHECK ([Status] IN ('Draft', 'Published', 'Archived')
AND [PublishedAt] IS NOT NULL WHEN [Status] = 'Published')
Becomes perfect TypeScript:
Status: z.union([z.literal('Draft'), z.literal('Published'), z.literal('Archived')])
.refine((status, ctx) => {
if (status === 'Published' && !this.PublishedAt) {
ctx.addIssue({ code: 'custom', message: 'Published items must have PublishedAt' });
}
})
Change your database schema → Everything updates automatically:
- Flyway migration executes
- CodeGen detects changes
- Regenerates affected code
- Type safety maintained across entire stack
- Zero manual intervention
- Intelligent caching prevents unnecessary regeneration
- Incremental updates for changed entities only
- Optimized SQL with proper indexing strategies
- Lazy loading for large schema datasets
- Parameterized queries in all generated SQL
- Input validation at every layer
- SQL injection protection built-in
- Type-safe APIs prevent runtime errors
Create a .memberjunctionrc
file:
{
"memberjunction": {
"database": {
"server": "localhost",
"database": "YourDatabase",
"trustedConnection": true
},
"directories": {
"output": "./generated",
"entities": "./generated/entities",
"actions": "./generated/actions",
"angular": "./generated/angular",
"sql": "./generated/sql"
},
"ai": {
"enabled": true,
"provider": "openai" // Powers constraint translation
}
}
}
Starting with a simple table:
CREATE TABLE [Customer] (
[ID] uniqueidentifier PRIMARY KEY DEFAULT newsequentialid(),
[Name] nvarchar(255) NOT NULL,
[Status] nvarchar(20) CHECK ([Status] IN ('Active', 'Inactive', 'Suspended')),
[CreatedAt] datetimeoffset DEFAULT getutcdate()
);
One CodeGen run produces:
export class CustomerEntity extends BaseEntity {
Status: 'Active' | 'Inactive' | 'Suspended';
// + complete validation, save methods, relationships
}
@Component({
template: `Complete form with validation and smart controls`
})
export class CustomerDetailsComponent {
// Ready for production use
}
-- spCreateCustomer, spUpdateCustomer, spDeleteCustomer
-- Complete with validation and error handling
type Customer {
# Complete type-safe schema
}
Total: 500+ lines of production code from 6 lines of SQL.
// Generate everything at once
await runCodeGen();
// Generate specific components
await generateEntitySubClasses(options);
await generateAngularEntityCode(options);
await generateSQLScripts(options);
await generateGraphQLServerCode(options);
import { generateEntitySubClasses } from '@memberjunction/codegen-lib';
const result = await generateEntitySubClasses({
outputDirectory: './generated/entities',
generateLoader: true,
generateCustomEntityClasses: true,
aiEnhanced: true, // Enable AI features
incrementalMode: true, // Only update changed entities
validateGenerated: true // Compile-check generated code
});
import { generateActionSubClasses } from '@memberjunction/codegen-lib';
const result = await generateActionSubClasses({
outputDirectory: './generated/actions',
generateLoader: true
});
import { generateGraphQLServerCode } from '@memberjunction/codegen-lib';
await generateGraphQLServerCode({
outputDirectory: './generated/graphql',
entities: entityMetadata
});
import { generateSQLScripts } from '@memberjunction/codegen-lib';
await generateSQLScripts({
outputDirectory: './generated/sql',
includeStoredProcedures: true,
includeViews: true
});
import { generateAllAngularEntityCode } from '@memberjunction/codegen-lib';
await generateAllAngularEntityCode({
outputDirectory: './generated/angular',
entities: entityMetadata
});
On a typical MemberJunction database with 150+ tables:
- Entity Generation: 2.3 seconds
- Angular Components: 4.7 seconds
- SQL Procedures: 1.8 seconds
- Total Stack Generation: <10 seconds
For 295 entity classes and thousands of generated files.
Works seamlessly with:
-
@memberjunction/core
- Entity framework -
@memberjunction/ai
- AI-powered features -
@memberjunction/angular-explorer
- UI framework -
@memberjunction/graphql-dataprovider
- API layer -
@memberjunction/sqlserver-dataprovider
- Data access
You can provide custom templates for code generation:
import { setCustomTemplate } from '@memberjunction/codegen-lib';
setCustomTemplate('entity', myCustomEntityTemplate);
import { analyzeSchema } from '@memberjunction/codegen-lib';
const schemaInfo = await analyzeSchema(databaseConnection);
// Work with schema information
import { onProgress } from '@memberjunction/codegen-lib';
onProgress((status) => {
console.log(`Progress: ${status.message} (${status.percentage}%)`);
});
Need to regenerate specific SQL objects without schema changes? Our force regeneration feature gives you surgical precision over what gets regenerated:
// In mj.config.cjs
forceRegeneration: {
enabled: true,
// Filter to specific entities using SQL WHERE clause
entityWhereClause: "SchemaName = 'CRM' AND __mj_UpdatedAt >= '2025-06-24'",
// Granular control over what gets regenerated
baseViews: true, // Regenerate base views
spCreate: false, // Skip create procedures
spUpdate: true, // Regenerate update procedures
spDelete: false, // Skip delete procedures
indexes: true, // Regenerate foreign key indexes
fullTextSearch: false // Skip full-text search components
}
Regenerate views for recently modified entities:
forceRegeneration: {
enabled: true,
entityWhereClause: "__mj_UpdatedAt >= '2025-06-24 22:00:00'",
baseViews: true
}
Regenerate all stored procedures for a specific schema:
forceRegeneration: {
enabled: true,
entityWhereClause: "SchemaName = 'Sales'",
allStoredProcedures: true
}
Regenerate specific SQL object for a single entity:
forceRegeneration: {
enabled: true,
entityWhereClause: "Name = 'Customer'",
spUpdate: true // Just regenerate the update procedure
}
Regenerate everything (no filtering):
forceRegeneration: {
enabled: true,
// No entityWhereClause = regenerate for ALL entities
allStoredProcedures: true,
baseViews: true,
indexes: true
}
-
Entity Filtering: The
entityWhereClause
runs against the Entity metadata table to select which entities qualify - Type Filtering: Individual flags control which SQL object types get regenerated
- Smart Combination: Only regenerates the intersection (selected entities AND selected types)
- Error Handling: Invalid WHERE clauses stop execution with clear error messages
The library provides comprehensive error handling:
try {
await runCodeGen();
} catch (error) {
if (error.code === 'CONFIG_NOT_FOUND') {
// Handle missing configuration
} else if (error.code === 'DB_CONNECTION_FAILED') {
// Handle database connection errors
}
}
Before MemberJunction CodeGen:
- Weeks of manual entity creation
- Inconsistent validation logic
- Type mismatches between layers
- Manual Angular form creation
- Brittle SQL procedures
- Schema changes break everything
After MemberJunction CodeGen:
- 10 seconds to regenerate entire stack
- Perfect type safety across all layers
- AI-powered intelligent code generation
- Zero manual intervention
- Production-ready from day one
- Configuration Management - Use environment-specific configuration files
- Output Organization - Keep generated code in separate directories
- Version Control - Consider excluding generated files from version control
- Regular Updates - Regenerate code when metadata changes
- Custom Extensions - Extend generated classes rather than modifying them
When contributing to this package:
- Test with real schemas - We generate production apps
- Maintain AI accuracy - Constraint translation must be perfect
- Performance matters - Large schemas must generate quickly
- Type safety is sacred - Never compromise type correctness
This package is part of the MemberJunction ecosystem and follows the same licensing terms.
Ready to experience the future of application development?
npm install @memberjunction/codegen-lib
Your database schema deserves better than manual code generation. Give it the AI-powered, production-ready, full-stack treatment it deserves.