arrow validation more then 10 fields - kotlin

all I have a question how can I validate more then 10 values with arrow in kotlin.
fun CreateEventDTO.validate(): Validated<IncorrectInput, CreateEventDTO> =
name.isEventNameValid()
.zip(
about.isAboutValid(),
phone.isPhoneValid(),
price.isPriceValid(),
location.isLocationValid(),
startDate.isStartDateValid(),
// TODO add common validation for date
// endDate.isEndDateValid(),
status.isEventStatusValid(),
access.isEventAccessValid(),
category.isEventCategoryValid(),
musicStyles.isMusicStyleValid()
)
{ name, _, _, price, location, status, access, category, musicStyles ->
CreateEventDTO(
name = name,
about = about,
phone = phone,
price = price,
location = location,
startDate = startDate,
endDate = endDate,
status = status,
access = access,
category = category,
musicStyles = musicStyles
)
}
.mapLeft(ApiError::IncorrectInput)
If I will try to add one more validation then I will get an error because zip just allows up to 10values
Required:
Semigroup<TypeVariable(E)>
Found:
ValidatedNel<InvalidAbout, String?> /* = Validated<NonEmptyList<InvalidAbout>, String?> */
is there any other elegant ways to handle this?

Kotlin requires all functions to be explicitly defined, and we cannot define an infinite amount of methods. Therefore Arrow made the decision to limit to 9 arguments.
However, you can easily combine different zip methods with each-other using tuples. For reaching 10 arguments, you can combine 9 + 2 in the following manner.
fun CreateEventDTO.validate(): Validated<IncorrectInput, CreateEventDTO> =
name.isEventNameValid()
.zip(
about.isAboutValid(),
phone.isPhoneValid(),
price.isPriceValid(),
location.isLocationValid(),
startDate.isStartDateValid(),
endDate.isEndDateValid(),
status.isEventStatusValid(),
access.isEventAccessValid(),
category.isEventCategoryValid().zip(musicStyles.isMusicStyleValid(), ::Pair)
)
{ name, _, _, price, location, startDate, endDate, status, access, (category, musicStyles) ->
CreateEventDTO(
name = name,
about = about,
phone = phone,
price = price,
location = location,
startDate = startDate,
endDate = endDate,
status = status,
access = access,
category = category,
musicStyles = musicStyles
)
}
.mapLeft(ApiError::IncorrectInput)

Related

creating a random list of coins from a repository

I'm trying to build a simple app that would display a coin collection for each user I type into a textfield. The coin collection would have to be unique to each user. I already have the repository for the coins. How do I generate a new random coin collection for each user? Each collection could have multiple coins of the same value but with different years.
object CoinRepository {
fun getCoinCollection(): List<Coin> {
return listOf(
Coin(
id = 1,
name = "Penny",
year = (1900..2022).random()
),
Coin(
id = 2,
name = "Nickel",
year = (1900..2022).random()
),
Coin(
id = 3,
name = "Dime",
year = (1900..2022).random()
),
Coin(
id = 4,
name = "Quarter",
year = (1900..2022).random()
),
Coin(
id = 5,
name = "Dollar",
year = (1900..2022).random()
)
)
}
}
data class Coin(
val id: Int,
val name: String,
val year: Int
)
You could do something like this:
import kotlin.random.Random
// Define your specific data in an enum, with all the relevant properties
enum class Denomination(val id: Int, val label: String) {
PENNY(1, "Penny"),
NICKEL(2, "Nickel"),
DIME(3, "Dime"),
QUARTER(4, "Quarter"),
DOLLAR(5, "Dollar");
companion object {
// a simple way to return one of the instances at random - the property
// avoids creating a new values() array every time it's called
val values = values()
fun random() = values.random()
}
}
// a basic way to keep the random date logic in the Coin class itself, using
// a default parameter. No validation involved obviously!
data class Coin(val id: Int, val label: String, val year: Int = (1900..2022).random())
// get a random number of Coins, within a certain min/max
fun getCoinCollection() = List(Random.nextInt(1, 10)) {
// pulls a random coin type and creates a Coin, letting its constructor
// handle the random date (you could do it here if you want)
Denomination.random().run { Coin(id, label) }
}
There's more than one way to organise it, I've thrown a few things in there so you can get some ideas of how you might do it. But it's basically a function that creates a list of random length (within limits), and then creates a Coin for each item, using a random Denomination
The Denomination enum is just a way to define your data, a fixed set of possible items with certain properties. Because enums generate that values() array automatically (containing all its instances) you can easily pick one at random. You could also extend the properties here to include a valid date range for each coin type, etc
You could just automatically generate the label and id values from the enum's name and ordinal properties (e.g. "PENNY" and 0) so you don't need to declare them explicitly - I feel like it's usually a good idea to decouple the data from how it's represented in the enum in code, but that's your call - I've included it so you can see how

Mapping postgres function that returns table with Hibernate

I have searched all over stackoverflow and other sites but I cannot figure out how to map tables that are returned from postgres functions with Hibernate in a Spring application.
I am not even sure if the return type table from postgres function can be matched with MyCustomTable somehow.
What I am trying to do is to call postgres functions (stored procedures) from the spring app with hibernate.
I have this postgres function
CREATE OR REPLACE FUNCTION func99(type text,start_date TIMESTAMP, end_date TIMESTAMP) RETURNS TABLE(
some_day TIMESTAMP,
tot_requests BIGINT)
AS $$
BEGIN
RETURN QUERY
SELECT t1.first_date, COUNT(*) FROM table1 t1
WHERE t1.request_type = type and t1.first_date > start_date and t1.first_date < end_date;
END;
$$ LANGUAGE PLpgSQL;
Controller
#GetMapping("/users/{username}/func99")
public List<MyCustomTable> getResultsFromFunc99(#PathVariable(value = "username") String username,
#CurrentUser UserPrincipal currentUser,
#RequestParam(value = "service_type") String type,
#RequestParam(value = "start_date") Timestamp startDate,
#RequestParam(value = "end_date") Timestamp endDate){
return queryService.getResultsFromFunc99(username, currentUser, type, startDate, endDate);
}
Service
public List<MyCustomTable> getResultsFromFunc99(String username, UserPrincipal currentUser, String type, Timestamp startDate, Timestamp endDate) {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new ResourceNotFoundException("User", "username", username));
return return incidentRepository.func99(type, startDate, endDate);
Repository
#Procedure(procedureName = "func99")
List<MyCustomTable> func99(String type, Timestamp startDate, Timestamp endDate);
Entity
#Entity
#NamedStoredProcedureQuery(
name = "func99",
procedureName = "func99",
parameters = {
#StoredProcedureParameter(name = "type", mode = ParameterMode.IN, type = String.class),
#StoredProcedureParameter(name = "start_date", mode = ParameterMode.IN, type = Timestamp.class),
#StoredProcedureParameter(name = "end_date", mode = ParameterMode.IN, type = Timestamp.class)
}
)
#Table(name = "table1")
public class MyCustomTable {...}
When a postgres function returns an integer i can make it work. What can i do to map table returns from postgres functions and how i integrate it with Hibernate?
This is a workaround I use for a similar problem, but it might work.
Define a SqlResultSetMapping like this:
#SqlResultSetMapping(
name = "MyCustomTableMapping",
entities = #EntityResult(entityClass = MyCustomTable.class)
)
Then change this parameter to your NamedStoredProcedureQuery annotation:
resultSetMappings = "MyCustomTableMapping"
I use this technique with NamedNativeQueries to make sure Hibernate doesn't track them for changes like actual entities. Saves me and my colleagues from having to remember to detach lots of entities. Just about every tutorial on how to use search results that don't correspond to a table will leave you with that problem and treat it as okay.
I found a working solution.
I don't use the method from repository.
Instead of the aforementioned repository:
*#Procedure(procedureName = "func99")
List<MyCustomTable> func99(String type, Timestamp startDate, Timestamp endDate);*
I know do this inside service without using the repository:
#PersistenceContext
EntityManager em;
.
public List<MyCustomTable> getResultsFromFunc99(String username, UserPrincipal currentUser, String type, Timestamp startDate, Timestamp endDate) {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new ResourceNotFoundException("User", "username", username));
Query query = em.createNamedStoredProcedureQuery("func99");
query.setParameter("some_day", someDay);
((StoredProcedureQuery) query).execute();
return query.getResultList()
Entity class remains the same where i declare
#Entity
#NamedStoredProcedureQuery(
name = "func99",
procedureName = "func99",
parameters = {
#StoredProcedureParameter(name = "type", mode = ParameterMode.IN, type = String.class),
#StoredProcedureParameter(name = "start_date", mode = ParameterMode.IN, type = Timestamp.class),
#StoredProcedureParameter(name = "end_date", mode = ParameterMode.IN, type = Timestamp.class)
}
)
#Table(name = "table1")
public class MyCustomTable {...}

Mapping Slick query to default projection after modifying column value

When creating a table query, I would like to modify my select statement by mapping the default table query. However, I cannot find a way to map the value of a column and still map to my case class
case class MyRecord(id: Int, name: String, value: Int)
class MyTable(tag: Tag) extends Table[MyRecord](tag, "MYTABLE") {
def id = column[Int]("id")
def name = column[String]("name")
def value = column[Int]("value")
def * = (id, name, value) <> (MyRecord.tupled, MyRecord.unapply)
}
lazy val tableQuery = TableQuery[MyTable]
I would like to trim the value of name with this function:
def trimLeading0: (Rep[String]) => Rep[String] = SimpleExpression.unary[String, String] {
(str, queryBuilder) =>
import slick.util.MacroSupport._
import queryBuilder._
b"TRIM(LEADING 0 FROM $str)"
}
Now I am at a loss about what to do here:
val trimmedTableQuery: Query[MyTable, MyRecord, Seq] = tableQuery.map(s => ???)
I have tried mapping the Rep like I would do with a case class:
val trimmedTableQuery = tableQuery.map(s => s.copy(name = trimLeading0(s.name)))
This refuses to compile with value copy is not a member of MyTable
My current workaround is to use a custom function instead of MyRecord.tupled for the default projection:
def trimming(t: (Int, String, Int)) = MyRecord(t._1, t._2.dropWhile(_ == "0"), t._3)
def * = (id, name, value) <> (trimming, MyRecord.unapply)
Alternatively, I could map the returned result of the DBIOAction returning a tuple to the case class, which is much less elegant:
val action = tableQuery.map{ s => (s.id, trimLeading0(s.name), s.value)}.result
val futureTuples: Future[Seq[(Int, String, Int)]] = db.run(action)
val records = futureTuples map (s => s.map(MyRecord.tupled))
But how can I do it inside the map method while building the query? OR would it be better to change the def name column description?
You can't mess with the default projection (i.e. def *) in MyTable as it needs to be symmetric. It's used for query and insert. But you can create a trimmedTableQuery based on a specialisation of MyTable with an overridden default projection. Then you can also have tableQuery based on the symmetric default projection. You will get an error if you try to do inserts based on the trimmedTableQuery (but you shouldn't need to do that, just use tableQuery for inserts).
lazy val tableQuery = TableQuery[MyTable]
lazy val trimmedTableQuery = new TableQuery(new MyTable(_) {
override def * = (id, trimLeading0(name), value) <> (MyRecord.tupled, MyRecord.unapply)
})

MapKit: How to retrieve apartment number from the return value of MKLocalSearchResponse

I searched thoroughly online but couldn't find any discussion about this:
The MKLocalSearchResponse object returned from a MapKit search is a collection of MKMapItem, which has the information of search results, e.g. City, state, country.
A single MKMapItem looks like this(from Xcode quick look of the object):
"Name: ADVANCED SOLUTIONS ADDICTION MANAGEMENT CurrentLocation: 0 Place: <GEOPlace: 0x9b2db90> {
address = {
formattedAddressLine = (
\"205 W Crestway Ave\",
\"Unit 200\",
\"Derby, KS 67037-1850\",
\"United States\"
);
structuredAddress = {
administrativeArea = Kansas;
administrativeAreaCode = KS;
country = \"United States\";
countryCode = US;
dependentLocality = (
Derby,
Rockford
);
fullThoroughfare = \"205 W Crestway Ave\";
geoId = (
);
locality = Derby;
postCode = 67037;
postCodeExtension = 1850;
postCodeFull = \"67037-1850\";
subAdministrativeArea = Sedgwick;
subLocality = Rockford;
subPremise = (
{
name = 200;
type = 0;
}
);
subThoroughfare = 205;
thoroughfare = \"W Crestway Ave\";
};
};
}"
I was able to retrieve all the information I needed, except the Apartment number. It's contained in the "subPremise" part, which I don't know how to retrieve.
You may suggest me to retrieve it from the "formattedAddressLines", which I have access to, but for some results, that property is empty, so I cannot rely on it.
I've also tried the "addressDictionary" property, it has all the necessary information except apartment number, which is very unthoughtful to me.
mapItem.placemark.subThoroughfare. Note that it may be empty

Linq to Entities convert one entity to similar

I have an Entity model with entities of Person and LogPerson. they are identical except that LogPerson has 2 additional fields (LogPersonID, CreateDate). How can I cast a LogPerson into a Person so that the VB.NET code that follows my Linq code doesn't have to try to work with both possible types?
For example:
dim p as person
If useLog then
p = From a In LogPerson Where ID = x
Else
p = From a In Person Where ID = x
End If
textbox1.text = p.firstname
There aren't any ways out-of-the box. The easiest way without third party tools/libraries is to use the Select method and map the properties manually, like so:
IEnumerable<Person> people = ...;
IEnumerable<LogPerson> logPeople = people.Select(p => new LogPerson {
Name = p.Name,
Age = p.Age,
...
});
Of course, this is tedious, so if you have a large number of fields or a number of places you have to perform this kind of operation, you might want to look into an auto mapping library, such as AutoMapper.
I am WRITING THE SOLUTION IN C#....
person p;
if(uselog)
{
var per = from pobj in LogPerson
where pobj.ID= x
select new person{
firstname = pobj.firstname,
lastname = pobj.lastname,
};
}else
{
var per = from pobj in Person
where pobj.ID= x
select new person{
firstname = pobj.firstname,
lastname = pobj.lastname,
};
}
p = per.first();
}
textbox1.text = p.firstname