Breaking Down MSON Template Queries | Hacker Noon

@redgeoffGeoff Cox

A coder with a passion for JS, React, GraphQL, Docker and Serverless

Template Queries are dynamic templates constructed with MongoDB-style operators. They allow you to customize MSON components with less code and are very extensible.

OK, but what the heck is MSON?

MSON is a low-code way to create apps from JSON. The ultimate goal of MSON is to allow anyone to develop software visually. You can also use pieces of MSON to turbo charge your existing apps.

A simple form component used to collect a name and email address could look like:

{
  name: 'MyForm',
  component: 'Form',
  fields: [
    { name: 'name', component: 'TextField', label: 'Name' },
    { name: 'email', component: 'EmailField', label: 'Email' }
  ]
}

You can read more about MSON’s language principles here.

What are MongoDB operators?

MongoDB uses an extensive query language that is written in JSON. Because this language is so powerful, a number of projects, that work independently from MongoDB, have adopted support for the query language:

  1. In-memory libraries for JS, like mingo and siftjs.
  2. Operators in sequelize ORM.
  3. Other databases, like CouchDB

This query language also contains a construct for pipeline aggregations, which can be used to execute operations like

$add

,

$multiply

,

$filter

,

$map

, etc… For example:

{
  $add: [ 1, 2 ]
}

A basic MSON Template Query

Now that you have that background, let’s take a look at an example where we extract the year from a user-provided date. Upon selecting a date with the date picker, you’ll see that the

Year

field is populated:

Let’s step through this example. First, we construct a form with

date

and

year

fields:

{
  component: "Form",
  fields: [
    {
      name: "date",
      component: "DateField",
      label: "Date"
    },
    {
      name: "year",
      component: "IntegerField",
      label: "Year"
    }
  ]
}

Second, we listen for changes to the

date

value, extract the year and then set the value of the

year

field:

{
  component: "Form",
  fields: ...,
  listeners: [
    {
      event: "fields.date.value",
      actions: [
        {
          component: "Set",
          name: "fields.year.value",
          value: {
            $year: {
              $toDate: "{{fields.date.value}}"
            }
          }
        }
      ]
    }
  ]
}

The

$toDate

operator is used to convert the date value, which is in milliseconds, to a date object. The

$year

operator is used to extract the year portion from the date. The

Set

action is native to MSON and is used to set the value of the

year

field.

Pretty cool? Let’s go a bit deeper…

How can we make this reusable?

You can create custom actions, which can then be reused. Let’s assume that we want to create an

app.GetYear

action that retrieves the year from a DateField value:

compiler.registerComponent("app.GetYear", {
  // Extend Set, a core MSON component, that sets a
  // property on another component
  component: "Set",

  // Define the inputs to the custom action
  schema: {
    component: "Form",
    fields: [
      {
        name: "date",
        component: "DateField",
        required: true
      }
    ]
  },

  // Omitting the "name" here allows the value
  // to be passed to the next action via
  // "{{arguments}}"
  //
  // name: "",

  // Use the template query to extract the year
  // from the date
  value: {
    $year: {
      $toDate: "{{date}}"
    }
  }
});

We can then use this custom action in a chain of actions:

const form = compiler.newComponent({
  component: "Form",
  fields: ...,
  listeners: [
    {
      event: "fields.date.value",
      actions: [
        // Extract the year and pass it to the next action
        {
          component: "app.GetYear",
          date: "{{fields.date.value}}"
        },

        // Use the extracted year to set the year field
        {
          component: "Set",
          name: "fields.year.value",

          // {{arguments}} is the output of app.GetYear
          value: "{{arguments}}"
        }
      ]
    }
  ]
});

Here is the completed example:

Another example: a conditional survey question

Let’s assume that we have a survey question and we want the user to be able to enter a free response when they select

Other

:

We define the form and hide the

covidOther

text field by default:

{
  component: "Form",
  fields: [
    {
      name: "covid",
      component: "SelectField",
      label: "My government's response to COVID-19 was...",
      fullWidth: true,
      options: [
        { label: "Good", value: "good" },
        { label: "Bad", value: "bad" },
        { label: "Other", value: "other" }
      ]
    },
    {
      name: "covidOther",
      component: "TextField",
      label: "Please explain",
      multiline: true,
      hidden: true
    }
  ]
}

If the user selects

Other

, we toggle the

hidden

boolean property of the

covidOther

field. The

$ne

operator is shorthand for not equal.

listeners: [
  {
    event: "fields.covid.value",
    actions: [
      {
        component: "Set",
        name: "fields.covidOther.hidden",
        value: {
          $ne: ["{{fields.covid.value}}", "other"]
        }
      }
    ]
  }
]

Why doesn’t MSON support custom JS in templates?

By now, you can probably see the power of Template Queries, but you may be wondering why MSON doesn’t support custom JavaScript. To support custom JS in template parameters, it would require breaking two of MSON’s core design principles:

  1. Compilation by instantiation – Components are _compiled_ into JS objects by simply instantiating a JS object and setting the props dynamically. This method of _compilation_ allows us to avoid a transpilation step and makes it much easier to dynamically modify components.
  2. Serialization & deserialization without
    eval()

    – Components can be serialized using

    JSON.stringfy()

    and stored practically anywhere. Moreover, components can be deserialized by dynamically compiling the result of

    JSON.parse()

    . As a result, raw JS (in a string), including JS template literals, are not supported as deserializing such JS would require the use of

    eval()

    or

    new Function()

    , which would expose a XSS vulnerability and add significant performance issues.

You can read more about this reasoning here.

Wrap It Up!

Template Queries add a ton of capability to MSON by providing another powerful way of customizing your MSON components. And, they can be particularly useful in minimizing the code it takes to conditionally chain a series of actions.

About the Author

Geoff Cox is the creator of MSON, a new declarative programming language that will allow anyone to develop software visually. He loves taking on ambitious, yet wife-maddening projects like creating a database and distributed data syncing system.

You can read more of his posts at redgeoff.com or reach him @CoxGeoffrey or at Github.

Also published at https://medium.com/geekculture/what-are-mson-template-queries-f6a508adf8ae

Read my stories

A coder with a passion for JS, React, GraphQL, Docker and Serverless

Tags

Join Hacker Noon

Create your free account to unlock your custom reading experience.

read original article here