Replies: 2 comments 1 reply
-
Hey, @mdbiscan. Thanks for proposing this. The seeding functionality has long been on my todo list, and I even gave it some attempts in #33 in the past. TLDR I agree, it's not easy due to the relationships and the safe amount of implicit behaviors one would expect when seeding their models. I will keep your utilities and the proposed API in mind when I come back to this discussion. For now, it's not on my radar. |
Beta Was this translation helpful? Give feedback.
1 reply
-
I'm posting my seed file here to show a real world example on how I'm using it. const db = require('./factories');
const columns = require('./columns');
const elements = require('./elements');
const fixtures = require('./fixtures');
const Seed = require('./seed');
const { faker } = require('@faker-js/faker');
const { transactionPrice } = require('../utils/calculate');
// Seeding with predetermined values
faker.seed(123);
// Seeds
const seed = new Seed(db);
Object.keys(columns).forEach(Name => {
seed.one('Column', {
Name,
All: columns[Name].All,
Selected: columns[Name].Selected,
});
});
elements.Permissions.forEach(Permission => seed.one('Permission', Permission));
elements.PlatformTypes.forEach(PlatformType =>
seed.one('PlatformType', PlatformType)
);
elements.Bases.forEach(Base => seed.one('UnderlyingBase', Base));
elements.Quotes.forEach(Quote => seed.one('UnderlyingQuote', Quote));
const USA = fixtures.Countries.find(Country => Country.Code === 'US');
const Canada = fixtures.Countries.find(Country => Country.Code === 'CA');
elements.Products.forEach(({ Description, Live, Symbol, Underlying }) => {
const Base = db.UnderlyingBase.findFirst({
where: {
Symbol: {
equals: Underlying.Base,
},
},
});
const Quote = db.UnderlyingQuote.findFirst({
where: {
Symbol: {
equals: Underlying.Quote,
},
},
});
seed.one('Product', {
Base,
Description,
Live,
Quote,
Symbol,
});
});
const SuperOperator = seed.one('ComplianceOperator', {
Name: 'Super Operator',
});
seed.many('ComplianceOperator', 10);
const SuperGroup = seed.one('Group', {
Name: 'Super Group',
Permissions: db.Permission.getAll(),
PhoneNumber: seed.one('PhoneNumber'),
Address: seed.one('Address'),
ComplianceOperator: SuperOperator,
GroupCommissions: seed.many('GroupCommission', 1),
CommissionEmails: seed.many('CommissionEmail', 1),
ACHEmails: seed.many('ACHEmail', 1),
});
const DevsGroup = seed.one('Group', {
Name: 'Devs',
Permissions: db.Permission.getAll(),
PhoneNumber: seed.one('PhoneNumber'),
Address: seed.one('Address'),
ComplianceOperator: SuperOperator,
GroupCommissions: seed.many('GroupCommission', 1),
CommissionEmails: seed.many('CommissionEmail', 1),
ACHEmails: seed.many('ACHEmail', 1),
Parent: SuperGroup,
});
const AccountingGroup = seed.one('Group', {
Name: 'Accounting',
Permissions: db.Permission.getAll().filter(({ Key }) =>
Key.includes('accounting')
),
PhoneNumber: seed.one('PhoneNumber'),
Address: seed.one('Address'),
ComplianceOperator: SuperOperator,
GroupCommissions: seed.many('GroupCommission', 1),
CommissionEmails: seed.many('CommissionEmail', 1),
ACHEmails: seed.many('ACHEmail', 1),
Parent: SuperGroup,
});
const ReadOnlyGroup = seed.one('Group', {
Name: 'ReadOnly',
Permissions: db.Permission.getAll().filter(({ Key }) => Key.includes('view')),
PhoneNumber: seed.one('PhoneNumber'),
Address: seed.one('Address'),
ComplianceOperator: seed.one('ComplianceOperator'),
GroupCommissions: seed.many('GroupCommission', 1),
CommissionEmails: seed.many('CommissionEmail', 1),
ACHEmails: seed.many('ACHEmail', 1),
Parent: SuperGroup,
});
const SuperPhoneNumbers = seed.many('PhoneNumber', 1, { Phone: '312444555' });
seed.one('Account', {
Email: '[email protected]',
FirstName: 'Super',
LastName: 'User',
FullName: 'User, Super',
Employer: 'DigitalMint',
PhoneNumbers: SuperPhoneNumbers,
PreferredPhoneNumber: SuperPhoneNumbers[0],
Addresses: seed.many('Address', 1),
ApprovalTier: 3,
Status: 12,
ComplianceOperator: SuperOperator,
OperatingCountry: USA,
Groups: [DevsGroup, AccountingGroup, SuperGroup],
});
const ReadOnlyPhoneNumbers = seed.many('PhoneNumber', 1, {
Phone: '773444555',
});
seed.one('Account', {
Email: '[email protected]',
FirstName: 'Read',
LastName: 'Only',
FullName: 'Only, Read',
Employer: 'DigitalMint',
PhoneNumbers: ReadOnlyPhoneNumbers,
PreferredPhoneNumber: ReadOnlyPhoneNumbers[0],
Addresses: seed.many('Address', 1),
ApprovalTier: 1,
Status: 10,
ComplianceOperator: SuperOperator,
OperatingCountry: USA,
Groups: [ReadOnlyGroup],
});
const Accounts = [];
seed.collect(154, Accounts, () => {
// Customer Tier 1
return {
Addresses: seed.many('Address', 1),
PhoneNumbers: seed.many('PhoneNumber', 1),
AccountTier: 1,
Status: 1,
};
});
seed.collect(36, Accounts, () => {
// Customer Tier 2
return {
Addresses: seed.many('Address', 1),
PhoneNumbers: seed.many('PhoneNumber', 1),
AccountTier: 2,
Status: 2,
};
});
seed.collect(19, Accounts, () => {
// Customer Tier 3
return {
Addresses: seed.many('Address', 1),
PhoneNumbers: seed.many('PhoneNumber', 1),
AccountTier: 3,
Status: 3,
};
});
seed.collect(21, Accounts, () => {
// Banned
return {
Addresses: seed.many('Address', 1),
PhoneNumbers: seed.many('PhoneNumber', 1),
ApprovalTier: 0,
Status: 11,
Banned: true,
};
});
seed.collect(43, Accounts, () => {
// Employees
return {
Addresses: seed.many('Address', 1),
PhoneNumbers: seed.many('PhoneNumber', 1),
Employer: 'DigitalMint',
ApprovalTier: 3,
Status: 12,
Banned: true,
Groups: [DevsGroup],
};
});
seed.collect(14, Accounts, () => {
// Accounting
return {
Addresses: seed.many('Address', 1),
PhoneNumbers: seed.many('PhoneNumber', 1),
Employer: 'DigitalMint',
ApprovalTier: 3,
Status: 3,
Groups: [AccountingGroup],
};
});
seed.collect(22, Accounts, () => {
// Service
return {
Addresses: seed.many('Address', 1),
PhoneNumbers: seed.many('PhoneNumber', 1),
ApprovalTier: 0,
Status: 10,
Banned: true,
Groups: [ReadOnlyGroup],
};
});
seed.shuffle('Account', Accounts, ({ PhoneNumbers, LastName, FirstName }) => {
return {
PreferredPhoneNumber: PhoneNumbers[0],
FullName: `${LastName}, ${FirstName}`,
};
});
seed.one('Profile', {
FirstName: 'Super',
LastName: 'User',
PhoneNumber: '7734445555',
PIN: '1234',
Address: () => seed.one('Address'),
});
seed.many('Profile', 10, {
Address: () => seed.one('Address'),
});
seed.many('Address', 3, { Active: false });
const LocationGroup = seed.one('Group', {
Name: 'Locations',
Permissions: db.Permission.getAll().filter(({ Key }) => Key.includes('view')),
PhoneNumber: seed.one('PhoneNumber'),
Address: seed.one('Address'),
ComplianceOperator: faker.helpers.arrayElement(
db.ComplianceOperator.getAll()
),
GroupCommissions: seed.many('GroupCommission', 1),
CommissionEmails: seed.many('CommissionEmail', 1),
ACHEmails: seed.many('ACHEmail', 1),
});
const LocationCreate = (fields = {}) => {
const Group = seed.one('Group', {
Permissions: db.Permission.getAll().filter(({ Key }) =>
Key.includes('view')
),
PhoneNumber: seed.one('PhoneNumber'),
Address: seed.one('Address'),
ComplianceOperator: faker.helpers.arrayElement(
db.ComplianceOperator.getAll()
),
GroupCommissions: seed.many('GroupCommission', 1),
CommissionEmails: seed.many('CommissionEmail', 1),
ACHEmails: seed.many('ACHEmail', 1),
Parent: LocationGroup,
});
const PlatformType = faker.helpers.arrayElement(db.PlatformType.getAll());
return {
Address: seed.one('Address'),
CreditAccount: seed.one('CreditAccount'),
ComplianceOperator: seed.one('ComplianceOperator'),
DebitAccount: seed.one('DebitAccount'),
CashCourier: seed.one('CashCourier'),
PlatformTypes: [PlatformType],
PlatformType: PlatformType.Name,
Group,
CashOperatingGroup: Group,
...fields,
};
};
const Locations = [];
seed.collect(87, Locations, LocationCreate);
seed.collect(32, Locations, () =>
// Inactive
LocationCreate({
Active: false,
})
);
seed.collect(29, Locations, () =>
// Decommissioned
LocationCreate({
Active: false,
Decommissioned: true,
})
);
seed.shuffle('Location', Locations);
seed.many('Platform', 140, {
Group: () => faker.helpers.arrayElement(db.Group.getAll()),
PlatformType: () => faker.helpers.arrayElement(db.PlatformType.getAll()),
Location: () =>
faker.helpers.arrayElement(
db.Location.getAll().filter(({ Decommissioned }) => !Decommissioned)
),
});
const TransactionAccounts = db.Account.findMany({
where: {
Status: {
between: [1, 3],
},
},
});
const Transactions = seed.many(
'Transaction',
261,
{
ComplianceOperator: () =>
faker.helpers.arrayElement(db.ComplianceOperator.getAll()),
Group: () => faker.helpers.arrayElement(db.Group.getAll()),
},
() => {
const Account = faker.helpers.arrayElement(TransactionAccounts);
const Event = faker.helpers.arrayElement(elements.Events);
const Platform = faker.helpers.arrayElement(db.Platform.getAll());
const State = faker.helpers.arrayElement(elements.States);
const Product = db.Product.findFirst({
where: {
Symbol: {
equals: Platform.Products,
},
},
});
const Price = transactionPrice(State.StateDesc === 'Settled');
return {
Account,
Base: Product.Base,
Location: Platform.Location,
Platform,
Product,
Quote: Product.Quote,
...Price,
...Event,
...State,
};
}
); |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I'm using this package not in msw, but other mocking environments. I love it, but its missing a few pieces that I think would be really helpful, such as seeding and
afterCreate
methods for updating fields after model creation that are dependent on others.Seeding
One in particular is easy seeding methods. I came from using Mirage for years, and I loved the ability to create lists on the fly, but the hard part can be the associations. I built out a little class for myself to be able to seed quickly.
Only other thing missing is a method after fields are written to update programmatically. I wrote up something here #272
EDIT: Updated the class with some new functions
Examples:
Db objects get returned in the order of creation, but I found sometimes randomized data with faker isn't enough to make the data feel real. For example, I might need a small percentage of inactive accounts vs a larger percentage of active accounts to look and feel more realistic in my system. Since the db returns objects the order of creation, it would look funny to see all the inactive accounts at the end of a list.
After Create
EDIT - I closed #273 for now, since it's discussed in here with seeding.
Beta Was this translation helpful? Give feedback.
All reactions