@seedts/jsx-runtime
v0.1.1
Published
JSX runtime for SeedTS seed definitions
Downloads
2
Maintainers
Readme
@seedts/jsx-runtime
JSX runtime for declarative seed definitions in SeedTS
The JSX runtime package enables you to write database seeds using familiar React-like JSX syntax. This provides a clean, declarative way to define seeds with full TypeScript support.
Installation
pnpm add @seedts/jsx-runtimeNote: This package is automatically included when you install the main
seedtspackage.
Setup
TypeScript Configuration
Add JSX support to your tsconfig.json:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "seedts"
}
}File Extension
Use .tsx extension for seed files:
users.seed.tsx✅users.seed.ts❌ (won't work with JSX)
Quick Start
Basic Example
import { Seed, Action, Entity, Attribute } from 'seedts/jsx-runtime';
import { PostgreSQLAdapter } from '@seedts/adapter-postgresql';
const adapter = new PostgreSQLAdapter(pool);
export const UsersSeed = (
<Seed name="users" adapter={adapter}>
<Action count={10}>
<Entity>
<Attribute
name="email"
factory={(ctx) => `user${ctx.index}@example.com`}
/>
<Attribute
name="name"
factory={(ctx) => `User ${ctx.index}`}
/>
<Attribute
name="role"
factory={() => 'user'}
/>
</Entity>
</Action>
</Seed>
);Components
<Seed> - Seed Container
The root component for a seed definition.
<Seed
name="users" // Seed name (required)
adapter={adapter} // Database adapter (required)
dependsOn="other-seed" // Single dependency
dependsOn={["a", "b"]} // Multiple dependencies
beforeInsert={fn} // Hook: before insert
afterInsert={fn} // Hook: after insert
onSuccess={fn} // Hook: on success
onError={fn} // Hook: on error
>
{/* Actions go here */}
</Seed>Props:
name: string- Unique seed identifieradapter: SeedAdapter- Database adapter instancedependsOn?: string | string[]- Seed dependenciesbeforeInsert?: (data) => Promise<T[]> | T[]- Pre-insert hookafterInsert?: (data, inserted) => Promise<void> | void- Post-insert hookonSuccess?: (data, metadata) => Promise<void> | void- Success hookonError?: (error) => Promise<void> | void- Error hook
<Action> - Data Generation Action
Defines a batch of data to generate and insert.
<Action
count={100} // Number of records
run={condition} // Conditional execution
condition={asyncFn} // Async condition check
beforeInsert={transformFn} // Transform before insert
onConflict="skip" // Conflict strategy
>
<Entity />
</Action>Props:
count: number- Number of records to generaterun?: boolean- Conditional execution (default: true)condition?: (ctx) => Promise<boolean> | boolean- Async conditionbeforeInsert?: (data) => Promise<T[]> | T[]- Transform dataonConflict?: 'skip' | 'update' | 'error'- Conflict resolution
<Entity> - Record Definition
Defines the structure of a single record.
<Entity
data={{name: 'Static', value: 123}} // Static data
factory={factoryFn} // Dynamic generation
>
<Attribute name="field1" factory={fn1} />
<Attribute name="field2" factory={fn2} />
</Entity>Props:
data?: Partial<T>- Static data for all recordsfactory?: (ctx) => Partial<T>- Dynamic data generation
<Attribute> - Field Definition
Defines a single field/column in a record.
<Attribute
name="email" // Field name
factory={factoryFn} // Value generator
transform={transformFn} // Value transformer
required={true} // Validation
unique={true} // Uniqueness check
/>Props:
name: string- Field/column namefactory: (ctx) => any- Value generation functiontransform?: (value) => any- Value transformationrequired?: boolean- Field is requiredunique?: boolean- Value must be unique
Examples
With Dependencies
// users.seed.tsx
export const UsersSeed = (
<Seed name="users" adapter={adapter}>
<Action count={50}>
<Entity>
<Attribute name="email" factory={faker.email()} />
<Attribute name="name" factory={faker.fullName()} />
</Entity>
</Action>
</Seed>
);
// posts.seed.tsx
export const PostsSeed = (
<Seed name="posts" dependsOn="users" adapter={adapter}>
<Action count={100}>
<Entity factory={async (ctx) => {
const users = await ctx.getSeed('users');
return {
userId: users[ctx.index % users.length].id,
};
}}>
<Attribute name="title" factory={faker.sentence()} />
<Attribute name="content" factory={faker.paragraph()} />
</Entity>
</Action>
</Seed>
);Conditional Seeding
<Seed name="demo-users" adapter={adapter}>
<Action
count={50}
run={process.env.NODE_ENV === 'development'}
>
<Entity>
<Attribute name="email" factory={faker.email()} />
</Entity>
</Action>
<Action
count={1}
condition={async (ctx) => {
const users = await ctx.getSeed('users');
return users.length === 0;
}}
>
<Entity data={{ email: '[email protected]', role: 'admin' }} />
</Action>
</Seed>Data Transformers
<Seed name="users" adapter={adapter}>
<Action count={10}>
<Entity>
<Attribute
name="email"
factory={faker.email()}
transform={(email) => email.toLowerCase()}
/>
<Attribute
name="password"
factory={() => 'password123'}
transform={hashPassword}
/>
<Attribute
name="createdAt"
factory={() => new Date()}
/>
</Entity>
</Action>
</Seed>Lifecycle Hooks
<Seed
name="users"
adapter={adapter}
beforeInsert={(data) => {
console.log(`Inserting ${data.length} users`);
return data.map(user => ({
...user,
createdAt: new Date(),
}));
}}
afterInsert={(data, inserted) => {
console.log(`Inserted ${inserted.length} users`);
}}
onSuccess={(data, metadata) => {
console.log(`Success! Duration: ${metadata.duration}ms`);
}}
onError={(error) => {
console.error('Seeding failed:', error);
}}
>
<Action count={100}>
<Entity>
<Attribute name="email" factory={faker.email()} />
</Entity>
</Action>
</Seed>Multiple Actions
<Seed name="users" adapter={adapter}>
{/* Admin users */}
<Action count={5}>
<Entity>
<Attribute name="email" factory={faker.email()} />
<Attribute name="role" factory={() => 'admin'} />
</Entity>
</Action>
{/* Regular users */}
<Action count={100}>
<Entity>
<Attribute name="email" factory={faker.email()} />
<Attribute name="role" factory={() => 'user'} />
</Entity>
</Action>
{/* Premium users */}
<Action count={20}>
<Entity>
<Attribute name="email" factory={faker.email()} />
<Attribute name="role" factory={() => 'premium'} />
<Attribute name="subscriptionEnd" factory={() => {
const date = new Date();
date.setFullYear(date.getFullYear() + 1);
return date;
}} />
</Entity>
</Action>
</Seed>Static Data
<Seed name="categories" adapter={adapter}>
<Action count={1}>
<Entity data={{
name: 'Technology',
slug: 'technology',
order: 1,
}} />
</Action>
<Action count={1}>
<Entity data={{
name: 'Science',
slug: 'science',
order: 2,
}} />
</Action>
</Seed>With Faker Integration
import { faker } from '@seedts/faker';
<Seed name="users" adapter={adapter}>
<Action count={100}>
<Entity>
<Attribute name="email" factory={faker.email()} />
<Attribute name="firstName" factory={faker.firstName()} />
<Attribute name="lastName" factory={faker.lastName()} />
<Attribute name="age" factory={faker.int({ min: 18, max: 80 })} />
<Attribute name="bio" factory={faker.paragraph()} />
<Attribute name="avatar" factory={faker.imageUrl()} />
<Attribute name="website" factory={faker.url()} />
</Entity>
</Action>
</Seed>Execution Context
Access execution context in factory functions:
<Attribute
name="email"
factory={(ctx) => {
// Current index (0-based)
const index = ctx.index;
// Total count
const total = ctx.count;
// Seed name
const seedName = ctx.seedName;
// Get data from other seeds
const otherData = await ctx.getSeed('other-seed');
return `user${index}@example.com`;
}}
/>Type Safety
Full TypeScript support with type inference:
type User = {
id?: number;
email: string;
name: string;
role: 'admin' | 'user';
};
export const UsersSeed = (
<Seed<User> name="users" adapter={adapter}>
<Action count={10}>
<Entity>
{/* TypeScript will enforce correct types */}
<Attribute<User, 'email'>
name="email"
factory={(ctx) => `user${ctx.index}@example.com`}
/>
<Attribute<User, 'role'>
name="role"
factory={() => 'user'} // Type-checked!
/>
</Entity>
</Action>
</Seed>
);Running JSX Seeds
import { Executor } from '@seedts/core';
import { UsersSeed } from './seeds/users.seed';
import { PostsSeed } from './seeds/posts.seed';
const executor = new Executor([UsersSeed, PostsSeed]);
await executor.execute();API Reference
For detailed API documentation, visit:
Related Packages
- @seedts/core - Core execution engine
- @seedts/types - Type definitions
- @seedts/faker - Faker integration
- seedts - Main convenience package
Contributing
Contributions are welcome! Please see our Contributing Guide.
License
MIT © SeedTS Contributors
