Go and Sitecore Interlude

This is part of the same program I'm developing to generate, serialize and deserialize items, but it's a general helper method that I found very useful, and can be used in any Go program. It can be expanded to be more complete, I pretty much did it for things that I am currently working with. You'll see what I mean.

The application is written as one application that does it all (generation, serialization, deserialization). So, it's looking for configuration settings for all aspects of those pieces of functionality. You generally don't want to serialize the same Sitecore paths that you want to generate code against. However, having the configuration in one file is not what I wanted. Here are the drawbacks.

If the configuration is in one file, you would have to update your configuration file in consecutive runs if you wanted to serialize, git fetch and merge, then deserialize. Your configuration would be committed and would be set for the next person that wants to run the program. You couldn't write bat files to run updates.

You could use the flag package to control the program pieces. Of course. But I set out to have multiple configs. For instance, if you wanted to serialize from a shared database then serialize to your local database. You could also make the config file a flag and set it to different huge files that each only differ by the connection string.

You could.

But then I wouldn't have this cool piece of code :)

Basically, when you run the program, you call it with a "-c" flag which takes a csv list of config files. The program reads them in order and merges them, having configuration values later in the chain overwrite values in the previous versions. I do this using Go's reflect package. As follows:

func Join(destination interface{}, source interface{}) interface{} {
    if source == destination {
        return destination 
    td := reflect.TypeOf(destination)
    ts := reflect.TypeOf(source)

    if td != ts || td.Kind() != reflect.Ptr {
        panic("Can't join different types OR non pointers")

    tdValue := reflect.ValueOf(destination)
    tsValue := reflect.ValueOf(source)

    for i := 0; i < td.Elem().NumField(); i++ {
        fSource := tsValue.Elem().Field(i)
        fDest := tdValue.Elem().Field(i)

        if fDest.CanSet(){
            switch fSource.Kind() {
                case reflect.Int:
                    if fDest.Int() == 0 {
                case reflect.Bool: 
                    if fDest.Bool() == false {
                case reflect.String: 
                    if fDest.String() == "" && fSource.String() != "" {
                case reflect.Slice:
                    fDest.Set(reflect.AppendSlice(fDest, fSource))
                case reflect.Map:
                    if fDest.IsNil(){
                    for _, key := range fSource.MapKeys() {
                        fDest.SetMapIndex(key, fSource.MapIndex(key))
        } else {
            fmt.Println("Can't set", tdValue.Field(i))

    return destination

So, you can see what I mean when I said it can be expanded. I'm only doing strings, bools, ints, slices and maps. The slice handling is different in that it adds values to the current slice. Map handling will add entries or overwrite if the key exists. Strings will only overwrite if the existing string is blank and the source isn't blank. So that's probably different from how I described the code in the beginning :)

Go is very useful. There's like, nothing you can't do :)

So the program is called like this:

scgen -c scgen.json,project.json,serialize.json

scgen.json will have the template ids for "template" and "template field", stuff that's pretty ok if it's hard coded. If sitecore were to change those template IDs, I'm fairly positive there's a lot of existing code out there that will break.

project.json has the connection string, the field type map, serialization path (since it's used for serialization and deserialization), and base paths for serialization.

serialize.json, in this instance, only has { "serialize" : true }  as its entire contents. Files like "generate.json" have "generate": true  as well as the file mode, output path, the Go text template, and template paths to generate.

So these files can be combined in this way to build up an entire configuration. The bools like "serialize" and "generate" are used to control program execution. The settings can be set in separate files, different files can be set and used depending on the environment, like a continuous integration server, or in a project pre-build execution. I foresee this being used with bat files. Create a "generate.bat" file which calls with generate.json in the config paths, etc for each program mode. Or a bat file to serialize, git commit, git pull, and deserialize. Enjoy!

This one is a C# post

At work, I was working on cool stuff, but then my boss was like "I need this report and this report and this report. Thanks."

I'm not one to turn down such a politely worded and completely fictitious request. Reports are easy until the requests become stuff like "Include subtotal line for every Apple category and Orange category"

My data set was obviously not Apples and Oranges, but here's what I did to quickly and easily make subtotals for each of these

First, I made some C# Attributes, which are nice when you like to work in the meta.

public class MyReportItem { [SubtotalGroup(GroupName = "Fruit Type")] public string FruitType { get; set; } public string FruitName { get; set; } [SubtotalSum] public int Count { get; set; } [SubtotalAverage] public int SalesPerDay { get; set; } [SubtotalSummaryDesignator] public bool IsSubtotalLine { get; set; } [TotalDesignator] public bool IsTotalLine { get; set; } }

Your SQL might look like this:

select FruitType, FruitName, StockQty, SalesPerDay from Fruits order by FruitType, FruitName

So your data looks like this

'Apple', 'Mcintosh', 12, 80 'Apple', 'Delicious Red', 22, 50 'Orange', 'Some Orange Name', 33, 90

The code I wrote allows that data to be quickly, easily, and automatically shown like this:

'Apple', 'Mcintosh', 12, 80 'Apple', 'Delicious Red', 22, 50 'Apple Subtotal', '', 34, 65 'Orange', 'Some Orange Name', 33, 90 'Orange Subtotal', '', 33, 90

Notice the "SalesPerDay" column has an average attribute on it, not a sum. Here's the meat of my code, after getting the attributes and the data all figured out.

public List<T> PopulateSubtotalItems() { List<T> withSubs = new List<T>(); if (this.list.Count == 0) return withSubs; // allow multiple group by with subtotals. e.g. group by Fruit Name and say fruit type, like "Citrus" // to subtotal Oranges and subtotal Limes and then subtotal Citrus List<GroupSub<T>> subs = new List<GroupSub<T>>(); foreach (string key in this.groupBy.Keys) { T sub = new T(); GroupSub<T> groupSub = this.groupBy[key]; groupSub.SubRecord = sub; // sets the properties which designate the group. So this subgroup might set FruitType to "Apple" this.SetGroup(groupSub, this.list[0]); // sets the bool property which the subtotal designator is on to true. this.SetSummary(groupSub); subs.Add(groupSub); } // if there's a bool property with the "TotalDesignator" attribute, include total GroupSub<T> totals = null; if (this.includeTotal) { T sub = new T(); totals = new GroupSub<T>(); totals.SubRecord = sub; totals.IsTotal = true; this.SetTotal(totals); // sets the property which the TotalDesignator is on to true } subs = subs.OrderBy(grp => grp.Sequence).ToList(); int grpCount = 0; for (int i = 0; i < this.list.Count; i++) { bool added = false, last = i == this.list.Count - 1; foreach (GroupSub<T> grp in subs) { bool same = SameGroup(grp, this.list[i]); if (!same) { this.Average(grp, grpCount); // set the average properties to the sum / grpCount withSubs.Add(grp.SubRecord); // add the subtotal record to the group grpCount = 0; // start afresh grp.SubRecord = new T(); this.SetSummary(grp); SetGroup(grp, this.list[i]); } Increment(grp, this.list[i]); if (last) // special handling on the last one. { this.Average(grp, grpCount); if (!added) { Increment(totals, this.list[i]); withSubs.Add(this.list[i]); added = true; } withSubs.Add(grp.SubRecord); grpCount++; } } if (!added) { Increment(totals, this.list[i]); withSubs.Add(this.list[i]); added = true; grpCount++; } } // add the total line if (this.includeTotal) { this.Average(totals, this.list.Count); // average the total record withSubs.Add(totals.SubRecord); } return withSubs; // that's it!! }

As you can see, I no longer have to dread doing subtotals on reports!