deser/pragmas

Types

RenameCase = enum
  CamelCase, CobolCase, KebabCase, PascalCase, PathCase, SnakeCase, PlainCase,
  TrainCase, UpperSnakeCase
  Source   Edit

Templates

template aliases(aliases: varargs[typed]) {.pragma.}

Deserialize field from the given names or from its Nim name. Accepts strings and RenameCase values.

Example:

type
  User = object
    nickName {.aliases("username", "login", SnakeCase).}: string

  Source   Edit
template defaultValue(value: typed = nil) {.pragma.}

Uses the specified value, function or template if the field was not in the input.

Function or template must be callable as myDefault[T]().

Examples:

type
  User = object
    name {.defaultValue("noname").}: string

Do not specify a value, then system default will be used:

import deser_json

type
  Foo = object
    id {.defaultValue.}: int

assert Foo.fromJson("""{}""").id == 0

Specify a function

proc myDefault[T](): T =
  when T is int:
    123
  elif T is string:
    "hello"
  else:
    {.error.}

type
  User = object
    id {.defaultValue(myDefault).}: int

You can use defaultValue on object. Than specified value will be used on all missing fields.

type
  User {.defaultValue(myDefault).} =
    id: int
    bio: string

  Source   Edit
template deserializeWith(with: typed) {.pragma.}

Deserialize this field using a procedure.

The given procedure must be callable as proc (deserializer: var auto): FieldType or proc [T](deserializer: var auto): T.

Example:

import std/times

import
  deser,
  deser_json

proc fromTimestamp(deserializer: var auto): Time =
  fromUnix(deserialize(int64, deserializer))

type
  User = object
    created {.deserializeWith(fromTimestamp).}: Time

makeDeserializable(User)

assert User(created: fromUnix(123)) == User.fromJson("""{"created": 123}""")

  Source   Edit
template deserWith(with: typed) {.pragma.}

Combination of serializeWith and deserializeWith.

The given type (or anything actually) must have callable .serialize and .deserialize attributes.

.serialize must be callable as proc (self: withType, field: FieldType, serializer: var auto).

.deserialize must be callable as proc (self: withType, deserializer: var auto): FieldType or proc [T](self: withType, deserializer: var auto): T.

Note: You dont need to reimplement this example in your project. Please use helpers module.

Example:

import std/times

import
  deser,
  deser_json


type UnixTimeFormat = object

proc deserialize(self: typedesc[UnixTimeFormat], deserializer: var auto): Time =
  fromUnix(deserialize(int64, deserializer))

proc serialize(self: typedesc[UnixTimeFormat], field: Time, serializer: var auto) =
  serializer.serializeInt64(self.toUnix())

type
  User = object
    created {.deserWith(UnixTimeFormat).}: Time

makeSerializable(User)
makeDeserializable(User)

let user = User(created: fromUnix(123))

assert user == User.fromJson("""{"created": 123}""")
assert user.toJson() == """{"created":123}"""

  Source   Edit
template onUnknownKeys(call: typed) {.pragma.}

By default, the deserializer skips unknown fields. You can change this behavior by specifying a template or procedure that will be called when an unknown field is detected.

The template or procedure must take two arguments:

  • the name of the object: string or static[string]
  • the field value: auto

Example:

import std/strformat

# this example will not work with all parsers,
# because it expects the field as a string,
# but in some formats the field can be represented by a number
proc showUpdateWarning(objName, fieldName: string) =
  # show warning only once
  var yet {.global.} = false
  
  if not yet:
    echo &"An unknown `{fieldName}` field was detected when deseralizing the `{objName}` object. Check the library updates"
    yet = true


type
  User {.onUnknownKeys(showUpdateWarning).} = object
    id: int
    name: string

Another example with warnings output only once for each object:

proc showUpdateWarning(objName: static[string], fieldName: string) =
  # Since the object name is known at compile time,
  # we can make the `objName` argument generic and use the behavior of the `global` pragma
  # https://nim-lang.org/docs/manual.html#pragmas-global-pragma
  var yet {.global.} = false
  
  if not yet:
    echo &"An unknown `{fieldName}` field was detected when deseralizing the `{objName}` object. Check the library updates"
    yet = true

  Source   Edit
template renameAll(renameTo: RenameCase) {.pragma.}
Rename all fields to some case.
Note: Pragma respects other rename pragmas. For example, if a field has the renameSerialize pragma, only deserialization will be affected.

Example:

import deser_json

type
  Foo {.renameAll(SnakeCase).} = object
    firstName: string
    lastName: string

makeSerializable(Foo)

assert Foo().toJson() == """{"first_name":"","last_name":""}"""

  Source   Edit
template renamed(renamed: string | RenameCase) {.pragma.}
Serialize and deserialize field with the given name instead of its Nim name.   Source   Edit
template renameDeserialize(renamed: string | RenameCase) {.pragma.}
Deserialize field with the given name instead of its Nim name.   Source   Edit
template renameSerialize(renamed: string | RenameCase) {.pragma.}
Serialize field with the given name instead of its Nim name.   Source   Edit
template serializeWith(with: typed) {.pragma.}

Serialize this field using a procedure.

The given function must be callable as proc (self: FieldType, serializer: var auto).

Example:

import std/times

import
  deser,
  deser_json

proc toTimestamp(self: Time, serializer: var auto) =
  serializer.serializeInt64(self.toUnix())

type
  User = object
    created {.serializeWith(toTimestamp).}: Time

makeSerializable(User)

assert User(created: fromUnix(123)).toJson() == """{"created":123}"""

  Source   Edit
template skipDeserializing() {.pragma.}

Use this pragma to skip the field during deserialization.

Example:

type
  Test = object
    skipOnDeserialization {.skipDeserializing.}: int

  Source   Edit
template skipped() {.pragma.}

Use this pragma to skip the field during serialization and deserialization.

Example:

type
  Test = object
    alwaysSkip {.skipped.}: int

  Source   Edit
template skipPrivate() {.pragma.}

Use this pragma to skip all private fields during serialization and deserialization.

Example:

type
  User {.skipPrivate.} = object
    id*: int
    name*: string
    passwordHash: string

  Source   Edit
template skipPrivateDeserializing() {.pragma.}

Use this pragma to skip all private fields during deserialization

Example:

type
  User {.skipPrivateDeserializing.} = object
    id*: int
    name*: string
    passwordHash: string

  Source   Edit
template skipPrivateSerializing() {.pragma.}

Use this pragma to skip all private fields during serialization

Example:

type
  User {.skipPrivateSerializing.} = object
    id*: int
    name*: string
    passwordHash: string

  Source   Edit
template skipSerializeIf(condition: typed) {.pragma.}

Use this pragma to skip the field during serialization based on the runtime value.

You must specify a function or template that accepts an argument with the same type as the field, and return bool.

Example:

import std/options

func isZero(x: int): bool = x == 0

type
  Test = object
    someOption {.skipSerializeIf(isNone).}: Option[int]
    someInt {.skipSerializeIf(isZero).}: int

  Source   Edit
template skipSerializing() {.pragma.}

Use this pragma to skip the field during serialization.

Example:

type
  Test = object
    skipOnSerialization {.skipSerializing.}: int

  Source   Edit
template untagged() {.pragma.}

By default, the discriminant of object variants is de/serialized as a regular field:

type
  Test = object
    kind: bool
    of true:
      trueField: string
    else:
      falseField: string
equals to this JSON:

{
  "kind": true
  "trueField": ""
}

However, deser can deduce the discriminant from the raw data:

import deser_json

type
  Test = object
    kind {.untagged.}: bool
    of true:
      trueField: string
    else:
      falseField: string

makeDeserializable(Test)

const json = """
  {
    "trueField": ""
  }
"""
let test = Test.fromJson(json)

assert test.kind == true

  Source   Edit