Reading data from JSON file using DAML Script
Hello!
This is my first time posting here. I am new to DAML. I am trying to find how to extract data from JSON file to the ledger using DAML script. I am currently working on putting records of students into the ledger, using smart contract. Any advise/guidance is really appreciated.
The daml script command takes a --input-file flag that must be a JSON value with a structure that matches the type of the first (and only) argument of the script you’re running.
Here is the documentation of daml script for full details.
Does that help?
Thanks very much for your reply. I am still a bit lost on how the data structure that we defined in JSON can directly be applied to the elements within our script. For example, given the following JSON structure:
{
“album”: “The White Stripes”,
“year”: 1999,
“US_peak_chart_post”: “-”
},
How can we extract the data directly to the DAML variables. Any suggestions?
You can write a daml script that returns the data type you’re expecting. Then if you use the --output-file argument of the daml script command, it’ll produce a json file in the format that the daml code is expecting.
And you can use the daml repl, like this:
daml repl /path/to/darfile.dar
daml> import AlbumModule
daml> :json Album with album = "The White Stripes", year = 1999, usPeakChartPost = "-"
You can experiment with the correspondence between Daml data types and their JSON equivalent using the :json directive at the REPL.
For example (look to the following for additional details):
$ daml repl .daml/dist/t-0.0.1.dar --import t
daml> let a = [Album with title = "first title", year = 12, us_peak_chart_post = ""]
daml> :json a
[{"title":"first title","year":12,"us_peak_chart_post":""}]
daml>
Here is a full example of how things fit together, to make things a bit more concrete. Let’s start with daml.yaml (generated by daml new t using the Daml SDK version 2.8.1):
# for config file options, refer to
# https://docs.daml.com/tools/assistant.html#project-config-file-daml-yaml
sdk-version: 2.8.1
name: t
source: daml
init-script: Main:setup
version: 0.0.1
dependencies:
- daml-prim
- daml-stdlib
- daml-script
Next, we have daml/Main.daml (also initially generated by the daml new t command, but heavily modified):
module Main where
import Daml.Script (script, Script)
import DA.List (head)
data Album = Album with
title : Text
year: Int
us_peak_chart_post : Text
setup : [Album] -> Script ()
setup albums = script do
debug $ "There were " <> show (length albums) <> "albums."
debug $ "The first one was titled: " <> show (title $ head albums) <> "."
Finally, we have an input file albums.json:
[{"title": "The White Stripes",
"year": 1999,
"us_peak_chart_post": "-"}]
Now, with that, we can run daml build to create the dar file:
$ daml build
Running single package build of t as no multi-package.yaml was found.
2024-02-15 18:29:41.10 [INFO] [build]
Compiling t to a DAR.
2024-02-15 18:29:41.83 [INFO] [build]
Created .daml/dist/t-0.0.1.dar
$
and, once the dar is created, we can run the above daml repl command (now that .daml/dist/t-0.0.1.dar exists), or we can run the script against our input JSON file. However, we first need a running ledger, so, in another terminal but form the same folder:
$ daml sandbox
Starting Canton sandbox.
Listening at port 6865
Canton sandbox is ready.
and, while that’s left running:
$ daml script --ledger-host localhost --ledger-port 6865 --dar .daml/dist/t-0.0.1.dar --script-name Main:setup --input-file albums.json
Slf4jLogger started
[DA.Internal.Prelude:557]: \"There were 1albums.\"
[DA.Internal.Prelude:557]: \"The first one was titled: \\\"The White Stripes\\\".\"
Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
$
You’ll probably want to be doing other things with the data than print it as debug logs, but hopefully this shows you how to tie the pieces together.
Thank you very much for the example given. It is clear now.
Just another related question. How do include the data that we extracted into a template, and submit it as a transaction using createCmd?
You need to create a data declaration that matches the structure of your JSON file (or format your JSON file to match one of your data declarations). Once you have that declaration, including said data in a template is just adding an attribute of that type to that template.
Here is a more complete example. We use the same daml.yaml as before (daml new t), but our daml/Main.daml is now:
module Main where
import Daml.Script
data Thing = Thing with a: Int, b: Text
deriving (Show, Eq)
template Asset
with
owner : Party
payload: Thing
where
signatory owner
setup : Script ()
setup = script do
alice <- allocatePartyWithHint "Alice" (PartyIdHint "Alice")
aliceId <- validateUserId "alice"
createUser (User aliceId (Some alice)) [CanActAs alice]
debug $ show alice
add_thing: Thing -> Script ()
add_thing t = script do
-- Get the alice party back - this only works against the sandbox
parties <- listKnownParties
let [alice] = filter (\p -> p.displayName == Some "Alice") parties
thing_id <- submit alice.party do
createCmd Asset with
owner = alice.party
payload = t
pure ()
list_things : Script [Thing]
list_things = script do
-- Get the alice party back - this only works against the sandbox
parties <- listKnownParties
let [alice] = filter (\p -> p.displayName == Some "Alice") parties
things <- query @Asset alice.party
pure $ map (\(_cid, asset) -> asset.payload) things
Note that for a real ledger you’ll need to deal with authentication.
We start the ledger in a separate terminal:
$ daml sandbox
Starting Canton sandbox.
Listening at port 6865
Canton sandbox is ready.
We then need to:
- Build the DAR file.
- Upload the DAR file to the ledger. This was not necessary in the previous case, but now we need t because the DAR file contains the definition of the template we want to create contracts for. In a real situation you’ll probably want to have a separate Daml project with just the templates, and have the script project depend on that.
- Run the
setupscript to create thealiceparty. - Run the
add_thingscript any number of times. - Run the
list_thingsscript.
Here is a sample such interaction:. This uses the special file >(cat) to display the results of the list_things script directly rather than saving it to a file.
$ daml build
Running single package build of t as no multi-package.yaml was found.
2024-02-22 15:31:49.52 [INFO] [build]
Compiling t to a DAR.
2024-02-22 15:31:50.39 [INFO] [build]
Created .daml/dist/t-0.0.1.dar
$ daml ledger upload-dar --host localhost --port 6865 .daml/dist/t-0.0.1.dar
Uploading .daml/dist/t-0.0.1.dar to localhost:6865
DAR upload succeeded.
$ daml script --ledger-host localhost --ledger-port 6865 --dar .daml/dist/t-0.0.1.dar --script-name Main:setup
Slf4jLogger started
[DA.Internal.Prelude:557]: \"'Alice::122043af73ecba74362ba1a4295506b1e20ee424ac2e1a3563530cb122cb647f9b8c'\"
Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
$ cat t1.json
{"a": 4, "b": "hello"}
$ cat t2.json
{"a": 8, "b": "bye"}
$ daml script --ledger-host localhost --ledger-port 6865 --dar .daml/dist/t-0.0.1.dar --script-name Main:add_thing --input-file t1.json
Slf4jLogger started
Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
$ daml script --ledger-host localhost --ledger-port 6865 --dar .daml/dist/t-0.0.1.dar --script-name Main:add_thing --input-file t1.json
Slf4jLogger started
Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
$ daml script --ledger-host localhost --ledger-port 6865 --dar .daml/dist/t-0.0.1.dar --script-name Main:add_thing --input-file t2.json
Slf4jLogger started
Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
$ daml script --ledger-host localhost --ledger-port 6865 --dar .daml/dist/t-0.0.1.dar --script-name Main:add_thing --input-file t1.json
Slf4jLogger started
Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
$ daml script --ledger-host localhost --ledger-port 6865 --dar .daml/dist/t-0.0.1.dar --script-name Main:list_things --output-file >(cat)
Slf4jLogger started
[{
"a": 4,
"b": "hello"
}, {
"a": 4,
"b": "hello"
}, {
"a": 8,
"b": "bye"
}, {
"a": 4,
"b": "hello"
}]
Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
$ daml script --ledger-host localhost --ledger-port 6865 --dar .daml/dist/t-0.0.1.dar --script-name Main:add_thing --input-file t1.json
Slf4jLogger started
Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
$ daml script --ledger-host localhost --ledger-port 6865 --dar .daml/dist/t-0.0.1.dar --script-name Main:list_things --output-file >(cat)
Slf4jLogger started
[{
"a": 4,
"b": "hello"
}, {
"a": 4,
"b": "hello"
}, {
"a": 8,
"b": "bye"
}, {
"a": 4,
"b": "hello"
}, {
"a": 4,
"b": "hello"
}]
Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
$
I simply have a DAML templates, another DAML script file
I built the dar file, uploaded to sandbox using daml start
when i run my script, i get
PS C:\Users\Admin\Rohit_TakeHomeAssignment\loan-project-medium> daml script --dar .daml/dist/loan-project-0.0.1.dar --script-name Test:testLoan --ledger-host localhost --ledger-port 6865
Slf4jLogger started
Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
What does it mean?
How do i run my script?
Hi, again, @Rohit_Mittal and welcome to the forums!
You’ll have better success getting a response to your questions if you create new posts for new questions. Posting to an existing question only gives visibility to those subscribed to the question.
I simply have a DAML templates, another DAML script file I built the dar file, uploaded to sandbox using daml start when i run my script, i get PS C:\Users\Admin\Rohit_TakeHomeAssignment\loan-project-medium> daml script --dar .daml/dist/loan-project-0.0.1.dar --script-name Test:testLoan --ledger-host localhost --ledger-port 6865 Slf4jLogger started Running CoordinatedShutdown with reason [ActorSystemTerminateReason] I have already built dar file, ran daml sandbox using daml start and I see…
Can you please help @WallaceKelly