How to create an instance of a specific type in Pact-Lang (Smart Contracts)? - smartcontracts

Pact's documentation says you can type objects with schemas. I have been unable to work out how to do this.
When creating an object, eg. in the REPL, with eg. {"a":1.0,"b":2.0}, it is of type object:*.
I have a schema of:
(defschema data
a : decimal
b : decimal
)
And a table schema that uses this:
(defschema table-schema
v : {data}
)
(deftable my-table:{table-schema})
As a note: the above does not type-check (see REPL output below)
I can find no way to insert into this table, as it produces a type error:
Type error: expected (defschema data [a:decimal, b:<a>]), found object:* at : (insert (deftable my-table:(defschema table-schema [v:(de... "123" {"v": {"value": 100.0,"rate": 0.5}}
Many thanks in advance.
Full Code:
(define-keyset 'admin-keyset (read-keyset "admin-keyset"))
(module complex-schema 'admin-keyset
(defschema data
a : decimal
b
)
(defschema table-schema
v : {data}
)
(deftable my-table:{table-schema})
(defun new-thing (id:string)
(insert my-table id {
"v" : {"value":100.0,"rate":0.5}
})
)
)
REPL Output/Interaction
pact> (load "complex-schema.repl")
"Loading complex-schema.repl..."
"Setting transaction keys"
"Setting transaction data"
"Begin Tx 0"
"Loading complex-schema.pact..."
"Keyset defined"
"Loaded module complex-schema, hash tGl1sYgL1VWh8zBJCU3KmMGbofkzK0gBEyXwbRnp7sI"
"Typecheck complex-schema: Unable to resolve all types"
:OutputFailure: Unable to unify field type: (v, {complex-schema.data}, (object:*, Object object5::object:* {"rate": Prim decimal6::decimal = LDecimal {_lDecimal = 0.5},"value": Prim decimal7::decimal = LDecimal {_lDecimal = 100.0}}))
"Verification of complex-schema failed"
:OutputFailure: Unable to unify field type: (v, {complex-schema.data}, (object:*, Object object4::object:* {"rate": Prim decimal5::decimal = LDecimal {_lDecimal = 0.5},"value": Prim decimal6::decimal = LDecimal {_lDecimal = 100.0}}))
"Commit Tx 0"
"Begin Tx 1"
"Using complex-schema"
"TableCreated"
"Commit Tx 1"
pact> (use complex-schema)
"Using complex-schema"
pact> (new-thing "123")
<interactive>:1:0: Type error: expected (defschema data [a:decimal, b:<a>]), found object:*
at : (insert (deftable my-table:(defschema table-schema [v:(de... "123" {"v": {"value": 100.0,"rate": 0.5}})
at <interactive>:0:0: (new-thing "123")

I'm not sure if it's exactly what you want since I left out the explicit type definition on the table. But it allowed me to load your module and call it's function to insert the record in my-table:
(module complex-schema 'admin-keyset
(defschema data
a : decimal
b )
(defschema table-schema
v
)
(deftable my-table:{table-schema})
(defun new-thing (id:string)
(insert my-table id
{
"v" : {"a":100.0,"b":0.5}
})
)
(defun read-thing (id:string)
(with-read my-table id { "v":= thing:{data} }
(format "Property a is {} b is {}" [(at 'a thing) (at 'b thing)]))
)
)
"Loaded module complex-schema, hash BuS1-Ez49mdvVuflRmWmJBJMmgq0nOl3XqAeSGLx_fM"
pact>
(create-table my-table)
"TableCreated"
pact>
(new-thing "test")
"Write succeeded"
pact> (read-thing "test")
"Property a is 100.0 b is 0.5"
You can apply the type definition upon reading the object:
(with-read my-table id { "v":= thing:{data} } ..
and then use the properties of the object with (at 'property objectname)

Related

Get constructor by value option in Elm (0.19.1)

I have some types:
type alias Type1 = { name : String }
type alias Type2 = { name : String, age : Int }
type S
= S1 Type1
| S2 Type2
So, when I want to build my info I can do the following:
a = S1 { name = "Name1" }
b = S2 { name = "Name2", age = 100 }
Now, I would like to get its constructor (S1 or S2) based on the info passed as parameter to the constructorByData function. Examples:
constructorByData a -- It should be returned `S1`
constructorByData b -- It should be returned `S2`
This is my aproach:
constructorByData : S -> (a -> S)
constructorByData s =
case s of
S1 _ -> S1
S2 _ -> S2
Please, note that the above code does not work. I get the following error:
-- TYPE MISMATCH ---------------------------------------------------------- REPL
Something is off with the 2nd branch of this `case` expression:
14| S2 _ -> S2
^^
This `S2` value is a:
Type2 -> S
But the type annotation on `constructorByData` says it should be:
a -> S
-- TYPE MISMATCH ---------------------------------------------------------- REPL
Something is off with the 1st branch of this `case` expression:
13| S1 _ -> S1
^^
This `S1` value is a:
Type1 -> S
But the type annotation on `constructorByData` says it should be:
a -> S
The main reason I want to do this is because I want to do the following by generalizing the message:
type Field
= Name
| Age
type Msg
= UpdateFieldString S Field String
| UpdateFieldInt S Field Int
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
UpdateFieldString s field value -> updateFieldString model s field value
UpdateFieldInt s field value -> updateFieldInt model s field value
And is for this I need the constructor in updateField{String, Int} functions

How to Query map in Groovy with sql?

I am trying to query a map in Groovy using mysql using:
def dat = [["id": person[-1], "date" : appt]]
dat.each{ db ->
sql.eachRow(
"select * from ${Sql.expand(db)};",
{ println "\t$db ${it.mid}"} );
but I get an error:
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '=10886, date=19-01-2017}' at line 1
what seems to be the problem here?
************************************************* EDIT *****************************************************
I'm now trying to insert the map into a mysql, which I am then querying using:
sql.execute '''DROP TABLE IF EXISTS EDSS'''
sql.execute '''
CREATE TABLE EDSS (
id INT,
Clinic VARCHAR(15),
EDSS VARCHAR(64),
item VARCHAR(64)
);
'''
sql.withBatch("INSERT INTO EDSS (id, Clinic, EDSS, item) VALUES (?,?,?,?)"){ bt ->
bt.addBatch(df)
}
def res = sql.eachRow("select * from EDSS"){ row ->
println "$row"
}
the sql.eachRow part works fine i.e. I can select, but in the the insert statement I only seem to be inserting the first row within the map i.e.
println(df):
[1025386, 20-10-2017, null, ahddkw9d9c]
[10213446, 19-04-2017, 2.5, null]
[102382, 19-04-2017, null, null]
[1628466, 19-04-2017, null, 292jdmd02d]
[1111345, 18-09-2015, unchanged, null]
but:
println(res):
[1025386, 20-10-2017, null, ahddkw9d9c]
*********************************** Another EDIT *****************************************************
So trying to loop round all the values in the map, df, with:
sql.withBatch { stmt ->
df.each { k, v, x, y ->
stmt.addBatch("INSERT INTO EDSS (study_id, Clinic, EDSS, NHS) VALUES ('$k', '$v', '$x', '$y')")
}
}
results in:
groovy.lang.MissingMethodException: No signature of method: sql$_run_closure1$_closure2$_closure4.doCall() is applicable for argument types: (java.lang.String) values: [1025386]
I'm used to R where everything is nice and vectorized. If anyone can help at all that would be excellent!
What I observed here :
You are trying to insert the java.util.ArrayList [[val11, val12,...],[val21, val22,...]]. you almost close at what you are trying to do.
Note : in comment dagget already mentioned this answer. I am just trying to show in code.
Answer :
def df = [
[1025386, '20-10-2017', null, 'ahddkw9d9c'],
[10213446, '19-04-2017', 2.5, null],
[102382, '19-04-2017', null, null],
[1628466,'19-04-2017', null, '292jdmd02d'],
[1111345, '18-09-2015', 'unchanged', null]
]
sql.withBatch("INSERT INTO EDSS (id, Clinic, EDSS, item) VALUES (?,?,?,?)"){ bt ->
df.each { row ->
bt.addBatch (row) // <==== Answer Line
}
}
sql.eachRow("select * from EDSS"){ row ->
println "$row"
}
Description :
The variable bt is actually BatchingPreparedStatementWrapper object. See the groovy document
So the addBatch() method can accept these types List<Object> or Object[].
Output :
[id:1025386, Clinic:20-10-2017, EDSS:[null], item:ahddkw9d9c]
[id:10213446, Clinic:19-04-2017, EDSS:2.5, item:[null]]
[id:102382, Clinic:19-04-2017, EDSS:[null], item:[null]]
[id:1628466, Clinic:19-04-2017, EDSS:[null], item:292jdmd02d]
[id:1111345, Clinic:18-09-2015, EDSS:unchanged, item:[null]]

Reading a FileReader type with a Maybe in elm

(This is related to Initializing an empty file value in Elm )
I am using Elm (0.18) and imported simonh1000's FileReader library. To store a file value, we use the following json type:
type alias FileContentArrayBuffer =
Value
and I structure my model thusly:
type alias Model =
{
username : String
, filecontent: Maybe FileContentArrayBuffer
}
initialModel : Model
initialModel =
{
username = "mark"
, filecontent = Nothing
}
When a file is dropped into place, getFileContents is called. The relevant functions and msg's are as follows:
getFileContents : NativeFile -> Cmd Msg
getFileContents nf =
FileReader.readAsArrayBuffer nf.blob
|> Task.attempt OnFileContent
type Msg
...
| OnFileContent (Result FileReader.Error (Maybe FileContentArrayBuffer))
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
...
OnFileContent res ->
case res of
Ok (Just filecontent) ->
( { model | filecontent = filecontent }, Cmd.none )
Ok Nothing ->
Debug.crash "No Content"
Err err ->
Debug.crash (toString err)
When I compile I get this error:
The right side of (|>) is causing a type mismatch.
56| FileReader.readAsArrayBuffer nf.blob
57|> |> Task.attempt OnFileContent
(|>) is expecting the right side to be a:
Task.Task FileReader.Error FileReader.FileContentArrayBuffer -> a
But the right side is:
Task.Task FileReader.Error (Maybe FileReader.FileContentArrayBuffer)
-> Cmd Msg
Not sure why, given that I have included the Maybe in my Type and provided cases. Any ideas?
If you define Msg like this instead:
type Msg
...
| OnFileContent (Result FileReader.Error FileContentArrayBuffer)
Then your update case can set the file value when successful or set to Nothing in failure:
OnFileContent res ->
case res of
Ok filecontent ->
( { model | filecontent = Just filecontent }, Cmd.none )
Err err ->
( { model | filecontent = Nothing }, Cmd.none )
Note that Debug.crash should be avoided at all costs. It really is just there for temporary debugging. It would be better perhaps to add an error message property on your model to notify the user of a problem.

How to migrate from working input range to elm-mdl Slider?

I currently have a function that I use for a range, and number input type for each piece of data (trait). Updates to the model are done via EditTrait Mhid Relevance message.
valueRange : String -> TraitWithRelevance -> Html Msg
valueRange typ trait =
let
( name, mhid, relevance ) =
trait
in
input [ Attr.type_ typ, Attr.min "0", Attr.max "100", Attr.value relevance, Attr.step "1", onInput <| EditTrait mhid ] []
In an attempt to bring in Google's material design through elm-mdl, I want to replace the valueRange "range" call with the valueSlider function which utilizes the Slider component from elm-mdl.
The code below compiles, but obviously doesn't work, because the important onChange handler is missing. However, it renders correctly and the slider changes, when I update a trait's relevance value through the input number element.
valueSlider trait =
let
( name, mhid, relevance ) =
trait
relAsFloat =
String.toFloat relevance |> Result.toMaybe |> Maybe.withDefault 0
in
Slider.view
[ Slider.value relAsFloat
, Slider.min 0
, Slider.max 100
, Slider.step 1
]
When I throw in Slider.onChange (EditTrait mhid), which works on the regular input, the compiler gives me this error.
The argument to function onChange is causing a mismatch.
438| Slider.onChange (EditTrait mhid)
^^^^^^^^^^^^^^ Function onChange is expecting the argument to be:
Float -> m
But it is:
Relevance -> Msg
Detected errors in 1 module.
As onInput type is (String -> msg) -> Html.Attribute msg I suppose Relevance is a String, and EditTrait is mhid -> String -> Msg.
In this case, Slider.onChange (EditTrait mhid) doesn't work because Slider.onChange expects a Float -> Msg not Relevance -> Msg (as the compiler message reads.)
To solve this issue, you should change EditTrait to receive a Float instead of String. Changing Relevance type to be a Float and updating the code accordingly should do the trick.

In Elm what is the correct way to implement my own toString

In Elm what is the correct way to take my Model and implement a toString function?
The type I am looking for would be toString : Model -> String, I am able to make a similar function with the type of toStr : Model -> String but I would think I would want the function to be called toString.
Example program (the Coin Changer kata):
module CoinChanger where
import Html exposing (..)
import StartApp.Simple as StartApp
import Signal exposing (Address)
import Html.Attributes exposing (..)
import Html.Events exposing (on, targetValue)
import String
---- MAIN ----
main =
StartApp.start
{
model = emptyModel
,update = update
,view = view
}
---- Model ----
type alias Model =
{
change : List Int
}
emptyModel : Model
emptyModel =
{
change = []
}
---- VIEW ----
toStr : Model -> String
toStr model =
model.change
|> List.map (\coin -> (toString coin) ++ "¢")
|> String.join ", "
view : Address String -> Model -> Html
view address model =
div []
[
input
[
placeholder "amount to make change for"
, on "input" targetValue (Signal.message address)
, autofocus True
-- style
]
[]
, div []
[
text (toStr model)
]
]
---- UPDATE ----
changeFor : Int -> List Int
changeFor amount =
[ 25, 10, 5, 1 ]
|> List.foldl
(\coin (change, amount)
-> ( change ++ List.repeat (amount // coin) coin
, amount % coin)
)
([], amount)
|> fst
update : String -> Model -> Model
update change model =
{ model | change =
case String.toInt change of
Ok amount
-> changeFor amount
Err msg
-> []
}
I would think the correct way to do this would be to call the function toString, but that gives me the following error from the compiler:
Detected errors in 1 module.
-- TYPE MISMATCH ----------------------------------------------- CoinChanger.elm
The type annotation for toString does not match its definition.
42│ toString : Model -> String
^^^^^^^^^^^^^^^ The type annotation is saying:
{ change : List Int } -> String
But I am inferring that the definition has this type:
{ change : List { change : List Int } } -> String
Renaming the function to toStr (or something not called toString) fixes the issue but seems wrong. What is the correct way to do this?
The problem is that, calling your function toString, you are overriding the toString function of the Basics module, which you are using at line 45.
To avoid this, you'll need to import the Basics module and use Basics.toString instead of simply toString to eliminare the ambiguity
The accepted answer is well out of date for anyone writing Elm 0.19+. The current solution is to write your own toString function for the type you want converted. There is a Debug.toString for use during development but its use in your code will prevent building for production.