Closed urosjarc closed 1 year ago
Hi @urosjarc , thanks for opening this issue.
To understand it better, do you want to prepend string values with the property name, or was that just an example?
I would like that faker prepends all string type property values with property name automatically if using randomClassInstance
on some random class.
I suggest adding a configuration option to faker prependWithPropertyName: Boolean
and by default it would be false so that breaking changes will not happen in the next version.
I would create PR myself if I would understand the architecture of this library.
In the CONTRIBUTING it writes only how to add a new provider but I could not see any manuals that could help me to structure PR myself. :sweat: I usually don't want to bother people with my wishes but in this case, I could not do things differently.
If you explain which files I have to look for, I will create PR myself no problem.
PRs are very much welcome, but I can take a look at it myself also if you don't feel like making a PR :) (Not promising a super fast solution though, but I will try to find time this month.) The implementation for random class instance is here - https://github.com/serpro69/kotlin-faker/blob/master/core/src/main/kotlin/io/github/serpro69/kfaker/provider/misc/RandomClassProvider.kt It's not mentioned in the "contributing" because it's a bit "specific", but the file has kdocs which hopefully makes it easier to understand what's what.
Anyways, I can see how something like this can be useful, but I would also like it to be more configurable so to speak. Prepending a property name seems like a very specific use-case. What I envision doing here is to add another function similar to typeGenerator
or namedParameterGenerator
(propertyGenerator
, for example), which would give access to the KProperty
, for example? There you could do something like this:
faker.randomProvider.randomClassInstance<T> {
propertyGenerator<String> { prop ->
"${prop.name}_${faker.random.randomString()}"
}
}
I need to think a bit if this makes sense at all and if so - how to implement it.
Look, now that you explained where to make a change I will be more than happy to create PR myself and show my appreciation for the work that you have done for this library.
I'm planning to add config with following options...
instanceProperties: {
prepend: {
active: Boolean = false,
position: <start,end> = start,
style: <snake_case, cammel_case, ...> = camel_case
text: <leave, capitalize, lowercase, ...> = leave
joinWith: String = "_"
maxWidth: Int? = null
forceWidth: Int? = null
align: <left, right> = left
emptySpaceFill: String = "_"
},
}
Sounds good :)
I rescind my previous proposal on giving access to KProperty
via a new function - I kind of thought it might be useful, but now that I've given it some thought, I don't really see how that would make things better in any way; and I wanted to get rid of reflection also for awhile now.
So yeah, let's go for the configuration of instance properties instead.
Not sure what some of these configs you mention are supposed to do, but I'm happy to look at the PR and we can continue discussing the implementation there :)
I will put some good tests displaying all possible configurations. :+1:
Available in 1.14.0-rc.1
;)
@serpro69
@serpro69 Here is my example of how to use this feature in the best possible way...
The code so fine you need sunglasses :sunglasses:
val fake = Faker()
var str_counter = 0
inline fun <reified T : Any> random(): T = fake.randomProvider.randomClassInstance {
this.typeGenerator<String> { pInfo ->
str_counter++
"${pInfo.name}_${str_counter}"
}
}
data class Person(
val name: String,
val surname: String,
val phone: String,
val email: String,
val password: String,
val username: String,
)
fun main() {
for (i in 0..10) {
val oseba = random<Person>()
println(oseba)
}
}
Person(name=name_1, surname=surname_2, phone=phone_3, email=email_4, password=password_5, username=username_6)
Person(name=name_7, surname=surname_8, phone=phone_9, email=email_10, password=password_11, username=username_12)
Person(name=name_13, surname=surname_14, phone=phone_15, email=email_16, password=password_17, username=username_18)
Person(name=name_19, surname=surname_20, phone=phone_21, email=email_22, password=password_23, username=username_24)
Person(name=name_25, surname=surname_26, phone=phone_27, email=email_28, password=password_29, username=username_30)
Person(name=name_31, surname=surname_32, phone=phone_33, email=email_34, password=password_35, username=username_36)
Person(name=name_37, surname=surname_38, phone=phone_39, email=email_40, password=password_41, username=username_42)
Person(name=name_43, surname=surname_44, phone=phone_45, email=email_46, password=password_47, username=username_48)
Person(name=name_49, surname=surname_50, phone=phone_51, email=email_52, password=password_53, username=username_54)
Person(name=name_55, surname=surname_56, phone=phone_57, email=email_58, password=password_59, username=username_60)
Person(name=name_61, surname=surname_62, phone=phone_63, email=email_64, password=password_65, username=username_66)
Or event better...
val fake = Faker()
var counters = mutableMapOf<String, Int>()
inline fun <reified T : Any> random(): T = fake.randomProvider.randomClassInstance {
this.typeGenerator<String> { pInfo ->
val value = counters.getOrDefault(pInfo.name, -1) + 1
counters[pInfo.name] = value
"${pInfo.name}_${value}"
}
}
Person(name=name_0, surname=surname_0, phone=phone_0, email=email_0, password=password_0, username=username_0)
Person(name=name_1, surname=surname_1, phone=phone_1, email=email_1, password=password_1, username=username_1)
Person(name=name_2, surname=surname_2, phone=phone_2, email=email_2, password=password_2, username=username_2)
Person(name=name_3, surname=surname_3, phone=phone_3, email=email_3, password=password_3, username=username_3)
Person(name=name_4, surname=surname_4, phone=phone_4, email=email_4, password=password_4, username=username_4)
Person(name=name_5, surname=surname_5, phone=phone_5, email=email_5, password=password_5, username=username_5)
Person(name=name_6, surname=surname_6, phone=phone_6, email=email_6, password=password_6, username=username_6)
Person(name=name_7, surname=surname_7, phone=phone_7, email=email_7, password=password_7, username=username_7)
Person(name=name_8, surname=surname_8, phone=phone_8, email=email_8, password=password_8, username=username_8)
Person(name=name_9, surname=surname_9, phone=phone_9, email=email_9, password=password_9, username=username_9)
Person(name=name_10, surname=surname_10, phone=phone_10, email=email_10, password=password_10, username=username_10)
Nice :) Glad it's doing exactly what you needed. I'm sure someone else will find this feature useful as well :)
I have a huge amount of domain models + 30 and I can't maintain all the functions that would create meaningful data for all of the domain models... Because of that I have joust one generic function that is responsible for generation of any domain model...
Currently if I want to seed database with this function I get something like this...
It would be SOO NICE if there could be option to prepend those string values it would make my job on fullstack testing so much easier!