Can this code be simplified?
update : Action -> Model -> Model
update action model =
let
formValue = model.formValue
in
case action of
UpdateWhat what ->
let
newValue = { formValue | what <- what }
in
{ model | formValue <- newValue }
UpdateTrigger trigger ->
let
newValue = { formValue | trigger <- trigger }
in
{ model | formValue <- newValue }
As I plan to add a couple more of Update... clauses, it is helpful to abstract this out a bit.
The code is written the way it is because Elm does not accept inner record updates.
I think what you're looking for is the focus library:
Focus
A Focus is a way to work with particular parts of a large chunk of data. On the most basic level, it lets you get and set fields of a record in a simple and composable way. This means you could avoid writing special record update syntax and use something that composes much more elegantly.
It gives you the ability to write stuff like freeze in the following snippet:
mario =
{ super = False
, fire = False
, physics = { position = { x=3, y=4 }
, velocity = { x=1, y=1 }
}
}
freeze object =
set (physics => velocity) { x=0, y=0 } object
In the code example physics and velocity are Foci. You can create a focus with code like the following, to use your example:
formValue = Focus.create .formValue (\f r -> { r | formValue <- f r.formValue })
what = Focus.create .what (\f r -> { r | what <- f r.what })
trigger = Focus.create .trigger (\f r -> { r | trigger <- f r.trigger })
update : Action -> Model -> Model
update action model =
case action of
UpdateWhat w -> Focus.set (formValue => what) w model
UpdateTrigger t -> Focus.set (formValue => trigger) t model
Related
There is a table A and jsonb field 'context', it looks like:
{
"variable": {},
"other_stuff": {}
}
I need to add a new property to 'varialbe' every time i run query. So It should do smth like:
query1
{
"variable": {
"var1": "var1Value"
},
"other_stuff": {}
}
query2
{
"variable": {
"var1": "var1Value1",
"var2": "var1Value2"
},
"other_stuff": {}
}
And if variable already has this field, it should replace it.
I run this sql, and it works:
let sql = UPDATE chatbots.A SET context = context || jsonb_set(context, '{variable, var1}', 'var1Value1')
It works but when i need to replace 'var1' and 'var1Value1' by parameters ($1 and $2) - it doesn't work (in node-postgres)
I realized that i can replace second parameter by
to_jsonb($2::text)
But what should i do with the first one?
My javascript code
async setUsersVariables(params: {users: ChatUser[], variable_name: string, variable_value: string}) {
const {users, variable_name, variable_value} = params
if (!users.length) return false
let sql = "UPDATE chatbots.A SET context = context || jsonb_set(context, '{variable, $1}', to_jsonb($2)::text) WHERE chat_user_id IN ( "
const parsedUsers = users.map(e=> e?.chat_user_id)
let sqlParams: any[] = [variable_name, variable_value]
let idx = 3;
({ sql, idx, params: sqlParams } = addSqlArrayParams(sql, parsedUsers, idx, sqlParams));
sql += ` RETURNING chat_id, chat_user_id, platform, platform_user_id`;
const filteredUsers: any = (await this.pool.query(sql, sqlParams)).rows
return filteredUsers
}
JSON
switch
uid
switch : true
uid2
switch : false
Update: above is the database structure, which I added after Jay's comment.
In swift I would do:
let databaseRef = Database.database().reference().child("switch").child(self.postID)
databaseRef.queryOrdered(byChild: "switch").queryEqual(toValue: "true").observeSingleEvent(of: .value) { (snapshot) in
print(snapshot)
if snapshot.exists() {
print("Address is in DB")
} else {
print("Address doesn't exist")
}
}
But I have to use Objective C because I have to use an Objective C selector
#objc func didLongPress() {
///that snapshot
}
override func awakeFromNib() {
super.awakeFromNib()
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(didLongPress))
like.addGestureRecognizer(longPress)
}
Update: Possible solution?
let ref = Database.database().reference().child("switch").child(self.postID).child("switch")
ref.observeSingleEvent(of:.value, with: {snapshot in
if snapshot.exists() {
print("Got data \(snapshot.value!)") //will print true or false
let ab = snapshot.value!
if ab as! Int>0 {
print("yes")
} else {
print("no")
}
}
else {
print("No data available")
}
})
The issue is with the query. Here's the structure from the question
JSON
switch
uid
switch : true
uid2
switch : false
and the query being used is querying the following
your_database
switch
uid
switch: true --> the query is running against this single child node <--
uid2
the query is NOT running here
There's really no reason to run a query against a single child node if you know the path. If the purpose is to determine if that child exists, there's no need for query at all. Just read the node directly and see if it exists
let ref = your_database.child("switch").child(self.postID).child("switch")
ref.observeSingleEvent...
and if switch is present with any value (true or false) it will be returned in the snapshot.
EDIT
If you want to know the value of the child, it will be in the snapshot if it exists. Here's some code
let ref = your_database.child("switch").child(self.postID).child("switch")
ref.getData { (error, snapshot) in
if let error = error {
print("Error getting data \(error)")
}
else if snapshot.exists() {
let myBool = snapshot.value as? Bool ?? false
print("Got data \(myBool)") //will print true or false
}
else {
print("No data available")
}
}
I have the following scenario:
when a user stops typing in the text area, I want to wait for 2 seconds and if the user didn't change anything in the textarea within those 2 seconds, I want to save the content of the textarea to the server. If the user changes something in the textarea within those 2 seconds, I want to restart the wait timeout.
In JavaScript, I would implement it something like this
http://codepen.io/ondrejsevcik/pen/LRxWQP
// Html
<textarea id="textarea"></textarea>
<pre id="server"></pre>
// JavaScript
var textarea = document.querySelector('#textarea');
var textValue = "";
textarea.oninput = function (e) {
textValue = e.target.value;
setSaveTimeout();
}
let saveTimeout;
function setSaveTimeout() {
if (saveTimeout) {
clearTimeout(saveTimeout);
}
saveTimeout = setTimeout(saveToServer, 2000);
}
function saveToServer() {
document.querySelector('#server').innerText =
'Value saved to server: ' + textValue;
}
One way to achieve the behavior is to..
Hook onInput event
Within onInput handler,
create a task which fires 2 sec later,
with a current value of textarea.
Also store the textarea contents.
check if the value has
changed or not, and save it if value did not change.
Here, it doesn't cancel the Task, so it may not be efficient.
-- MODEL
type alias Model =
{ str : String
, saved : String
}
init : (Model, Cmd Msg)
init =
(Model "" "", Cmd.none)
-- UPDATE
type Msg
= ChangeText String
| Save String
| NoOp ()
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
NoOp _ -> (model, Cmd.none)
Save str ->
let
_ = Debug.log "save" str
newmodel =
if model.str /= str
then model
else { model | saved = str }
in (newmodel, Cmd.none)
ChangeText str ->
let
_ = Debug.log "textarea" str
cmd = Task.perform NoOp Save <|
Process.sleep (2 * Time.second)
`Task.andThen`
\_ -> Task.succeed str
in ({ model | str = str }, cmd)
-- VIEW
view : Model -> Html Msg
view model =
Html.div []
[ Html.textarea [ onInput ChangeText ] []
, Html.div [] [ Html.text <| "saved: " ++ model.saved ]
]
I am new to elm and functional programming. Hope this is a simple question. What I am trying to do is, when I change views I want elm to fetch records based on the view that it is about to change to. I was hoping I could do it in the urlUpdate method based on the currentRoute. I have two views one for players and one for perks, both have independent commands objects. I tried to do it like this:
urlUpdate : Result String Route -> Model -> ( Model, Cmd Msg )
urlUpdate result model =
let
currentRoute =
Routing.routeFromResult result
_ =
Debug.log "Current Route" currentRoute
in
if toString currentRoute == "PerksRoute" then
( { model | route = currentRoute }
, Perks.Commands.fetchAll
)
else if toString currentRoute == "PlayersRoute" then
( { model | route = currentRoute }
, Players.Commands.fetchAll
)
else
( { model | route = currentRoute }, Cmd.none )
However I get this error:
The 1st branch has this type:
( { a | route : Route }, Cmd Perks.Messages.Msg )
But the 2nd is:
( { a | route : Route }, Cmd Players.Messages.Msg )
I am not sure why this is happening, I would think that having this Type defined at would be ok.
type Msg
= PlayersMsg Players.Messages.Msg
| PerksMsg Perks.Messages.Msg
Here is the full src
You need to use Cmd.map to map the child command to the parent:
if toString currentRoute == "PerksRoute" then
( { model | route = currentRoute }
, Cmd.map PerksMsg Perks.Commands.fetchAll
)
else if toString currentRoute == "PlayersRoute" then
( { model | route = currentRoute }
, Cmd.map PlayersMsg Players.Commands.fetchAll
)
I have this model
type alias Model =
{ exampleId : Int
, groupOfExamples : GroupExamples
}
type alias GroupExamples =
{ groupId : Int
, results : List String
}
In my update function, if I want to update the exampleId would be like this:
{ model | exampleId = updatedValue }
But what if I need to do to update, for example, just the results value inside of GroupExamples?
The only way to do it in the language without anything extra is to destructure the outer record like:
let
examples = model.groupOfExamples
newExamples = { examples | results = [ "whatever" ] }
in
{ model | groupOfExamples = newExamples }
There is also the focus package which would allow you to:
set ( groupOfExamples => results ) [ "whatever" ] model