Repository F# setup
open Reified
open Reified.Refinements
open Reified.Result
open Reified.Schema.JsonDataDSL
Reified provides a DSL for more concise data construction and editing. It includes short names and the => and
?=> operators.
Without opening Reified.DataDSL
This example declares nested data, omits an optional field, applies an atomic patch, and renders the result without
opening Reified.DataDSL:
open Reified
let nickname : string option = None
let customer =
Data.data [
Data.assoc "name" "Ada"
Data.optionalAssoc "nickname" nickname
Data.assoc "deletedAt" Data.Null
Data.assoc "address" (
Data.data [
Data.assoc "city" "Adelaide"
Data.assoc "postcode" 5000
])
Data.assoc "roles" [ "author" ]
]
let request =
customer
|> Data.patch [
DataEdit.replace "address.postcode" 5001
DataEdit.append "roles" "admin"
DataEdit.remove "deletedAt"
]
Data.render request
// => "{ name: \"Ada\", address: { city: \"Adelaide\", postcode: 5001 }, roles: [\"author\", \"admin\"] }"
Reifiednickname: string optionstringAn abbreviation for the CLI type . Basic Types
optionThe type of optional values. When used from other CLI languages the empty option is the null value. Use the constructors Some and None to create values of this type. Use the values in the Option module to manipulate values of this type, or pattern match against the values directly. 'None' values will appear as the value null to other CLI languages. Instance methods on this type will appear as static methods to other CLI languages due to the use of null as a value representation. Options
NoneThe representation of "No value"
customer: DataReified.DataModuledata: DataField list -> DataBuilds an object from ordered field instructions. Data.data [ Data.assoc "name" "Ada" ] // Data.Object [ "name", Data.Text "Ada" ]
assoc: string -> ^a -> DataFieldAssociates an object field name with one exact value. Data.assoc "name" "Ada" // one DataField
optionalAssoc: string -> ^value option -> DataFieldAssociates an object field name with Some value, or omits None. Data.optionalAssoc "nickname" (None: string option) // an omitted DataField
Reified.DataA portable tree for structured data. Data preserves null, text, number, Boolean, list, and object distinctions without depending on a serializer or input format. Data is a structured-value model, not a source syntax tree. It does not model whitespace, comments, source locations, or other format-specific syntax. Number values currently retain a lexical token so adapters do not narrow arbitrary-size integers, decimal precision, or exponent notation to one runtime numeric type.
NullA null value.
request: Data(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
patch: DataEdit list -> Data -> DataApplies edits atomically or raises DataPatchException. Data.data [ Data.assoc "name" "Ada" ] |> Data.patch [ DataEdit.replace "name" "Grace" ] // Data.data [ Data.assoc "name" "Grace" ]
Reified.DataEditModulereplace: string -> ^a -> DataEditDescribes replacing an existing value. DataEdit.replace "name" "Grace" // one DataEdit
append: string -> ^a -> DataEditDescribes appending an item to an existing list. DataEdit.append "roles" "admin" // one DataEdit
remove: string -> DataEditDescribes removing an existing field or list item. DataEdit.remove "obsolete" // one DataEdit
render: Data -> stringRenders structured data in a compact, human-readable form. Data.render (data [ "name" => "Ada"; "active" => true ]) // { name: "Ada", active: true }
For a single edit, apply the direct Data operation instead:
customer |> Data.replace "name" "Grace"
customer: Data(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Reified.DataModulereplace: string -> ^a -> Data -> DataReplaces one existing value and returns the changed tree. data [ "name" => "Ada" ] |> Data.replace "name" "Grace" // data [ "name" => "Grace" ]
The same example with Reified.DataDSL
open Reified
open Reified.DataDSL
let customerViaDsl =
data [
"name" => "Ada"
"nickname" ?=> nickname
"deletedAt" => nil
"address" => [ "city" => "Adelaide"; "postcode" => 5000 ]
"roles" => [ "author" ]
]
let requestViaDsl =
customerViaDsl
|> Data.patch [
replace "address.postcode" 5001
append "roles" "admin"
remove "deletedAt"
]
ReifiedReified.DataDSLConcise opt-in syntax for literals, immutable edits, cases, and matching.
customerViaDsl: Datadata: DataField list -> DataBuilds an object from ordered field instructions. data [ "name" => "Ada"; "active" => true ] // Data.Object [ "name", Data.Text "Ada"; "active", Data.Bool true ]
(=>): string -> ^value -> DataFieldAssociates a field name with an exact value or recursive data pattern.
(?=>): string -> ^value option -> DataFieldAssociates a field name with an optional exact value, omitting None.
nickname: string optionnil: DataAn explicit structured null used by literals and edits.
requestViaDsl: Data(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Reified.DataModulepatch: DataEdit list -> Data -> DataApplies edits atomically or raises DataPatchException. Data.data [ Data.assoc "name" "Ada" ] |> Data.patch [ DataEdit.replace "name" "Grace" ] // Data.data [ Data.assoc "name" "Grace" ]
replace: string -> ^a -> DataEditReplaces an existing value.
append: string -> ^a -> DataEditAppends an item to an existing list.
remove: string -> DataEditRemoves an existing field or list item.
Literal and edit mappings
| DataDSL | Explicit API | Result |
|---|---|---|
name => value |
Data.assoc name value |
DataField |
name ?=> option |
Data.optionalAssoc name option |
DataField |
nil |
Data.Null |
Data |
num token |
Data.number token |
Data |
data fields |
Data.data fields |
Data |
fields value |
Data.fields value |
DataField list |
set path value |
DataEdit.set path value |
DataEdit |
replace path value |
DataEdit.replace path value |
DataEdit |
remove path |
DataEdit.remove path |
DataEdit |
append path value |
DataEdit.append path value |
DataEdit |
prepend path value |
DataEdit.prepend path value |
DataEdit |
insert path index value |
DataEdit.insert path index value |
DataEdit |
rename path name |
DataEdit.rename path name |
DataEdit |
update path function |
DataEdit.update path function |
DataEdit |
| — | Data.patch edits input |
changed Data |
set makes the final path contain the value, adding a missing final object field when necessary. replace requires
the target to exist, so a misspelled or unexpectedly absent path fails.
The matching and case-generation names also live in Reified.DataDSL. Without opening it, qualify them as
Reified.DataDSL.at, Reified.DataDSL.containing, Reified.DataDSL.variant, and so on.
Remaining Reified.DataDSL names
| Area | Names |
|---|---|
| Paths | at, absent |
| Object patterns | exactly, containing |
| List patterns | containingItems, inOrder, allItems, someItem |
| General patterns | any, anyText, anyNumber, oneOf, satisfying |
| Matching | matching |
| Cases | variant, variants, dimension, matrix |
Data.tryMatch is always qualified because it is not part of the DSL.