Skip to main content
doc0blade47/drizzle-ormdocumentation home
Sign in

Seed Data Generators

Last updated Oct 12, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

Overview

Seed data generators power the Seed Service Engine by programmatically constructing typed mock values for database columns across PostgreSQL, MySQL, and SQLite. Built upon a unified class architecture with deterministic pseudo-random number generation, these generators map database types and column constraints to realistic synthetic datasets, unique identifiers, and weighted distributions.

Sources: drizzle-seed/src/services/Generators.ts:17-67, drizzle-seed/src/services/SeedService.ts:503-795

Abstract Generator Base Architecture

Class Lifecycle and Properties

The foundational abstract class AbstractGenerator establishes the common contract, static metadata, and runtime properties shared by all mock data generators in drizzle-seed. Every concrete generator inherits static properties such as entityKind (defaulting to 'AbstractGenerator') and version (defaulting to 1), alongside instance flags including isUnique, notNull, dataType, timeSpent, arraySize, baseColumnDataType, and stringLength.

export abstract class AbstractGenerator<T = {}> {
	static readonly entityKind: string = 'AbstractGenerator';
	static readonly version: number = 1;
 
	public isUnique = false;
	public notNull = false;
 
	// param for generators which have a unique version of themselves
	public uniqueVersionOfGen?: new(params: T) => AbstractGenerator<T>;
 
	public dataType?: string;
	public timeSpent?: number;
 
	//
	public arraySize?: number;
	public baseColumnDataType?: string;
 
	// param for text-like generators
	public stringLength?: number;
 
	// params for GenerateValuesFromArray
	public weightedCountSeed?: number | undefined;
	public maxRepeatedValuesCount?: number | { weight: number; count: number | number[] }[] | undefined;
 
	public params: T;
 
	constructor(params?: T) {
		this.params = params === undefined ? {} as T : params as T;
	}

Sources: drizzle-seed/src/services/Generators.ts:17-45

The lifecycle of a generator proceeds from instantiation through parameter initialization and value generation. When instantiated without parameters, it assigns an empty object. Subclasses implement the abstract generate({ i }: { i: number }) method to emit typed values for individual row iterations.

init(params: { count: number | { weight: number; count: number | number[] }[]; seed: number }): void;
init() {
	this.updateParams();
}
 
updateParams() {
	if ((this.params as any).arraySize !== undefined) {
		this.arraySize = (this.params as any).arraySize;
	}
 
	if ((this.params as any).isUnique !== undefined) {
		if ((this.params as any).isUnique === false && this.isUnique === true) {
			throw new Error('specifying non unique generator to unique column.');
		}
 
		this.isUnique = (this.params as any).isUnique;
	}
}
 
abstract generate(params: { i: number }): number | string | boolean | unknown | undefined | void;
 

Sources: drizzle-seed/src/services/Generators.ts:47-67

Parameter Synchronization Protocol

The updateParams() method normalizes configuration state by synchronizing runtime options from the parameter object onto instance properties. Specifically, it maps arraySize and enforces constraints on isUnique. If parameters specify isUnique: false on an instance where isUnique is already true, it throws a fatal error preventing non-unique generators from binding to unique database columns.

updateParams() {
	if ((this.params as any).arraySize !== undefined) {
		this.arraySize = (this.params as any).arraySize;
	}
 
	if ((this.params as any).isUnique !== undefined) {
		if ((this.params as any).isUnique === false && this.isUnique === true) {
			throw new Error('specifying non unique generator to unique column.');
		}
 
		this.isUnique = (this.params as any).isUnique;
	}
}

Sources: drizzle-seed/src/services/Generators.ts:52-64

Caution

Attempting to pass isUnique: false to a generator configured for a unique column triggers an immediate Error('specifying non unique generator to unique column.'). Always verify column constraints before modifying generator uniqueness parameters.

In addition to parameter synchronization, AbstractGenerator provides structural replacement handlers for unique constraint escalation and array column wrapping. The replaceIfUnique() method checks for a registered uniqueVersionOfGen constructor and isUnique flag, instantiating the specialized unique variant while preserving data types and parameters. Similarly, replaceIfArray() detects non-array generators flagged with an arraySize, wrapping the base or unique generator inside a GenerateArray container instance.

replaceIfUnique() {
	this.updateParams();
	if (
		this.uniqueVersionOfGen !== undefined
		&& this.isUnique === true
	) {
		const uniqueGen = new this.uniqueVersionOfGen({
			...this.params,
		});
 
		uniqueGen.isUnique = this.isUnique;
		uniqueGen.dataType = this.dataType;
 
		return uniqueGen;
	}
	return;
}
 
replaceIfArray() {
	this.updateParams();
	if (!(this.getEntityKind() === 'GenerateArray') && this.arraySize !== undefined) {
		const uniqueGen = this.replaceIfUnique();
		const baseColumnGen = uniqueGen === undefined ? this : uniqueGen;
		baseColumnGen.dataType = this.baseColumnDataType;
		const arrayGen = new GenerateArray(
			{
				baseColumnGen,
				size: this.arraySize,
			},
		);
 
		return arrayGen;
	}
 
	return;
}

Sources: drizzle-seed/src/services/Generators.ts:73-108

Pseudo-Random Number Generation with Pure-Rand

Generators requiring random distributions initialize stateful pseudo-random number generators (PRNGs) via the pure-rand library. For instance, GenerateWeightedCount seeds a prand.xoroshiro128plus instance alongside precalculated weighted index arrays, sampling uniform integer distributions across configured frequency weights during generation cycles.

override init({ seed, count }: { count: { weight: number; count: number | number[] }[]; seed: number }) {
	const rng = prand.xoroshiro128plus(seed);
	const weightedIndices = getWeightedIndices(count.map((val) => val.weight));
	this.state = { rng, weightedIndices, weightedCount: count };
}
 
generate() {
	if (this.state === undefined) {
		throw new Error('state is not defined.');
	}
 
	// logic for this generator
	let idx: number;
	const weightedCount = this.state.weightedCount;
 
	[idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.weightedIndices.length - 1, this.state.rng);
	const objIdx = this.state.weightedIndices[idx] as number;
 
	if (typeof weightedCount[objIdx]!.count === 'number') {
		return weightedCount[objIdx]!.count as number;
	} else {
		// typeof weightedCount[objIdx]!.count === 'object' // number[]
		const possCounts = weightedCount[objIdx]!.count as number[];
		[idx, this.state.rng] = prand.uniformIntDistribution(0, possCounts.length - 1, this.state.rng);
		return possCounts[idx]!;
	}
}

Sources: drizzle-seed/src/services/Generators.ts:141-167

Note

drizzle-seed relies exclusively on prand.xoroshiro128plus combined with explicit numeric seeds passed into generator init methods, guaranteeing fully reproducible test data across execution runs and database engines.

Primitive and Temporal Generators

Integer and Numeric Generators

The drizzle-seed engine handles primitive numeric types through dedicated generators designed to cover integer scalars, floating-point numbers, and coordinate systems. The GeneratePoint and GenerateUniquePoint classes instantiate underlying GenerateNumber and GenerateUniqueNumber instances with default precisions set to 10 decimal places, supporting coordinate bounds via minXValue, maxXValue, minYValue, and maxYValue parameters. Depending on the target column data type, point generators emit values as JSON objects, coordinate string tuples, or native arrays.

export class GeneratePoint extends AbstractGenerator<{
	isUnique?: boolean;
	minXValue?: number;
	maxXValue?: number;
	minYValue?: number;
	maxYValue?: number;
	arraySize?: number;
}> {
	static override readonly entityKind: string = 'GeneratePoint';
 
	private state: {
		xCoordinateGen: GenerateNumber;
		yCoordinateGen: GenerateNumber;
	} | undefined;
	override uniqueVersionOfGen = GenerateUniquePoint;
 
	override init({ count, seed }: { count: number; seed: number }) {
		super.init({ count, seed });
 
		const xCoordinateGen = new GenerateNumber({
			minValue: this.params.minXValue,
			maxValue: this.params.maxXValue,
			precision: 10,
		});
		xCoordinateGen.init({ count, seed });
 
		const yCoordinateGen = new GenerateNumber({
			minValue: this.params.minYValue,
			maxValue: this.params.maxYValue,
			precision: 10,
		});
		yCoordinateGen.init({ count, seed });
 
		this.state = { xCoordinateGen, yCoordinateGen };
	}
 
	generate() {
		if (this.state === undefined) {
			throw new Error('state is not defined.');
		}
 
		const x = this.state.xCoordinateGen.generate();
		const y = this.state.yCoordinateGen.generate();
 
		if (this.dataType === 'json') {
			return { x, y };
		} else if (this.dataType === 'string') {
			return `[${x}, ${y}]`;
		} else {
			// if (this.dataType === "array")
			return [x, y];
		}
	}
}
 
export class GenerateUniquePoint extends AbstractGenerator<{
	minXValue?: number;
	maxXValue?: number;
	minYValue?: number;
	maxYValue?: number;
	isUnique?: boolean;
}> {
	static override readonly entityKind: string = 'GenerateUniquePoint';
 
	private state: {
		xCoordinateGen: GenerateUniqueNumber;
		yCoordinateGen: GenerateUniqueNumber;
	} | undefined;
	public override isUnique = true;
 
	override init({ count, seed }: { count: number; seed: number }) {
		const xCoordinateGen = new GenerateUniqueNumber({
			minValue: this.params.minXValue,
			maxValue: this.params.maxXValue,
			precision: 10,
		});
		xCoordinateGen.init({ count, seed });
 
		const yCoordinateGen = new GenerateUniqueNumber({
			minValue: this.params.minYValue,

Sources: drizzle-seed/src/services/Generators.ts:2873-2978

Geometric entity generation extends to linear equations via GenerateLine, which parameterizes linear coefficients across configurable minimum and maximum bounds for variables $A$, $B$, and $C$.

export class GenerateLine extends AbstractGenerator<{
	isUnique?: boolean;
	minAValue?: number;
	maxAValue?: number;
	minBValue?: number;
	maxBValue?: number;
	minCValue?: number;
	maxCValue?: number;
	arraySize?: number;
}> {
	static override readonly entityKind: string = 'GenerateLine';
 
	private state: {
		aCoefficientGen: GenerateNumber;
		bCoefficientGen: GenerateNumber;
		cCoefficientGen: GenerateNumber;
	} | undefined;
	override uniqueVersionOfGen = GenerateUniqueLine;
 

Sources: drizzle-seed/src/services/Generators.ts:2980-2998

Note

Point generators inspect the target column's dataType property at runtime, switching output formats dynamically between { x, y } for JSON columns, [x, y] strings for string columns, and JavaScript arrays for array columns.

Text and Paragraph Generators

Text-based primitive generation includes GenerateLoremIpsum, which builds multi-sentence lorem ipsum text blocks using predefined sentence datasets. The initialization phase computes the maximum possible string length based on the requested sentence count and compares it against database column length restrictions.

export class GenerateLoremIpsum extends AbstractGenerator<{
	sentencesCount?: number;
	arraySize?: number;
}> {
	static override readonly entityKind: string = 'GenerateLoremIpsum';
 
	private state: {
		rng: prand.RandomGenerator;
	} | undefined;
 
	override init({ count, seed }: { count: number; seed: number }) {
		super.init({ count, seed });
 
		const rng = prand.xoroshiro128plus(seed);
		if (this.params.sentencesCount === undefined) this.params.sentencesCount = 1;
 
		const maxLoremIpsumSentencesLength = maxLoremIpsumLength * this.params.sentencesCount + this.params.sentencesCount
			- 1;
		if (this.stringLength !== undefined && this.stringLength < maxLoremIpsumSentencesLength) {
			throw new Error(
				`You can't use lorem ipsum generator with a db column length restriction of ${this.stringLength}. Set the maximum string length to at least ${maxLoremIpsumSentencesLength}.`,
			);
		}
 
		this.state = { rng };
	}

Sources: drizzle-seed/src/services/Generators.ts:2768-2793

During generation, GenerateLoremIpsum samples uniform integer distributions across the dataset of lorem ipsum sentences using prand.xoroshiro128plus, concatenating the selected sentences into the final result string.

	generate() {
		if (this.state === undefined) {
			throw new Error('state is not defined.');
		}
 
		let idx, resultText: string = '';
		for (let i = 0; i < this.params.sentencesCount!; i++) {
			[idx, this.state.rng] = prand.uniformIntDistribution(0, loremIpsumSentences.length - 1, this.state.rng);
			resultText += loremIpsumSentences[idx] + ' ';
		}
 
		return resultText;
	}
}

Sources: drizzle-seed/src/services/Generators.ts:2795-2808

Caution

If a database column enforces a maximum string length that is smaller than the minimum required size for the requested lorem ipsum sentence count, GenerateLoremIpsum throws an explicit error during init(). Always verify column length constraints when configuring paragraph generators.

Realistic Entity Datasets

Static Corpora and Bounded String Lengths

drizzle-seed incorporates static domain datasets to supply contextually accurate mock records for geographic, professional, and contact attributes. These corpora are paired with explicit string length constants to validate column schema boundaries before execution. The country dataset provides 170 recognized country names derived from census and geographical repositories, with a maximum string length boundary of 30 characters.

export default [
	'Afghanistan',
	'Albania',
	'Algeria',
	'Angola',
	'Antigua and Barbuda',
	'Argentina',
	'Armenia',
	'Australia',
	'Austria',
	'Azerbaijan',
	'Bahamas',
	'Bahrain',
	'Bangladesh',
	'Barbados',
	'Belgium',
	'Belize',
	'Benin',
	'Bhutan',
	'Bolivia',
	'Bosnia and Herzegovina',
	'Botswana',
	'Brazil',
	'Brunei',
	'Bulgaria',
	'Burkina Faso',
	'Burundi',
	'Cambodia',
	'Cameroon',
	'Canada',
	'Cape Verde',
	'Central African Republic',
	'Chad',
	'Chile',
	'China',
	'Colombia',
	'Comoros',
	'Congo, Dem. Rep.',
	'Congo, Rep.',
	'Costa Rica',
	"Cote d'Ivoire",
	'Croatia',
	'Cyprus',
	'Czech Republic',
	'Denmark',
	'Dominican Republic',
	'Ecuador',
	'Egypt',
	'El Salvador',
	'Equatorial Guinea',
	'Eritrea',
	'Estonia',
	'Fiji',
	'Finland',
	'France',
	'Gabon',
	'Gambia',
	'Georgia',
	'Germany',
	'Ghana',
	'Greece',
	'Grenada',
	'Guatemala',
	'Guinea',
	'Guinea-Bissau',
	'Guyana',
	'Haiti',
	'Hungary',
	'Iceland',
	'India',
	'Indonesia',
	'Iran',
	'Iraq',
	'Ireland',
	'Israel',
	'Italy',
	'Jamaica',
	'Japan',
	'Jordan',
	'Kazakhstan',

Sources: drizzle-seed/src/datasets/countries.ts:5-171, drizzle-seed/src/datasets/countries.ts:173

Email domains comprise 23 global messaging providers and regional top-level domains, accompanied by a maximum string length constraint of 14 characters.

export default [
	'gmail.com',
	'yahoo.com',
	'outlook.com',
	'msn.com',
	'hotmail.com',
	'aol.com',
	'hotmail.co.uk',
	'hotmail.fr',
	'yahoo.fr',
	'wanadoo.fr',
	'orange.fr',
	'comcast.net',
	'yahoo.co.uk',
	'yahoo.com.br',
	'yahoo.co.in',
	'live.com',
	'rediffmail.com',
	'free.fr',
	'gmx.de',
	'web.de',
	'ymail.com',
	'libero.it',
];
…
export const maxStringLength = 14;

Sources: drizzle-seed/src/datasets/emailDomains.ts:1-24, drizzle-seed/src/datasets/emailDomains.ts:26

Professional titles encompass 152 distinct job roles spanning engineering, management, healthcare, and administrative specializations, bounded by a maximum string length of 35 characters.

export default [
	'Digital marketing specialist',
	'Web developer',
	'Operations manager',
	'Network engineer',
	'Event manager',
	'Software tester',
	'Teacher',
	'Ux/ui designer',
	'Wedding planner',
	'Qa analyst',
	'Litigation attorney',
	'Mechanical engineer',
	'Network administrator',
	'Account manager',
	'Brand manager',
	'Social worker',
	'Social media coordinator',
	'Email marketing specialist',
	'Hr generalist',
	'Legal assistant',
	'Nurse practitioner',
	'Account director',
	'Software engineer',
	'Purchasing agent',
	'Sales consultant',
	'Civil engineer',
	'Network security specialist',
	'Ui developer',
	'Financial planner',
	'Event planner',
	'Psychologist',
	'Electrical designer',
	'Data analyst',
	'Technical writer',
	'Tax consultant',
	'Account executive',
	'Systems administrator',
	'Database administrator',
	'Research analyst',
	'Data entry clerk',
	'Registered nurse',
	'Investment analyst',
	'Speech therapist',
	'Sales manager',
	'Landscape architect',
	'Key account manager',
	'Ux researcher',
	'Investment banker',
	'It support specialist',
	'Art director',
	'Software developer',
	'Project manager',
	'Customer service manager',
	'Procurement manager',
	'Substance abuse counselor',
	'Supply chain analyst',
	'Data engineer',
	'Accountant',
	'Sales representative',
	'Environmental consultant',
	'Electrical engineer',
	'Systems engineer',
	'Art teacher',
	'Human resources manager',
	'Inventory analyst',
	'Legal counsel',
	'Database developer',
	'Procurement specialist',
	'Systems analyst',
	'Copywriter',
	'Content writer',
	'Hr coordinator',
	'Business development manager',
	'Java developer',
	'Supply chain manager',
	'Event coordinator',
	'Family nurse practitioner',
	'Front-end engineer',
	'Customer success manager',

Sources: drizzle-seed/src/datasets/jobsTitles.ts:4-152, drizzle-seed/src/datasets/jobsTitles.ts:154

Note

Specific geographic entries and administrative subdivisions are intentionally filtered out from standard datasets during curation to prevent inappropriate records from populating relational columns.

Dataset Schema Summary

Dataset ModuleSample Entries / CategoriesMaximum String LengthPrimary Source Reference
countries.tsAfghanistan, Albania, ..., Zambia30Kaggle countrydatacsv
emailDomains.tsgmail.com, yahoo.com, outlook.com, ..., libero.it14Native dataset corpus
jobsTitles.tsDigital marketing specialist, Web developer, ..., Market analyst35Kaggle job-description-dataset

Sources: drizzle-seed/src/datasets/countries.ts:5-173, drizzle-seed/src/datasets/emailDomains.ts:1-26, drizzle-seed/src/datasets/jobsTitles.ts:4-154

Unique Constraint Enforcement and Deduplication

Replacement Strategies and Unique Versions

drizzle-seed enforces column uniqueness using replacement mechanisms and specialized generator classes designed to prevent collisions. When a base generator detects that isUnique is set to true, replaceIfUnique() inspects the generator's uniqueVersionOfGen mapping and instantiates the specialized variant with preserved parameters and data types.

replaceIfUnique() {
	this.updateParams();
	if (
		this.uniqueVersionOfGen !== undefined
		&& this.isUnique === true
	) {
		const uniqueGen = new this.uniqueVersionOfGen({
			...this.params,
		});
 
		uniqueGen.isUnique = this.isUnique;
		uniqueGen.dataType = this.dataType;
 
		return uniqueGen;
	}
	return;
}

Sources: drizzle-seed/src/services/Generators.ts:73-89

For instance, GeneratePoint maps its uniqueVersionOfGen property directly to GenerateUniquePoint, ensuring that coordinates are generated through dedicated unique numeric generators for each axis.

override uniqueVersionOfGen = GenerateUniquePoint;

Sources: drizzle-seed/src/services/Generators.ts:2887

public override isUnique = true;
 
override init({ count, seed }: { count: number; seed: number }) {
	const xCoordinateGen = new GenerateUniqueNumber({
		minValue: this.params.minXValue,
		maxValue: this.params.maxXValue,
		precision: 10,
	});
	xCoordinateGen.init({ count, seed });
 
	const yCoordinateGen = new GenerateUniqueNumber({
		minValue: this.params.minYValue,
		maxValue: this.params.maxYValue,
		precision: 10,
	});
	yCoordinateGen.init({ count, seed });
 
	this.state = { xCoordinateGen, yCoordinateGen };
}

Sources: drizzle-seed/src/services/Generators.ts:2941-2959

Warning

Specifying a non-unique generator class directly on a column marked with a unique constraint throws an immediate error during parameter updates via updateParams(), preventing invalid database seeding configurations before execution.

if ((this.params as any).isUnique !== undefined) {
	if ((this.params as any).isUnique === false && this.isUnique === true) {
		throw new Error('specifying non unique generator to unique column.');
	}
 
	this.isUnique = (this.params as any).isUnique;
}

Sources: drizzle-seed/src/services/Generators.ts:57-63

String and Temporal Uniqueness Deduplication

String and temporal generators implement explicit boundary validations and collision-avoidance loops during initialization and record generation. GenerateUniqueStringV2 converts the loop index i into a hexadecimal string (i.toString(16)) and pads it with randomly sampled character distributions to guarantee absolute uniqueness across requested row counts.

generate({ i }: { i: number }) {
	if (this.state === undefined) {
		throw new Error('state is not defined.');
	}
 
	const minStringLength = this.state.minStringLength,
		maxStringLength = this.state.maxStringLength;
	const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	let idx: number,
		strLength: number;
	let currStr: string;
 
	currStr = '';
	const uniqueStr = i.toString(16);
	[strLength, this.state.rng] = prand.uniformIntDistribution(
		minStringLength,
		maxStringLength - uniqueStr.length,
		this.state.rng,
	);
	for (let j = 0; j < strLength - uniqueStr.length; j++) {
		[idx, this.state.rng] = prand.uniformIntDistribution(
			0,
			stringChars.length - 1,
			this.state.rng,
		);
		currStr += stringChars[idx];
	}
 
	return uniqueStr + currStr;
}

Sources: drizzle-seed/src/services/versioning/v2.ts:202-231

If the requested count exceeds the combinatorial capacity of the maximum string length, GenerateUniqueStringV2 throws a descriptive error.

if (maxStringLength < count.toString(16).length) {
	throw new Error(
		`You can't generate ${count} unique strings, with a maximum string length of ${maxStringLength}.`,
	);
}

Sources: drizzle-seed/src/services/versioning/v2.ts:193-197

Similarly, GenerateUniqueIntervalV2 calculates the maximum possible unique intervals using a configuration map of field boundaries spanning years down to seconds. If the requested record count exceeds this calculated ceiling, a RangeError is thrown.

private config: { [key: string]: { from: number; to: number } } = {
	year: {
		from: 0,
		to: 5,
	},
	month: {
		from: 0,
		to: 11,
	},
	day: {
		from: 0,
		to: 29,
	},
	hour: {
		from: 0,
		to: 23,
	},
	minute: {
		from: 0,
		to: 59,
	},
	second: {
		from: 0,
		to: 59,
	},
};
 
override init({ count, seed }: { count: number; seed: number }) {
	const allFields = ['year', 'month', 'day', 'hour', 'minute', 'second'];
	let fieldsToGenerate: string[] = allFields;
 
	if (this.params.fields !== undefined && this.params.fields?.includes(' to ')) {
		const tokens = this.params.fields.split(' to ');
		const endIdx = allFields.indexOf(tokens[1]!);
		fieldsToGenerate = allFields.slice(0, endIdx + 1);
	} else if (this.params.fields !== undefined) {
		const endIdx = allFields.indexOf(this.params.fields);
		fieldsToGenerate = allFields.slice(0, endIdx + 1);
	}
 
	let maxUniqueIntervalsNumber = 1;
	for (const field of fieldsToGenerate) {
		const from = this.config[field]!.from, to = this.config[field]!.to;
		maxUniqueIntervalsNumber *= from - to + 1;
	}
 
	if (count > maxUniqueIntervalsNumber) {
		throw new RangeError(`count exceeds max number of unique intervals(${maxUniqueIntervalsNumber})`);
	}

Sources: drizzle-seed/src/services/versioning/v2.ts:31-79

When generating records, GenerateUniqueIntervalV2 populates an internal Set<string> (intervalSet), retrying uniform distributions until an unrecorded unique interval string is secured.

	generate() {
		if (this.state === undefined) {
			throw new Error('state is not defined.');
		}
 
		let interval, numb: number;
 
		for (;;) {
			interval = '';
 
			for (const field of this.state.fieldsToGenerate) {
				const from = this.config[field]!.from, to = this.config[field]!.to;
				[numb, this.state.rng] = prand.uniformIntDistribution(from, to, this.state.rng);
				interval += `${numb} ${field} `;
			}
 
			if (!this.state.intervalSet.has(interval)) {
				this.state.intervalSet.add(interval);
				break;
			}
		}
 
		return interval;
	}
}

Sources: drizzle-seed/src/services/versioning/v2.ts:86-110

Caution

Relying on retry loops with Set collections can introduce performance bottlenecks if the requested count approaches the total combinatorial limit of the underlying configuration domain.

Weighted Random Distributions

Weighted Array and Count Distribution Mechanics

drizzle-seed implements non-uniform value selection using weighted distribution engines built on top of the pure-rand Xoroshiro128plus PRNG. The GenerateWeightedCount class manages counts associated with explicit weights, utilizing helper utilities to resolve index probabilities. During initialization, GenerateWeightedCount maps user-defined weights into an array of weighted indices via getWeightedIndices, allowing frequency-based selection during record generation.

override init({ seed, count }: { count: { weight: number; count: number | number[] }[]; seed: number }) {
	const rng = prand.xoroshiro128plus(seed);
	const weightedIndices = getWeightedIndices(count.map((val) => val.weight));
	this.state = { rng, weightedIndices, weightedCount: count };
}

Sources: drizzle-seed/src/services/Generators.ts:141-145

When generate() is invoked, uniform integer distribution selects an index from the precomputed weighted array. If the target count entry contains a single numeric value, it is returned directly; if the entry defines an array of possible counts, a secondary uniform distribution resolves the specific integer count to return.

let idx: number;
const weightedCount = this.state.weightedCount;
 
[idx, this.state.rng] = prand.uniformIntDistribution(0, this.state.weightedIndices.length - 1, this.state.rng);
const objIdx = this.state.weightedIndices[idx] as number;
 
if (typeof weightedCount[objIdx]!.count === 'number') {
	return weightedCount[objIdx]!.count as number;
} else {
	// typeof weightedCount[objIdx]!.count === 'object' // number[]
	const possCounts = weightedCount[objIdx]!.count as number[];
	[idx, this.state.rng] = prand.uniformIntDistribution(0, possCounts.length - 1, this.state.rng);
	return possCounts[idx]!;
}

Sources: drizzle-seed/src/services/Generators.ts:153-166

Note

If GenerateWeightedCount is called before its init() lifecycle method establishes the internal state object, an explicit runtime error is thrown to prevent unseeded execution.

if (this.state === undefined) {
	throw new Error('state is not defined.');
}

Sources: drizzle-seed/src/services/Generators.ts:148-150

WeightedRandomGenerator Configuration and Initialization

The WeightedRandomGenerator class distributes generation tasks across multiple wrapped sub-generators based on assigned weighting parameters. During its initialization phase, it tabulates sample frequencies across the population count to size and initialize each underlying sub-generator properly.

override init({ count, seed }: { count: number; seed: number }) {
	const weights = this.params.map((weightedGen) => weightedGen.weight);
	const weightedIndices = getWeightedIndices(weights);
 
	let idx: number, valueIdx: number, tempRng = prand.xoroshiro128plus(seed);
	const indicesCounter: { [key: number]: number } = {};
	for (let i = 0; i < count; i++) {
		[idx, tempRng] = prand.uniformIntDistribution(0, weightedIndices.length - 1, tempRng);
		valueIdx = weightedIndices[idx]!;
		if (!Object.hasOwn(indicesCounter, valueIdx)) indicesCounter[valueIdx] = 0;
		indicesCounter[valueIdx]! += 1;
	}
 
	for (const [idx, weightedGen] of this.params.entries()) {
		weightedGen.value.isUnique = this.isUnique;
		weightedGen.value.dataType = this.dataType;
		weightedGen.value.init({ count: indicesCounter[idx]!, seed });
 

Sources: drizzle-seed/src/services/Generators.ts:2818-2835

Generator ClassEntity Kind IdentifierCore State ParametersPrimary Purpose
GenerateWeightedCountGenerateWeightedCountrng, weightedIndices, weightedCountResolves non-uniform integer counts or ranges based on assigned weights
WeightedRandomGeneratorWeightedRandomGeneratorrng, weightedIndicesRoutes value generation across a weighted array of sub-generators

Sources: drizzle-seed/src/services/Generators.ts:133-139, drizzle-seed/src/services/Generators.ts:2811-2816

Tip

WeightedRandomGenerator automatically propagates column uniqueness flags and data types down to each weighted sub-generator, instantiating unique counterpart generator classes when unique constraints are active.

for (const [idx, weightedGen] of this.params.entries()) {
	weightedGen.value.isUnique = this.isUnique;
	weightedGen.value.dataType = this.dataType;
	weightedGen.value.init({ count: indicesCounter[idx]!, seed });
 
	if (
		weightedGen.value.uniqueVersionOfGen !== undefined
		&& weightedGen.value.isUnique === true
	) {
		const uniqueGen = new weightedGen.value.uniqueVersionOfGen({
			...weightedGen.value.params,
		});
		uniqueGen.init({
			count: indicesCounter[idx]!,
			seed,
		});
		uniqueGen.isUnique = weightedGen.value.isUnique;
		uniqueGen.dataType = weightedGen.value.dataType;
 
		weightedGen.value = uniqueGen;
	}

Sources: drizzle-seed/src/services/Generators.ts:2831-2851

Versioned Generator Evolutions

Versioning Interfaces and Generator Mappings

drizzle-seed supports evolutionary versioning across generator implementations, allowing refined algorithms to be introduced without breaking legacy behavior. Generators declare their version via static properties on the AbstractGenerator base class and register variations in the global generatorsMap lookup structure.

export abstract class AbstractGenerator<T = {}> {
	static readonly entityKind: string = 'AbstractGenerator';
	static readonly version: number = 1;
 

Sources: drizzle-seed/src/services/Generators.ts:17-20

Generator ClassEntity Kind IdentifierVersionCore State Parameters / Mappings
GenerateIntervalGenerateInterval1Standard interval generator
GenerateUniqueIntervalV2GenerateUniqueInterval2rng, fieldsToGenerate, intervalSet
GenerateStringGenerateString1Standard string generator
GenerateStringV2GenerateString2rng, minStringLength, maxStringLength
GenerateUniqueStringV2GenerateUniqueString2rng, minStringLength, maxStringLength, isUnique

Sources: drizzle-seed/src/services/Generators.ts:816-830, drizzle-seed/src/services/versioning/v2.ts:22-29, drizzle-seed/src/services/versioning/v2.ts:116-123, drizzle-seed/src/services/versioning/v2.ts:172-179

Note

The generatorsFuncsV2 object mirrors the standard generator function bindings, providing a uniform API surface for accessing updated version behaviors during schema refinement.

}
 
if (this.state!.integersCount.get(numb) === undefined || this.state!.integersCount.get(numb) === 0) {
	if (numb === currMinNumb) {

Sources: drizzle-seed/src/services/Generators.ts:760-763

GenerateStringV2 and GenerateUniqueStringV2 Execution

The GenerateStringV2 class bounds random string lengths between 7 and 20 characters by default, adjusting parameters if a specific stringLength restriction is supplied. Its unique counterpart, GenerateUniqueStringV2, encodes the current iteration index i into a hexadecimal string prefix, appending randomly selected characters from a 62-character alphanumeric set (stringChars) to satisfy uniqueness constraints.

override init({ seed, count }: { seed: number; count: number }) {
	const rng = prand.xoroshiro128plus(seed);
 
	let minStringLength = 7;
	let maxStringLength = 20;
	// TODO: revise later
	if (this.stringLength !== undefined) {
		maxStringLength = this.stringLength;
		if (maxStringLength === 1 || maxStringLength < minStringLength) minStringLength = maxStringLength;
	}
 
	if (maxStringLength < count.toString(16).length) {
		throw new Error(
			`You can't generate ${count} unique strings, with a maximum string length of ${maxStringLength}.`,
		);
	}
 
	this.state = { rng, minStringLength, maxStringLength };
}

Sources: drizzle-seed/src/services/versioning/v2.ts:182-200

generate({ i }: { i: number }) {
	if (this.state === undefined) {
		throw new Error('state is not defined.');
	}
 
	const minStringLength = this.state.minStringLength,
		maxStringLength = this.state.maxStringLength;
	const stringChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	let idx: number,
		strLength: number;
	let currStr: string;
 
	currStr = '';
	const uniqueStr = i.toString(16);
	[strLength, this.state.rng] = prand.uniformIntDistribution(
		minStringLength,
		maxStringLength - uniqueStr.length,
		this.state.rng,
	);
	for (let j = 0; j < strLength - uniqueStr.length; j++) {
		[idx, this.state.rng] = prand.uniformIntDistribution(
			0,
			stringChars.length - 1,
			this.state.rng,
		);
		currStr += stringChars[idx];
	}
 
	return uniqueStr + currStr;
}

Sources: drizzle-seed/src/services/versioning/v2.ts:202-231

Warning

GenerateUniqueStringV2 throws an explicit error if the requested population count requires more hexadecimal characters than the allowed maximum string length permits.

if (maxStringLength < count.toString(16).length) {
	throw new Error(
		`You can't generate ${count} unique strings, with a maximum string length of ${maxStringLength}.`,
	);
}

Sources: drizzle-seed/src/services/versioning/v2.ts:193-197

Was this page helpful?