npm.io
1.1.1 • Published yesterday

linked-faker

Licence
MIT
Version
1.1.1
Deps
0
Size
204 kB
Vulns
0
Weekly
0

linked-faker

Generate realistic relational test data with valid relationships — from one declarative schema.

Random values give you one field at a time. linked-faker gives you a whole dataset — users, orders, products — wired together with valid foreign keys.

No manual IDs. No seed scripts. No broken foreign keys.

Installation

npm install linked-faker

Zero required dependencies. Built-in field generators included.

Quick Start

import { defineSchema, generate, oneOf, number, faker } from 'linked-faker';

const schema = defineSchema({
  users: {
    count: 10,
    idPrefix: 'usr',
    fields: {
      name: 'person.fullName',              // built-in path
      email: faker('internet.email'),       // helper API
      createdAt: 'date.past',
    },
  },
  products: {
    count: 20,
    idPrefix: 'prd',
    fields: {
      name: 'commerce.productName',
      price: 'commerce.price',
    },
  },
  orders: {
    count: 50,
    idPrefix: 'ord',
    fields: {
      orderedAt: 'date.recent',
    },
    relations: {
      userId: { ref: 'users' },
      productIds: { ref: 'products', many: true, min: 1, max: 4 },
    },
  },
});

const data = generate(schema);

console.log(data.users[0]);
console.log(data.orders[0]);
// { id: 'ord_1', orderedAt: '...', userId: 'usr_7', productIds: ['prd_2', 'prd_9'] }

Every userId in orders is guaranteed to match a real generated id in users. No manual wiring required.

Core Concepts

Entities

Each top-level key in your schema (users, products, orders) is an entity — think of it as a database table.

Fields

Each entity has fields, mapped to built-in generator paths, helper descriptors, custom functions, or static values.

Relations

Relations describe how one entity's records point to another — the core feature that turns random fields into a coherent dataset.

IDs

By default, every generated record gets an auto id field (usr_1, usr_2, …). Customize the format per entity with idPrefix.

API Reference

defineSchema(schemaObject)

Defines the shape of your dataset. Validates the schema and returns it for use with generate().

defineSchema({
  [entityName: string]: {
    count?: number;
    countPerParent?: { ref: string; min: number; max: number };
    idPrefix?: string;
    fields?: Record<string, string | ((record, index) => unknown) | unknown>;
    relations?: Record<string, RelationConfig>;
  };
});
Option Type Default Description
count number Number of records to generate (required unless countPerParent is set)
countPerParent object Generate a variable number of child records per parent
idPrefix string first 3 chars of entity name Prefix for generated IDs (usr_1, prd_1, etc.)
fields object {} Field name → generator mapping
relations object {} Field name → relation config
generate(schema, options?)

Generates the full dataset based on the schema. Entities are generated in topological order to satisfy relationship dependencies — you don't need to declare entities in a particular order.

generate(schema, {
  seed?: number;      // reproducible output
  validate?: boolean; // return { data, validation, valid }
});

Returns: an object keyed by entity name, each containing an array of generated records.

{
  users: [{ ... }, { ... }],
  products: [{ ... }, { ... }],
  orders: [{ ... }, { ... }],
}
Field Generators

Fields accept:

1. A built-in generator path

fields: {
  name: 'person.fullName',
  email: 'internet.email',
  price: 'commerce.price',
}

2. A helper descriptor

fields: {
  status: oneOf(['pending', 'paid', 'cancelled']),
  total: number({ min: 10, max: 500 }),
  email: faker('internet.email'),
}

3. A custom function (receives the record being built and its index)

fields: {
  username: (record, index) => `user_${index}`,
  isActive: () => Math.random() > 0.2,
}

4. A fixed/static value

fields: {
  role: 'customer',
}
Relations

Belongs-to (single reference)

relations: {
  userId: { ref: 'users' },
}

Many-to-many

relations: {
  productIds: { ref: 'products', many: true, min: 1, max: 5 },
}

Filtered relation

relations: {
  userId: {
    ref: 'users',
    filter: (user) => user.isActive === true,
  },
}

Cascading counts (each user has 0–5 orders)

orders: {
  countPerParent: { ref: 'users', min: 0, max: 5 },
  idPrefix: 'ord',
  fields: { orderedAt: 'date.recent' },
  relations: {
    userId: { ref: 'users', linkedToParent: true },
  },
},

Export Formats

Export generated data to common formats for seeding a real database:

import { generate, exportAs } from 'linked-faker';

const data = generate(schema);

await exportAs(data, 'json', './seed-data.json');
await exportAs(data, 'csv', './seed-data/'); // one CSV file per entity
await exportAs(data, 'sql', './seed.sql', {
  dialect: 'postgres', // or 'mysql', 'sqlite'
});
Format Output
json Single JSON file, keyed by entity
csv One .csv file per entity in a target folder
sql INSERT INTO ... statements, dialect-aware

Recipes

Reproducible datasets
const data = generate(schema, { seed: 42 });

Same schema + same seed → same output every run. Different seeds produce different datasets.

Validation
const result = generate(schema, { seed: 42, validate: true });

console.log(result.valid);       // true
console.log(result.validation); // []
console.log(result.data);       // generated dataset
Seeding a database manually

Use the generated arrays directly with your ORM or query builder:

const data = generate(schema);

await db.insert(usersTable).values(data.users);
await db.insert(productsTable).values(data.products);
await db.insert(ordersTable).values(data.orders);
Multi-level relationships
const schema = defineSchema({
  categories: {
    count: 5,
    idPrefix: 'cat',
    fields: { name: 'commerce.department' },
  },
  products: {
    count: 30,
    idPrefix: 'prd',
    fields: { name: 'commerce.productName' },
    relations: { categoryId: { ref: 'categories' } },
  },
  orders: {
    count: 100,
    idPrefix: 'ord',
    relations: {
      productIds: { ref: 'products', many: true, min: 1, max: 3 },
    },
  },
});

Roadmap

See VERSIONS.md for the full version plan (v1, v2, v3).

Upcoming highlights:

  • CLI: npx linked-faker generate schema.json --out ./seed
  • Self-referencing relations (e.g. Employee.managerId → Employee)
  • TypeScript type inference from schema
  • Plugin system for custom field-generator libraries
  • Web-based schema builder UI

How does it decide generation order? It builds a dependency graph from your relations and countPerParent config, then generates entities in topological order. Declare entities in any order in your schema.

License

MIT

Keywords