I had recently at work gotten into using 
[MapStruct](https://github.com/mapstruct/mapstruct) for mapping data-classes of 
Type A to Type B in a simple manner.

And I thought to myself "Huh, I have to do a lot of mapping of type A to B for 
webdev to hide certain fields or do minor transformations/renames on some of 
them. This seems like it would be a nice small utility". And so I decided to 
[reimplement the simple mapping of A to B that MapStruct made 
possible](https://github.com/PhilippMDoerner/mapster). And because I am 
creative at naming I named it mapster.

The concept is pretty simple:

Define a proc/func that takes in parameters that may include types with fields 
and outputs a type with fields, then annotate it with the `{.map.}` pragma. 
Mapster will insert assignment status of the variety `result.<fieldName> = 
parameter.<fieldName>` for every field where name and type match. You can 
define your own assignments of `result.myField = 5` or the like as you want in 
the proc body, it's just a normal proc after all that inserts a few lines of 
code before your code body.

So an example:
    
    
    import std/times
    
    type A = object
      str: string
      num: int
      floatNum: float
      dateTime: DateTime
      boolean: bool
    
    type B = object
      str: string
      num: int
      floatNum: float
      dateTime: DateTime
      boolean: bool
    
    let a = A(
      str: "str,
      num: 5,
      floatNum: 2.5,
      dateTime: now(),
      boolean: true
    )
    
    proc myMapProc(x: A): B {.map.} = discard # Will transfer all fields of A 
to B
    
    let myB: B = myMapProc(a)
    
    
    proc myMapProcTripleNum(x: A): B {.map.} =
      # Perfectly valid, it's just a proc with extra stuff added before the 
proc-body!
      result.num = x.num * 3
      echo "Assigned triple num!"
    
    let myB2: B = myMapProcTripleNum(a)
    
    
    Run

It was a nice little project, particularly about learning more about macros and 
I likely will make use of it in my web-projects a fair bit as those have a lot 
of mapping-steps from data-models that interact with the database to 
data-models that can get JSON-serialized and sent to the outside. And a lot of 
those are quite annoying to deal with, having the simple assignments dealt with 
so I only need to write out the ones that matter will be quite nice.

Shoutout here to hugogranstrom and elegantbeef for the support in discord and 
the forum (in threads like [this](https://forum.nim-lang.org/t/10379) )

As an aside: Nim's AST manipulation made this **obscenely** simple. I was 
legitimately in awe at how something that seemed like it took an arm and a leg 
to implement in Java was doable in nim in ~100 lines of code (though tbf this 
does not 100% reimplement everything MapStruct does but basically everything 
that I've ever needed from it). I was already expecting nim to be an order of 
magnitude simpler to do this in, but this was more than just 1 order of 
magnitude.

Reply via email to