#1 2016-05-16 18:50:26

Eugene Ilyin
Member
From: milky_way/orion_arm/sun/earth
Registered: 2016-03-27
Posts: 132
Website

Scope delivery from Default() to Mustache didn't come with respect

Let's look into the TSynMustache.DateFmt mustache helper:

SynMustache.pas
...
class procedure TSynMustache.DateFmt(const Value: variant; out result: variant);
...
  with _Safe(Value)^ do
    if (Kind=dvArray) and (Count=2) and (TVarData(Values[0]).VType=varDate) then
      result := FormatDateTime(Values[1],TVarData(Values[0]).VDate) else
      SetVariantNull(result);

It's pretty simple: the DateFmt helper expects varDate as a first parameter and then call FormatDateTime.

Let's have a simple Mustache template with copyright notice and put it into Views\Default.html:

...
<div>(c) {{DateFmt Scope.Now,"yyyy"}}</div>
...

So, we are ready to use the full power of suggested MVVM approach.

Let's introduce simple Default interface-based method:

procedure TMyApplication.Default(var Scope: variant);
begin
  if VarIsEmptyOrNull(Scope) then
  begin
    TDocVariant.NewFast(Scope);
    Scope.Now := NowUTC;
  end;
end;

As expected Scope.Now contains current UTC server time stamp with appropriate varDate type.

You can expect that this Scope will be used as a data context for the mustache template rendering. Nope! smile

Scope will be transferred to Mustache Renderer through serialization/deserialization with no respect to initial variant types (like varDate).

Here how it works under the hood:

mORMotMVC.pas

procedure TMVCRendererAbstract.ExecuteCommand(aMethodIndex: integer);
...
              if not exec.ExecuteJson([fApplication.fFactoryEntry],pointer(fInput),WR,true) then
...
            WR.SetText(methodOutput);
...
            renderContext := _JsonFast(methodOutput);
            Renders(renderContext,action.ReturnedStatus,false);

As you see we serialize our Default(Scope) call into RawUTF8 methodOutput variable and then deserialize it into renderContext with _JsonFast.

As the result all accurate data types placed into Scope were lost and replaced with strings (but not varDate for example).

What we have as the result? DateFmt expects varDate but received varString and returns nothing.

How to resolve it?

Of course you can suggest smth like:

Scope.Copyright := '(c) 2016';
Scope.Year := 2016;

This is not good:

1. You mix data (Model) and template representation (View) concepts which provides representation leaks.
2. You didn't use nice DateFmt helper because there are no ways to pass varDate from interface-based MVVM pattern to mustache template scope.

This serialization/deserialization is so deep in the Mustache kernel processing that I didn't see easy ways how to resolve it.

Any suggestions?

Offline

#2 2016-05-17 06:29:41

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,230
Website

Re: Scope delivery from Default() to Mustache didn't come with respect

There was indeed a problem...
I've ensured DateTimeToText/DateToText/DateFmt Mustache expression helpers would decode ISO-8601 date/time values as expected.
See http://synopse.info/fossil/info/446cbba153

Thanks for the detailed feedback.

Online

Board footer

Powered by FluxBB