UNPKG

keystone-seeder

Version:
352 lines (351 loc) 19.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateFieldValue = generateFieldValue; exports.handleRelationField = handleRelationField; exports.buildSeedData = buildSeedData; const faker_1 = require("@faker-js/faker"); // Entity context for maintaining consistency between related fields class EntityContext { constructor() { this.gender = faker_1.fakerES_MX.person.sex(); this.firstName = faker_1.fakerES_MX.person.firstName(this.gender.toLowerCase()); this.lastName = faker_1.fakerES_MX.person.lastName(); this.username = faker_1.fakerES_MX.internet.username({ firstName: this.firstName, lastName: this.lastName }); this.email = faker_1.fakerES_MX.internet.email({ firstName: this.firstName, lastName: this.lastName }); this.avatar = faker_1.fakerES_MX.image.avatar(); this.company = faker_1.fakerES_MX.company.name(); this.jobTitle = faker_1.fakerES_MX.person.jobTitle(); this.phoneNumber = faker_1.fakerES_MX.phone.number(); this.address = faker_1.fakerES_MX.location.streetAddress(); this.city = faker_1.fakerES_MX.location.city(); this.state = faker_1.fakerES_MX.location.state(); this.zipCode = faker_1.fakerES_MX.location.zipCode(); this.country = faker_1.fakerES_MX.location.countryCode({ variant: "alpha-3" }).toLowerCase(); this.birthDate = faker_1.fakerES_MX.date.birthdate({ min: 18, max: 65, mode: 'age' }); } getFirstName() { return this.firstName; } getLastName() { return this.lastName; } getFullName() { return `${this.firstName} ${this.lastName}`; } getUsername() { return this.username; } getEmail() { return this.email; } getGender() { return this.gender; } getAvatar() { return this.avatar; } getCompany() { return this.company; } getJobTitle() { return this.jobTitle; } getPhoneNumber() { return this.phoneNumber; } getAddress() { return this.address; } getCity() { return this.city; } getState() { return this.state; } getZipCode() { return this.zipCode; } getCountry() { return this.country; } getBirthDate() { return this.birthDate; } getAge() { return new Date().getFullYear() - this.birthDate.getFullYear(); } } const stringFieldPatterns = { fullname: (_, context) => context ? context.getFullName() : `${faker_1.fakerES_MX.person.firstName()} ${faker_1.fakerES_MX.person.lastName()}`, firstname: (_, context) => context ? context.getFirstName() : faker_1.fakerES_MX.person.firstName(), lastname: (_, context) => context ? context.getLastName() : faker_1.fakerES_MX.person.lastName(), username: (_, context) => context ? context.getUsername() : faker_1.fakerES_MX.internet.username(), name: (modelName, context) => { const sanitizedModelName = modelName.toLowerCase(); if (sanitizedModelName.includes("product")) return faker_1.fakerES_MX.commerce.productName(); if (sanitizedModelName.includes("event")) return faker_1.fakerES_MX.lorem.words(3); if (sanitizedModelName.includes("company")) return faker_1.fakerES_MX.company.name(); if (sanitizedModelName.includes("job")) return faker_1.fakerES_MX.person.jobTitle(); if (sanitizedModelName.includes("course")) return faker_1.fakerES_MX.lorem.words(2) + " Course"; if (sanitizedModelName.includes("category")) return faker_1.fakerES_MX.commerce.department(); if (sanitizedModelName.includes("blog") || sanitizedModelName.includes("post") || sanitizedModelName.includes("article")) return faker_1.fakerES_MX.lorem.sentence(5); return context ? context.getFirstName() : faker_1.fakerES_MX.person.firstName(); }, email: (_, context) => context ? context.getEmail() : faker_1.fakerES_MX.internet.email(), gender: (_, context) => context ? context.getGender() : faker_1.fakerES_MX.person.sex(), password: () => faker_1.fakerES_MX.internet.password({ length: 12, memorable: true }), phone: (_, context) => context ? context.getPhoneNumber() : faker_1.fakerES_MX.phone.number(), phonenumber: (_, context) => context ? context.getPhoneNumber() : faker_1.fakerES_MX.phone.number(), mobile: (_, context) => context ? context.getPhoneNumber() : faker_1.fakerES_MX.phone.number(), address: (_, context) => context ? context.getAddress() : faker_1.fakerES_MX.location.streetAddress(), street: (_, context) => context ? context.getAddress() : faker_1.fakerES_MX.location.street(), city: (_, context) => context ? context.getCity() : faker_1.fakerES_MX.location.city(), state: (_, context) => context ? context.getState() : faker_1.fakerES_MX.location.state(), zipcode: (_, context) => context ? context.getZipCode() : faker_1.fakerES_MX.location.zipCode(), postalcode: (_, context) => context ? context.getZipCode() : faker_1.fakerES_MX.location.zipCode(), country: (_, context) => context ? context.getCountry() : faker_1.fakerES_MX.location.countryCode({ variant: "alpha-3" }).toLowerCase(), company: (_, context) => context ? context.getCompany() : faker_1.fakerES_MX.company.name(), jobtitle: (_, context) => context ? context.getJobTitle() : faker_1.fakerES_MX.person.jobTitle(), title: (modelName) => { const sanitizedModelName = modelName.toLowerCase(); if (sanitizedModelName.includes("product")) return faker_1.fakerES_MX.commerce.productName(); if (sanitizedModelName.includes("job")) return faker_1.fakerES_MX.person.jobTitle(); if (sanitizedModelName.includes("post") || sanitizedModelName.includes("article") || sanitizedModelName.includes("blog")) return faker_1.fakerES_MX.lorem.sentence(); return faker_1.fakerES_MX.lorem.words(3); }, description: (modelName) => { const sanitizedModelName = modelName.toLowerCase(); if (sanitizedModelName.includes("product")) return faker_1.fakerES_MX.commerce.productDescription(); if (sanitizedModelName.includes("user") || sanitizedModelName.includes("person")) return faker_1.fakerES_MX.lorem.sentence(8); return faker_1.fakerES_MX.lorem.paragraph(); }, content: () => faker_1.fakerES_MX.lorem.paragraphs(3), summary: () => faker_1.fakerES_MX.lorem.paragraph(), bio: () => faker_1.fakerES_MX.lorem.paragraph(2), avatar: (_, context) => context ? context.getAvatar() : faker_1.fakerES_MX.image.avatar(), image: (modelName) => { const sanitizedModelName = modelName.toLowerCase(); if (sanitizedModelName.includes("avatar") || sanitizedModelName.includes("profile")) return faker_1.fakerES_MX.image.avatar(); return faker_1.fakerES_MX.image.url(); }, url: () => faker_1.fakerES_MX.internet.url(), website: () => faker_1.fakerES_MX.internet.url(), date: () => faker_1.fakerES_MX.date.recent().toISOString(), birthdate: (_, context) => context ? context.getBirthDate().toISOString() : faker_1.fakerES_MX.date.birthdate({ min: 18, max: 65, mode: 'age' }).toISOString(), birthday: (_, context) => context ? context.getBirthDate().toISOString() : faker_1.fakerES_MX.date.birthdate({ min: 18, max: 65, mode: 'age' }).toISOString(), age: (_, context) => context ? context.getAge().toString() : faker_1.fakerES_MX.number.int({ min: 18, max: 65 }).toString(), sku: () => faker_1.fakerES_MX.commerce.isbn({ separator: "" }), isbn: () => faker_1.fakerES_MX.commerce.isbn(), price: () => faker_1.fakerES_MX.commerce.price().toString(), cost: () => faker_1.fakerES_MX.commerce.price().toString(), currency: () => faker_1.fakerES_MX.finance.currencyCode(), color: () => faker_1.fakerES_MX.color.human(), hex: () => faker_1.fakerES_MX.color.rgb(), rgb: () => faker_1.fakerES_MX.color.rgb(), department: () => faker_1.fakerES_MX.commerce.department(), category: () => faker_1.fakerES_MX.commerce.department(), tag: () => faker_1.fakerES_MX.lorem.word(), tags: () => faker_1.fakerES_MX.lorem.words(3), status: (modelName) => { const statuses = ["active", "inactive", "pending", "completed", "cancelled"]; if (modelName.toLowerCase().includes("order")) { return faker_1.fakerES_MX.helpers.arrayElement(["pending", "processing", "shipped", "delivered", "cancelled"]); } return faker_1.fakerES_MX.helpers.arrayElement(statuses); }, role: () => faker_1.fakerES_MX.helpers.arrayElement(["user", "admin", "editor", "viewer"]), permission: () => faker_1.fakerES_MX.helpers.arrayElement(["read", "write", "admin"]), language: () => faker_1.fakerES_MX.helpers.arrayElement(["en", "es", "fr", "de", "it"]), locale: () => faker_1.fakerES_MX.helpers.arrayElement(["en-US", "es-ES", "fr-FR", "de-DE", "it-IT"]), timezone: () => faker_1.fakerES_MX.location.timeZone(), uuid: () => faker_1.fakerES_MX.string.uuid(), ip: () => faker_1.fakerES_MX.internet.ip(), mac: () => faker_1.fakerES_MX.internet.mac(), domain: () => faker_1.fakerES_MX.internet.domainName(), useragent: () => faker_1.fakerES_MX.internet.userAgent(), token: () => faker_1.fakerES_MX.string.alphanumeric(32), default: () => faker_1.fakerES_MX.lorem.words(3) }; const typeHandlers = { String: (fieldName, modelName, context) => { const pattern = Object.keys(stringFieldPatterns).find(pattern => fieldName.includes(pattern)); return pattern ? stringFieldPatterns[pattern](modelName, context) : stringFieldPatterns.default(modelName); }, Int: (fieldName, modelName) => { const sanitizedFieldName = fieldName.toLowerCase(); const sanitizedModelName = modelName.toLowerCase(); if (sanitizedFieldName.includes("age")) return faker_1.fakerES_MX.number.int({ min: 18, max: 65 }); if (sanitizedFieldName.includes("year")) return faker_1.fakerES_MX.number.int({ min: 2000, max: 2023 }); if (sanitizedFieldName.includes("step")) return faker_1.fakerES_MX.number.int({ min: 1, max: 20 }); if (sanitizedFieldName.includes("count") || sanitizedFieldName.includes("quantity")) return faker_1.fakerES_MX.number.int({ min: 1, max: 100 }); if (sanitizedFieldName.includes("rating") || sanitizedFieldName.includes("score")) return faker_1.fakerES_MX.number.int({ min: 1, max: 5 }); if (sanitizedFieldName.includes("price") || sanitizedFieldName.includes("cost")) return faker_1.fakerES_MX.number.int({ min: 5, max: 500 }); if (sanitizedFieldName.includes("discount") || sanitizedFieldName.includes("percentage")) return faker_1.fakerES_MX.number.int({ min: 5, max: 30 }); if (sanitizedModelName.includes("order") && sanitizedFieldName.includes("total")) return faker_1.fakerES_MX.number.int({ min: 10, max: 1000 }); return faker_1.fakerES_MX.number.int({ min: 1, max: 1000 }); }, Float: (fieldName) => { const sanitizedFieldName = fieldName.toLowerCase(); if (sanitizedFieldName.includes("price") || sanitizedFieldName.includes("cost")) return faker_1.fakerES_MX.number.float({ min: 5, max: 500, fractionDigits: 2 }); if (sanitizedFieldName.includes("rating") || sanitizedFieldName.includes("score")) return faker_1.fakerES_MX.number.float({ min: 1, max: 5, fractionDigits: 1 }); if (sanitizedFieldName.includes("discount") || sanitizedFieldName.includes("percentage")) return faker_1.fakerES_MX.number.float({ min: 0.05, max: 0.3, fractionDigits: 2 }); if (sanitizedFieldName.includes("weight")) return faker_1.fakerES_MX.number.float({ min: 0.1, max: 10, fractionDigits: 1 }); if (sanitizedFieldName.includes("height") || sanitizedFieldName.includes("width") || sanitizedFieldName.includes("length")) { return faker_1.fakerES_MX.number.float({ min: 1, max: 100, fractionDigits: 1 }); } return faker_1.fakerES_MX.number.float({ min: 1, max: 1000, fractionDigits: 2 }); }, Boolean: (fieldName) => { const sanitizedFieldName = fieldName.toLowerCase(); if (sanitizedFieldName.includes("active") || sanitizedFieldName.includes("enabled") || sanitizedFieldName.includes("available")) { return true; } if (sanitizedFieldName.includes("deleted") || sanitizedFieldName.includes("archived") || sanitizedFieldName.includes("disabled")) { return false; } if (sanitizedFieldName.includes("featured") || sanitizedFieldName.includes("premium")) { return faker_1.fakerES_MX.datatype.boolean({ probability: 0.3 }); // 30% chance of being true } if (sanitizedFieldName.includes("verified") || sanitizedFieldName.includes("confirmed")) { return faker_1.fakerES_MX.datatype.boolean({ probability: 0.8 }); // 80% chance of being true } return faker_1.fakerES_MX.datatype.boolean(); }, DateTime: (fieldName) => { const sanitizedFieldName = fieldName.toLowerCase(); if (sanitizedFieldName.includes("created") || sanitizedFieldName.includes("createdAt")) { return faker_1.fakerES_MX.date.recent({ days: 30 }); } if (sanitizedFieldName.includes("updated") || sanitizedFieldName.includes("updatedAt")) { return faker_1.fakerES_MX.date.recent({ days: 7 }); } if (sanitizedFieldName.includes("birth") || sanitizedFieldName.includes("dob")) { return faker_1.fakerES_MX.date.birthdate({ min: 18, max: 65, mode: 'age' }); } if (sanitizedFieldName.includes("expiry") || sanitizedFieldName.includes("expiration")) { return faker_1.fakerES_MX.date.future({ years: 2 }); } if (sanitizedFieldName.includes("start")) { return faker_1.fakerES_MX.date.past({ years: 1 }); } if (sanitizedFieldName.includes("end") || sanitizedFieldName.includes("deadline")) { return faker_1.fakerES_MX.date.future({ years: 1 }); } return faker_1.fakerES_MX.date.recent(); }, default: () => null }; /** * Generate a value for a field based on its type and name */ function generateFieldValue(field, modelName, context) { const fieldName = field.name.toLowerCase(); const handler = typeHandlers[field.type] || typeHandlers.default; return handler(fieldName, modelName, context); } /** * Build seed data for a model based on its fields and metadata */ /** * Get related entities for a relation field */ async function getRelatedEntities(context, relatedModel) { try { // Query the database to get all entities of the related model const entities = await context.sudo().db[relatedModel].findMany({ take: 100, // Limit to 100 records for performance }); return entities; } catch (error) { console.error(`Error fetching related entities for ${relatedModel}:`, error); return []; } } /** * Handle relation field by selecting a related entity */ const interactive_prompts_1 = require("./interactive-prompts"); async function handleRelationField(context, field, relationMode) { try { // Get the related model name from the field const relatedModel = field.type; const fieldName = field.name; // Get all available entities of the related model const relatedEntities = await getRelatedEntities(context, relatedModel); if (relatedEntities.length === 0) { console.warn(`No ${relatedModel} entities found for relation. Skipping relation field.`); return null; } // If connect-one mode, always use the first entity if (relationMode === 'connect-one' && relatedEntities.length > 0) { return { connect: { id: relatedEntities[0].id } }; } // If interactive mode, prompt user to select entities if (relationMode === 'interactive') { if (field.isList) { const selectedEntities = await (0, interactive_prompts_1.selectMultipleEntities)(fieldName, relatedModel, relatedEntities); return selectedEntities ? { connect: selectedEntities } : null; } else { const selectedEntity = await (0, interactive_prompts_1.selectSingleEntity)(fieldName, relatedModel, relatedEntities); return selectedEntity ? { connect: selectedEntity } : null; } } // Otherwise, randomly select an entity const randomEntity = faker_1.fakerES_MX.helpers.arrayElement(relatedEntities); return { connect: { id: randomEntity.id } }; } catch (error) { console.error(`Error handling relation field:`, error); return null; } } function buildSeedData(model, fieldsMeta, context, relationMode) { const data = {}; try { // Get non-relation required fields const regularFields = model.fields.filter((field) => field.isRequired && !field.isGenerated && !field.isId && !field.relationName); // Get relation fields (if relation mode is specified) const relationFields = relationMode ? model.fields.filter((field) => field.isRequired && field.relationName && !field.isId && !field.name.startsWith('from')) : []; // Create entity context if the model appears to be person-related const modelNameLower = model.name.toLowerCase(); const isPersonModel = modelNameLower.includes('user') || modelNameLower.includes('person') || modelNameLower.includes('employee') || modelNameLower.includes('customer'); const entityContext = isPersonModel ? new EntityContext() : undefined; // Process regular fields for (const field of regularFields) { const fieldName = field.name; const fieldMeta = fieldsMeta[fieldName]; if (fieldMeta?.options) { // Handle select fields with options const options = fieldMeta.options; // Check if 'published' exists in options const publishedOption = options.find((opt) => opt.value === "published"); if (publishedOption) { data[field.name] = "published"; } else if (fieldMeta?.defaultValue !== undefined) { // Use defaultValue if available data[field.name] = fieldMeta.defaultValue; } else { data[field.name] = faker_1.fakerES_MX.helpers.arrayElement(options).value; } } else { data[field.name] = generateFieldValue(field, model.name, entityContext); } } // Process relation fields if relation mode is specified if (relationMode && context) { // We'll handle relation fields asynchronously later in the seed function data._relationFields = relationFields.map((field) => ({ fieldName: field.name, relatedModel: field.type, isList: field.isList })); } return data; } catch (error) { console.error("Error building seed data:", error); throw error; } }