Set property when value is Just - ramda.js

I would like to set the property of an object when the value is Just, and not to set the property when the value is Nothing. However, if the value is Nothing, the returned object become Nothing.
let person = {name: 'Franz'}
const address = getAddress(response) // getAddress returns Maybe
// person will be Nothing if address is Nothing
person = S.map(R.assoc('address', R.__, person))(address)

It seems your Person type is something like this:
Person = { name :: String, (address :: Address)? }
If at all possible, I suggest avoiding null, undefined, and optional record fields as these are all sources of bugs. I suggest something like this:
// person :: Person
const person = {name: 'Franz', address: S.Nothing};
// address :: Maybe Address
const address = getAddress (response);
// person$ :: Person
const person$ = R.assoc ('address') (address) (person);
If for some reason you must have an optional address field in this case, you could use S.maybe:
// person :: Person
const person = {name: 'Franz'}
// address :: Maybe Address
const address = getAddress (response);
// person$ :: Person
const person$ = S.maybe (person)
(address => R.assoc ('address') (address) (person))
(address);
The result will either be {name: 'Franz'} or something like {name: 'Franz', address: 'Frankfurter Allee 42'}. As I mentioned, though, {name: 'Franz', address: S.Nothing} and {name: 'Franz', address: S.Just ('Frankfurter Allee 42')} are preferable representations of these “people”.

Related

Terraform Conditional Content Block Inside Resource

How do I make ip_configuration optional to turn the below:
resource "azurerm_firewall" "example" {
name = "testfirewall"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
ip_configuration {
name = "configuration"
subnet_id = azurerm_subnet.example.id
public_ip_address_id = azurerm_public_ip.example.id
}
}
In to something that OPTIONALLY accepts values in this:
variable "ip_configuration" {
type = object({
name = string // Specifies the name of the IP Configuration.
subnet_id = string // Reference to the subnet associated with the IP Configuration.
public_ip_address_id = string // The ID of the Public IP Address associated with the firewall.
})
description = "(Optional) An ip_configuration block as documented"
default = null
}
I was looking at dynamic blocks, lookups and try expressions but nothing seems to work. Can anyone help? I have spent days on it trying to figure it out
Edit:
There maybe a neater way to do it, but I have found something that works. If someone can improve on this that would be great, but thanks for those who have replied.
subnet_id should only appear in the first ip_configuration which is why I have decided to use the numbering system on the key.
resource "azurerm_firewall" "example" {
name = "testfirewall"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
dynamic "ip_configuration" {
for_each = var.ip_configuration
iterator = ip
content {
name = ip.value["name"]
subnet_id = ip.key == "0" ? ip.value["subnet_id"] : null
public_ip_address_id = ip.value["public_ip_address_id"]
}
}
}
variable "ip_configuration" {
type = map
description = <<-EOT
(Optional) An ip_configuration block is nested maps with 0, 1, 2, 3 as the name of the map as documented below:
name = string // Specifies the name of the IP Configuration.
public_ip_address_id = string // The ID of the Public IP Address associated with the firewall.
subnet_id = string // Reference to the subnet associated with the IP Configuration. The Subnet used for the Firewall must have the name AzureFirewallSubnet and the subnet mask must be at least a /26.
NOTE: Only the first map (with a key of 0) should have a subnet_id property.
EXAMPLE LAYOUT:
{
"0" = {
name = "first_pip_configuration"
public_ip_address_id = azurerm_public_ip.firstpip.id
subnet_id = azurerm_subnet.example.id
},
"1" = {
name = "second_pip_configuration"
public_ip_address_id = azurerm_public_ip.secondpip.id
},
"2" = {
name = "third_pip_configuration"
public_ip_address_id = azurerm_public_ip.thirdpip.id
}
}
EOT
default = {}
}
There maybe a neater way to do it, but I have found something that works. If someone can improve on this that would be great, but thanks for those who have replied.
subnet_id should only appear in the first ip_configuration which is why I have decided to use the numbering system on the key.
resource "azurerm_firewall" "example" {
name = "testfirewall"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
dynamic "ip_configuration" {
for_each = var.ip_configuration
iterator = ip
content {
name = ip.value["name"]
subnet_id = ip.key == "0" ? ip.value["subnet_id"] : null
public_ip_address_id = ip.value["public_ip_address_id"]
}
}
}
variable "ip_configuration" {
type = map
description = <<-EOT
(Optional) An ip_configuration block is nested maps with 0, 1, 2, 3 as the name of the map as documented below:
name = string // Specifies the name of the IP Configuration.
public_ip_address_id = string // The ID of the Public IP Address associated with the firewall.
subnet_id = string // Reference to the subnet associated with the IP Configuration. The Subnet used for the Firewall must have the name AzureFirewallSubnet and the subnet mask must be at least a /26.
NOTE: Only the first map (with a key of 0) should have a subnet_id property.
EXAMPLE LAYOUT:
{
"0" = {
name = "first_pip_configuration"
public_ip_address_id = azurerm_public_ip.firstpip.id
subnet_id = azurerm_subnet.example.id
},
"1" = {
name = "second_pip_configuration"
public_ip_address_id = azurerm_public_ip.secondpip.id
},
"2" = {
name = "third_pip_configuration"
public_ip_address_id = azurerm_public_ip.thirdpip.id
}
}
EOT
default = {}
}

SwiftUI : Type of expression is ambiguous without more context when define data type

This warning is really weird to me because I was able to create one of the data type but the other 2 are not. You will see the implement + init are mostly the same.
1 small question, if my graphql API does not have id, which is the best way to implement the id? I'm currently use country name for id. which I think is a pretty bad practice
Thank you in advance!
typealias CountryData = ScpecificCountryQuery.Data
struct Countries: Decodable {
var countries: [Country]
init(_ countries: CountryData?) {
self.countries = countries?.countries.map({ country -> Country in
Country(country)
}) ?? []
}
struct Country: Identifiable, Decodable {
var id: String {
return currency
}
var code: String
var name: String
var phone: String
var capital: String
var currency : String
var continent: Continent ( Does not have any warning)
var languages : Lan ("Type of expression is ambiguous without more context")
var states: State ("Type of expression is ambiguous without more context")
init(_ country: ScpecificCountryQuery.Data.Country?) {
self.name = country?.name ?? ""
self.code = country?.code ?? ""
self.phone = country?.phone ?? ""
self.capital = country?.capital ?? ""
self.currency = country?.currency ?? ""
self.emoji = country?.emoji ?? ""
self.continent = Continent(country?.continent)
self.languages = Lan(country?.languages)
self.states = State(country?.states)
}
struct Lan: Decodable {
var code: String
var name: String
init(_ lan: ScpecificCountryQuery.Data.Country.Language?) {
self.code = lan?.code ?? ""
self.name = lan?.name ?? ""
}
}
struct Continent: Decodable {
var code: String
var name: String
init (_ continent: ScpecificCountryQuery.Data.Country.Continent?) {
self.code = continent?.code ?? ""
self.name = continent?.name ?? ""
}
}
struct State {
var code: String
var name: String
init (_ state: ScpecificCountryQuery.Data.Country.State?) {
self.code = state?.code ?? ""
self.name = state?.name ?? ""
}
}
}
}

How to merge two different classes data into one in Kotlin

I have use two different classes:
ListTitle.kt
class ListTitle {
var id: Int? = null
var title: String? = null
constructor(id:Int, title: String) {
this.id = id
this.title = title
}
}
ListDes.kt
class ListDes {
var address: Int? = null
var des: String? = null
constructor(address: Int, des: String) {
this.address = address
this.des = des
}
}
listOfTitle and listDes are ArrayLists:
listOfTitle.add(ListTitle(1, "Hello"))
listOfTitle.add(ListTitle(2, "World"))
listDes.add(ListDes(1, "World Des"))
listDes.add(ListDes(2, "Hello Des"))
I want to assign title of ListTitle to des of ListDes by matching them by id/address for each element of the two lists.
How can I approach this?
You can use zip to merge two lists into one which has Pairs as elements.
val listOfTitle = listOf(ListTitle(1, "Hello"), ListTitle(2, "World"))
val listDes = listOf(ListDes(1, "World Des"), ListDes(2, "Hello Des"))
val pairList = listOfTitle.zip(listDes)
// since an element in the new list is a pair, we can use destructuring declaration
pairList.forEach { (title, des) ->
println("${title.title} ${des.des}")
}
Output:
Hello World Des
World Hello Des
A few notes:
You can write your classes in a shorter form in Kotlin. Just put the properties directly in the argument list of the primary constructor like shown below.
class ListTitle(
var id: Int? = null,
var title: String? = null
)
class ListDes(
var address: Int? = null,
var des: String? = null
)
Don't overuse nullability (using Int? instead of Int for instance). Make properties only nullable if necessary. If you always pass in arguments for the specified properties there is not need for them to be nullable.
Maybe you should choose other names for the classes (without "List" in it) since they are actually elements of a List in your example and not lists themselves.
If you just want to print the values you could do this:
listOfTitle.forEach {
val id = it.id
println(it.title + " " + listDes.filter { it.address == id }[0].des)
}
will print the matching des for each id:
Hello World Des
World Hello Des
The above code is supposed to work when both lists have the same length and there is always a matching des for each id
if you want to create a new list with the matching pairs:
val newList = listOfTitle.map { it ->
val id = it.id
Pair(it.title, listDes.filter { it.address == id }[0].des)
}
newList.forEach { println(it.first + " " + it.second) }

If statement in for loop not filtering out items in solidity

// #param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
// #return _id - list of ids for homes
function listHomesByAddress(string _physicalAddress) public returns(uint [] _id ) {
uint [] results;
for(uint i = 0 ; i<homes.length; i++) {
if(keccak256(homes[i].physicalAddress) == keccak256(_physicalAddress) && homes[i].available == true) {
results.push(homes[i].id);
}
}
return results;
}
The result is supposed to be a list of ids which match the physical address entered however it does not filter through but returns all the available homes.
When I change to using String utils nothing changes.
Here is the whole code:
pragma solidity ^0.4.0;
import "browser/StringUtils.sol";
// #title HomeListing
contract HomeListing {
struct Home {
uint id;
string physicalAddress;
bool available;
}
Home[] public homes;
mapping (address => Home) hostToHome;
event HomeEvent(uint _id);
event Test(uint length);
constructor() {
}
// #param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
function addHome(string _physicalAddress) public {
uint _id = uint(keccak256(_physicalAddress, msg.sender));
homes.push(Home(_id, _physicalAddress, true));
}
// #param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
// #return _id - list of ids for homes
function listHomesByAddress(string _physicalAddress) public returns(uint [] _id ) {
uint [] results;
for(uint i = 0 ; i<homes.length; i++) {
string location = homes[i].physicalAddress;
if(StringUtils.equal(location,_physicalAddress )) {
results.push(homes[i].id);
}
}
return results;
}
}
The part giving you trouble is the line uint[] results;. Arrays declared as local variables reference storage memory by default. From the "What is the memory keyword" section of the Solidity docs:
There are defaults for the storage location depending on which type of variable it concerns:
state variables are always in storage
function arguments are in memory by default
local variables of struct, array or mapping type reference storage by default
local variables of value type (i.e. neither array, nor struct nor mapping) are stored in the stack
The result is you're referencing the first storage slot of your contract, which happens to be Home[] public homes. That's why you're getting the entire array back.
To fix the problem, you need to use a memory array. However, you have an additional problem in that you can't use dynamic memory arrays in Solidity. A workaround is to decide on a result size limit and declare your array statically.
Example (limited to 10 results):
function listHomesByAddress(string _physicalAddress) public view returns(uint[10]) {
uint [10] memory results;
uint j = 0;
for(uint i = 0 ; i<homes.length && j < 10; i++) {
if(keccak256(homes[i].physicalAddress) == keccak256(_physicalAddress) && homes[i].available == true) {
results[j++] = homes[i].id;
}
}
return results;
}

Translate nested join and groupby query to Slick 3.0

I'm implementing a todo list. A user can have multiple lists and a list can have multiple users. I want to be able to retrieve all the lists for a user, where each of these lists contain a list of the users for which it's shared (including the owner). Not succeeding implementing this query.
The table definitions:
case class DBList(id: Int, uuid: String, name: String)
class Lists(tag: Tag) extends Table[DBList](tag, "list") {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc) // This is the primary key column
def uuid = column[String]("uuid")
def name = column[String]("name")
// Every table needs a * projection with the same type as the table's type parameter
def * = (id, uuid, name) <> (DBList.tupled, DBList.unapply)
}
val lists = TableQuery[Lists]
case class DBUser(id: Int, uuid: String, email: String, password: String, firstName: String, lastName: String)
// Shared user projection, this is the data of other users which a user who shared an item can see
case class DBSharedUser(id: Int, uuid: String, email: String, firstName: String, lastName: String, provider: String)
class Users(tag: Tag) extends Table[DBUser](tag, "user") {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc) // This is the primary key column
def uuid = column[String]("uuid")
def email = column[String]("email")
def password = column[String]("password")
def firstName = column[String]("first_name")
def lastName = column[String]("last_name")
def * = (id, uuid, email, password, firstName, lastName) <> (DBUser.tupled, DBUser.unapply)
def sharedUser = (id, uuid, email, firstName, lastName) <> (DBSharedUser.tupled, DBSharedUser.unapply)
}
val users = TableQuery[Users]
// relation n:n user-list
case class DBListToUser(listUuid: String, userUuid: String)
class ListToUsers(tag: Tag) extends Table[DBListToUser](tag, "list_user") {
def listUuid = column[String]("list_uuid")
def userUuid = column[String]("user_uuid")
def * = (listUuid, userUuid) <> (DBListToUser.tupled, DBListToUser.unapply)
def pk = primaryKey("list_user_unique", (listUuid, userUuid))
}
val listToUsers = TableQuery[ListToUsers]
I created an additional class to hold the database list object + the users, my goal is to map the query result somehow to instances of this class.
case class DBListWithSharedUsers(list: DBList, sharedUsers: Seq[DBSharedUser])
This is the SQL query for most of it, it gets first all the lists for the user (inner query) then it does a join of lists with list_user with user in order to get the rest of the data and the users for each list, then it filters with the inner query. It doesn't contain the group by part
select * from list inner join list_user on list.uuid=list_user.list_uuid inner join user on user.uuid=list_user.user_uuid where list.uuid in (
select (list_uuid) from list_user where user_uuid=<myUserUuuid>
);
I tested it and it works. I'm trying to implement it in Slick but I'm getting a compiler error. I also don't know if the structure in that part is correct, but haven't been able to come up with a better one.
def findLists(user: User) = {
val listsUsersJoin = listToUsers join lists join users on {
case ((listToUser, list), user) =>
listToUser.listUuid === list.uuid &&
listToUser.userUuid === user.uuid
}
// get all the lists for the user (corresponds to inner query in above SQL)
val queryToGetListsForUser = listToUsers.filter(_.userUuid===user.uuid)
// map to uuids
val queryToGetListsUuidsForUser: Query[Rep[String], String, Seq] = queryToGetListsForUser.map { ltu => ltu.listUuid }
// create query that mirrors SQL above (problems):
val queryToGetListsWithSharedUsers = (for {
listsUuids <- queryToGetListsUuidsForUser
((listToUsers, lists), users) <- listsUsersJoin
if lists.uuid.inSet(listsUuids) // error because inSet requires a traversable and passing a ListToUsers
} yield (lists))
// group - doesn't compile because above doesn't compile:
queryToGetListsWithSharedUsers.groupBy {case (list, user) =>
list.uuid
}
...
}
How can I fix this?
Thanks in advance
Edit:
I put together this emergency solution (at least it compiles), where I execute the query using raw SQL and then do the grouping programmatically, it looks like this:
case class ResultTmp(listId: Int, listUuid: String, listName: String, userId:Int, userUuid: String, userEmail: String, userFirstName: String, userLastName: String, provider: String)
implicit val getListResult = GetResult(r => ResultTmp(r.nextInt, r.nextString, r.nextString, r.nextInt, r.nextString, r.nextString, r.nextString, r.nextString, r.nextString))
val a = sql"""select (list.id, list.uuid, list.name, user.id, user.uuid, user.email, user.first_name, user.last_name, user.provider) from list inner join list_user on list.uuid=list_user.list_uuid inner join user on user.uuid=list_user.user_uuid where list.uuid in (
select (list_uuid) from list_user where user_uuid=${user.uuid}
);""".as[ResultTmp]
val result: Future[Vector[ResultTmp]] = db.run(a)
val res: Future[Seq[DBListWithSharedUsers]] = result.map {resultsTmp =>
val myMap: Map[String, Vector[ResultTmp]] = resultsTmp.groupBy { resultTmp => resultTmp.listUuid }
val r: Iterable[DBListWithSharedUsers] = myMap.map {case (listUuid, resultsTmp) =>
val first = resultsTmp(0)
val list = DBList(first.listId, listUuid, first.listName)
val users: Seq[DBSharedUser] = resultsTmp.map { resultTmp =>
DBSharedUser(resultTmp.userId, resultTmp.userUuid, resultTmp.userEmail, resultTmp.userFirstName, resultTmp.userLastName, resultTmp.provider)
}
DBListWithSharedUsers(list, users)
}
r.toSeq
}
But that's just horrible, how do I get it working the normal way?
Edit 2:
I'm experimenting with monadic joins but also stuck here. For example something like this would get all the lists for a given user:
val listsUsersJoin = for {
list <- lists
listToUser <- listToUsers
user_ <- users if user_.uuid === user.uuid
} yield (list.uuid, list.name, user.uuid, user.firstName ...)
but this is not enough because I need the get also all the users for those lists, so I need 2 queries. So I need to get first the lists for the user and then find all the users for those lists, something like:
val queryToGetListsForUser = listToUsers.filter(_.userUuid===user.uuid)
val listsUsersJoin = for {
list <- lists
listToUser <- listToUsers
user_ <- users /* if list.uuid is in queryToGetListsForUser result */
} yield (list.uuid, list.name, user.uuid, user.firstName ... )
But I don't know how to pass that to the join. I'm not even sure if groupBy, at least at database level is correct, so far I see this used only to aggregate the results to a single value, like count or avg. I need them in a collection.
Edit 3:
I don't know yet if this is right but the monadic join may be the path to the solution. This compiles:
val listsUsersJoin = for {
listToUser <- listToUsers if listToUser.userUuid === user.uuid // get the lists for the user
list <- lists if list.uuid === listToUser.listUuid // join with list
listToUser2 <- listToUsers if list.uuid === listToUser.listUuid // get all the users for the lists
user_ <- users if user_.uuid === listToUser2.userUuid // join with user
} yield (list.uuid, list.name, user.uuid, user.email, user.firstName, user.lastName)
Ah, look at that, I came up with a solution. I still have to test if works but at least the compiler stopped shouting at it. I’ll edit this later if necessary.
val listsUsersJoin = for {
listToUser <- listToUsers if listToUser.userUuid === user.uuid
list <- lists if list.uuid === listToUser.listUuid
listToUser2 <- listToUsers if list.uuid === listToUser.listUuid
user_ <- users if user_.uuid === listToUser2.userUuid
} yield (list.id, list.uuid, list.name, user_.id, user_.uuid, user_.email, user_.firstName, user_.lastName, user_.provider)
val grouped = listsUsersJoin.groupBy(_._2)
val resultFuture = db.run(grouped.result).flatMap {groupedResults =>
val futures: Seq[Future[DBListWithSharedUsers]] = groupedResults.map {groupedResult =>
val listUuid = groupedResult._1
val valueQuery = groupedResult._2
db.run(valueQuery.result).map {valueResult =>
val first = valueResult(0) // if there's a grouped result this should never be empty
val list = DBList(first._1, listUuid, first._3)
val users = valueResult.map {value =>
DBSharedUser(value._4, value._5, value._6, value._7, value._8, value._9)
}
DBListWithSharedUsers(list, users)
}
}
Future.sequence(futures)
}