3

I have a report server that needs to parse a string with some arguments controlling what is in the report.

I am using the parser library sprache to help with this. All is working fine except for one thing I'm stuck on.

I have a time filter that can be one of the following values: today, yesterday, last week, last month, none or custom.

It is custom that is giving me some grief. All of the others are just simple strings. Custom also has a from and to properties afterwards.

   private static readonly Parser<DataFilterEntity> TimeFilter =
        from filter in Parse.String("today").Return(DataFilterEntity.Today)
            .Or(Parse.String("yesterday").Return(DataFilterEntity.Yesterday)
            .Or(Parse.String("last week").Return(DataFilterEntity.LastWeek)
            .Or(Parse.String("last month").Return(DataFilterEntity.LastMonth)
            .Or(Parse.String("none").Return(DataFilterEntity.None))
            .Or(Parse.String("custom").Return(DataFilterEntity.Custom())))))
        select filter;

The custom line is the problem. I need to parse the "custom" string but then parse the from and to DateTime fields as well and pass them through to DataFilterEntity.Custom(from, to)

Any ideas much appreciated.

Geoff
  • 8,551
  • 1
  • 43
  • 50
Jack Hughes
  • 5,514
  • 4
  • 27
  • 32
  • Can you show such a "custom" data example? – Michael Mar 05 '13 at 09:21
  • custom 2012/12/25 2013/1/1 the first date is "from" the second "to". That is then passed through to DataFilterEntity.Custom(from, to) – Jack Hughes Mar 05 '13 at 09:23
  • Okay, do you get an error or does it not parse the custom-content anyway? How does the filter for custom look like at the moment? Is it designated to take those two dates, separated by a blank or do you have to provide those two dates separately (2 single parameters)? – Michael Mar 05 '13 at 09:31
  • The above doesn't compile because DataFilterEntity.Custom() takes 2 args from and to. I can't pass them through at the moment because I don't know how to combine a sprache Or expression with further parsing. – Jack Hughes Mar 05 '13 at 09:38

1 Answers1

7

You need to create a parser for DateTime first and then a parser for your custom type. Here's a 'simplest thing that could possibly work' example. You'd probably want to make the DateTimeParser a bit more specific in the values it accepts. I don't know what the constructor for your DataFilterEntity looks like, so I guessed :)

public static readonly Parser<DateTime> DateTimeParser =
    from day in Parse.Number
    from s1 in Parse.Char('/')
    from month in Parse.Number
    from s2 in Parse.Char('/')
    from year in Parse.Number
    select new DateTime(int.Parse(year), int.Parse(month), int.Parse(day));

public static readonly Parser<DataFilterEntity> CustomParser =
    from a1 in Parse.String("custom").Token()
    from fromDateTime in DateTimeParser.Token()
    from toDateTime in DateTimeParser.Token()
    select new DataFilterEntity(fromDateTime.ToShortDateString() + " -> " + toDateTime.ToShortDateString());

public static readonly Parser<DataFilterEntity> TimeFilter =
    Parse.String("today").Return(DataFilterEntity.Today)
        .Or(Parse.String("yesterday").Return(DataFilterEntity.Yesterday)
        .Or(Parse.String("last week").Return(DataFilterEntity.LastWeek)
        .Or(Parse.String("last month").Return(DataFilterEntity.LastMonth)
        .Or(Parse.String("none").Return(DataFilterEntity.None))
        .Or(CustomParser))));

public void TestIt()
{
    var result = TimeFilter.Parse("custom 21/3/2013 10/4/2013");
    Console.Out.WriteLine("result.Value = {0}", result.Value);
}
Mike Hadlow
  • 9,427
  • 4
  • 45
  • 37