Source

client/core/db/faker.js

/**
 * 
 * ## Mockup tool to feed a database with fake random values
 * 
 * - The fake value is generated according to the field **label** property.
 * - A few common fields are recognized automatically
 * - If the **label** is undefined or not recognized, it tries to look at the field **type** property instead (text, number, date)
 * 
 * Recognized field labels are:
 * - name
 * - first name
 * - last name
 * - full name
 * - company name
 * - department
 * - email
 * - phone
 * - address
 * - address 1
 * - address 2
 * - zip code
 * - city
 * - country
 * - title
 * - description
 * - priority
 * - status
 * 
 * The fake values are generated one field at a time, so, to feed a complete record, you must loop over its list of fields.
 * ```
 * const userRecord = {}
 * userModel.getFields().forEach(field => userRecord[field.id] = kiss.db.faker(field))
 * ```
 * 
 * @namespace
 * @param {object|string} field - An object defining a label and a type | A simple string for the label ("First name") or the type ("number")
 * 
 * @example
 * kiss.db.faker({label: "First name"}) can return "Julia"
 * kiss.db.faker("First name") can return "Julia"
 * kiss.db.faker({label: "Full name"}) can return "Julia Giordini"
 * kiss.db.faker({label: "Amount", type: "number"}) can return 123
 * kiss.db.faker({label: "Workload", type: "float", min: 0, max: 100, precision: 2}) can return 42.42
 * kiss.db.faker({label: "Invoice date", type: "date", year: 2020}) can return "2020-05-27"
 * kiss.db.faker("date") can return "1984-05-31"
 * kiss.db.faker("priority") can return "high"
 * kiss.db.faker("status") can return "in progress"
 */
kiss.db.faker = function (field) {
	// Don't generate values for these special items
	if (["block", "panel", "link", "lookup", "summary", "attachment", "aiImage", "password", "selectViewColumn", "selectViewColumns"].indexOf(field.type) != -1) return null

	let sourceArray = []

	// Accept objects like {label: "First name", type: "text"} or simple strings like "First name"
	let mockupName = (typeof field === "object") ? field.label.toLowerCase() : field.toLowerCase()

	switch (mockupName) {
	/**
	 * Generate *GENERIC* data according to field types
	 */
	case "text":
		sourceArray = kiss.db.faker.text

		if (field.validationType == "url") return "https://airprocess.com"
		if (field.validationType == "email") return kiss.db.faker("email")
		if (field.value == "unid") return kiss.tools.shortUid().toUpperCase()
		return sourceArray[Math.floor(Math.random() * sourceArray.length)]

	case "textarea":
	case "aitextarea":
	case "richtextfield":
		return kiss.db.faker("description")

	case "select":
		// Time field is a select with custom options
		if (field.template == "time") return ("0" + Math.round(Math.random() * 23)).slice(-2) + ":00"

		if (field.options) {
			sourceArray = field.options.map(option => option.value)
			return sourceArray[Math.floor(Math.random() * sourceArray.length)]
		}
		return ["A", "B", "C"]

	case "checkbox":
		let value = Math.random() * 100
		return (value > 50)

	case "date":
		let year = field.year || (1980 + Math.floor(Math.random() * 45))
		let month = field.month || (1 + Math.floor(Math.random() * 12))
		let day = field.day || (1 + Math.floor(Math.random() * 28))
		let date = year.toString() + "-" + ("0" + month.toString()).slice(-2) + "-" + ("0" + day.toString()).slice(-2)
		return date

	case "integer":
		return Math.floor(kiss.db.faker(Object.assign({}, field, {
			label: "float",
			precision: 0
		})))

	case "number":
	case "float":
		let min = field.min || 0
		let max = field.max || 100
		let precision = (field.precision === 0) ? 0 : 2
		let val = (min + Math.random() * (max - min)).toFixed(precision)
		if (mockupName == "number") return Math.floor(val)
		return val

	case "slider":
		return Math.floor((Math.random() * 100).toFixed(0))

	case "rating":
		let minRate = field.min || 0
		let maxRate = field.max || 10
		let rate = (minRate + Math.random() * (maxRate - minRate)).toFixed(0)
		return Math.floor(rate)
        
	case "directory":
		return kiss.session.getUserId()

	case "color":
	case "colorpicker":
		return "#" + kiss.global.palette[Math.round(Math.random() * 59)]

	case "icon":
	case "iconpicker":
		return kiss.webfonts.all[Math.round(Math.random() * 1040)]

	case "mapfield":
		return "-20.992914, 55.389535" // Enjoy!

		/**
		 * Generate *SPECIFIC* data according to field ids
		 */
	case "username":
	case "fullname":
	case "full name":
	case "nom complet":
	case "utilisateur":
		return kiss.db.faker({
			label: "first name"
		}) + " " + kiss.db.faker({
			label: "last name"
		})

	case "prénom":
		return kiss.db.faker({
			label: "first name"
		})

	case "nom":
		return kiss.db.faker({
			label: "last name"
		})

	case "email":
		return (kiss.db.faker({
			label: "first name"
		}) + "." + kiss.db.faker({
			label: "last name"
		}) + "@" + kiss.db.faker({
			label: "company name"
		}).toLowerCase() + "." + kiss.db.faker({
			label: "domain"
		})).toLowerCase()

	case "phone":
	case "mobile":
	case "mobile phone":
	case "téléphone":
	case "telephone":
		return kiss.db.faker({
			label: "integer",
			min: 1000000000,
			max: 9900000000
		})

	case "company":
	case "société":
		return kiss.db.faker({
			label: "company name"
		})

	case "address":
	case "adresse":
		return kiss.db.faker({
			label: "address 1"
		}) +
                ", " + kiss.db.faker({
			label: "address 2"
		}) +
                ", " + kiss.db.faker({
			label: "zip code"
		}) +
                ", " + kiss.db.faker({
			label: "city"
		}) +
                ", " + kiss.db.faker({
			label: "country"
		})

	case "address 1":
	case "addresse 1":
		return kiss.db.faker({
			label: "company name"
		}) + " building"

	case "address 2":
	case "addresse 2":
		return kiss.db.faker({
			label: "integer",
			min: 1
		}) + " " + kiss.db.faker({
			label: "last name"
		}) + " " + kiss.db.faker({
			label: "street"
		})

	case "zip code":
	case "code postal":
		return kiss.db.faker({
			label: "integer",
			min: 1000,
			max: 90000
		})

	case "description":
		return "Lorem ipsum dolor sit amet. Vel animi quia aut deserunt quos qui quia quaerat ut internos ipsa."

		// !Funny text disabled
		// return "This is a " + kiss.db.faker({
		//         label: "description.adjectives"
		//     }) +
		//     " " + kiss.db.faker({
		//         label: "description.starts"
		//     }) +
		//     " about a " + kiss.db.faker({
		//         label: "description.adjectives"
		//     }) +
		//     " " + kiss.db.faker({
		//         label: "description.subjects"
		//     }) +
		//     " who " + kiss.db.faker({
		//         label: "description.auxiliaries"
		//     }) +
		//     " " + kiss.db.faker({
		//         label: "description.adverbs"
		//     }) +
		//     " " + kiss.db.faker({
		//         label: "description.verbs"
		//     }) +
		//     " a " + kiss.db.faker({
		//         label: "description.subjects"
		//     }) +
		//     ", which " + kiss.db.faker({
		//         label: "description.ends"
		//     }) + "."

	case "title":
	case "titre":
		return kiss.db.faker({
			label: "description.adjectives"
		}).toTitleCase() +
                " " + kiss.db.faker({
			label: "description.adjectives"
		}) +
                " " + kiss.db.faker({
			label: "description.subjects"
		})

	default:
		if (typeof field === "object") {
			// Field was passed as a field configuration object

			// If the field is a "description", it's generated using a composition of multiple db.faker elements.
			// Otherwise, we try to get a specific field definition, depending the field label (example: "Last name")
			sourceArray = (field.label.indexOf("description") != -1) ? kiss.db.faker.description[field.label.split(".")[1]] : kiss.db.faker[mockupName]

			// If the field label couldn't be find amongst pre-defined field names, we use the field's type instead (text, number, date, ...)
			if (!sourceArray) {
				return kiss.db.faker(Object.assign({}, field, {
					label: field.type
				}))
			}
		} else {
			// Field was passed as a simple field label
			sourceArray = kiss.db.faker[mockupName]
			if (!sourceArray) return kiss.db.faker("text")
		}

		// If the field label could be find, returns a random value of the source array
		return sourceArray[Math.floor(Math.random() * sourceArray.length)]
	}
}

// Define values to pick from...
kiss.db.faker["priority"] = ["1 - Critical", "2 - High", "3 - Normal", "4 - Low"]
kiss.db.faker["first name"] = ["Mihaela", "Johanna", "Julia", "Christian", "Brigitte", "Erwin", "Maurice", "Lydia", "Adrian", "Lucienne", "John", "Robert", "Bob", "Will", "Stephen", "Pavel", "Robin", "Gad", "Arnold", "Sylvester", "Dolph", "Robbie", "Flavien"]
kiss.db.faker["last name"] = ["Clinciu", "Giordini", "Cvejzek", "Ponzini", "Collat", "Romell", "Lanoix", "Mikevskaia", "Smith", "Dupont", "Romero", "De Rosa", "Wilson", "Smith", "King", "Yurgen", "Lundgren", "Al'Shadar", "Gad'Nayé", "Bouliama", "Legendre"]
kiss.db.faker["department"] = ["Head office", "Sales", "IT", "Support", "Marketing", "Communication", "Accounting", "Back office", "Human resources", "Quality"]
kiss.db.faker["company name"] = ["Google", "Amazon", "Facebook", "Apple", "IBM", "Microsoft", "Sony", "Nintendo", "SpaceX", "Toyota", "Ford", "Ferrari", "Renault", "Epic", "Ubisoft", "Quantic Dream", "Valve", "Stripe", "AirProcess", "Exauce", "The-Data-Box", "Infinity"]
kiss.db.faker["domain"] = ["net", "com", "org", "eu", "fr", "re"]
kiss.db.faker["city"] = ["Paris", "New York", "Tokyo", "London", "Ajaccio", "Saint-Denis", "Sydney", "Marseilles", "Lyon"]
kiss.db.faker["street"] = ["street", "avenue", "boulevard", "road"]
kiss.db.faker["country"] = ["Gaulle", "Germanistan", "Corsica", "Bhukistan", "Wessex", "Africanistan", "Americanistan", "Paradisistan"]
kiss.db.faker["text"] = ["Sample text", "This is an example", "Lorem ipsum"]
kiss.db.faker["description"] = {
	starts: ["example", "story", "book", "example", "use case", "case", "article"],
	adjectives: ["green", "blue", "red", "purple", "big", "small", "giant", "slick", "clever", "stupid", "wonderful", "serious", "shy", "dangerous", "hilarious", "not so serious", "really cool", "strange", "perfect", "moody"],
	subjects: ["man", "woman", "gorilla", "flying saucer", "donkey", "cat", "kiwi", "dog", "mouse", "wolf", "mammoth", "banana", "peanut", "zombie", "monster", "frog", "bird", "chair", "laptop", "planet"],
	auxiliaries: ["can", "can't", "could", "couldn't", "will", "won't", "did", "didn't", "may", "may not", "might", "might not", "shall"],
	verbs: ["talk to", "jump over", "sing with", "eat", "reprogram", "brain-wash", "help", "paint", "study", "invite"],
	adverbs: ["gracefully", "peacefully", "gently", "heavily", "slightly", "deeply", "silently", "carefully", "nicely", "easily", "electronically"],
	ends: ["is funny", "is a bit weird", "doesn't make any sense", "hurts a little bit", "should never happen", "remains to proof", "is nonsense", "might or might not be the truth", "makes me wonder", "invites to meditation"]
}

/**
 * Generate multiple fake records
 * 
 * @param {object[]} fields
 * @param {number} numberOfRecords
 * @returns {object[]} - An array of fake records
 */
kiss.db.faker.generate = function (fields, numberOfRecords) {
	let records = []
	if (numberOfRecords < 1) return records
	
	// Keep only the non-deleted fields
	let activeFields = fields.filter(field => field.deleted != true)

	for (let index = 0; index < numberOfRecords; index++) {
		let newRecord = {}
		activeFields.forEach(field => {
			if (field.primary == true) {
				// Primary fields: get field name + index
				newRecord[field.id] = field.label.toTitleCase() + " " + ("0000" + (index + 1)).slice(-5)
			} else if (field.label.toLowerCase() == "name") {
				// Name fields
				newRecord[field.id] = "Name " + ("0000" + (index + 1)).slice(-5)
			} else {
				// Other fields
				let generatedValue = kiss.db.faker(field)
				if (generatedValue !== "") newRecord[field.id] = generatedValue
			}
		})

		newRecord.id = uid()
		newRecord.isFake = true
		records.push(newRecord)
	}
	return records
}