generateDeserialization method

List<MapEntry<Expression, Code>> generateDeserialization(
  1. bool serverCode, {
  2. required GeneratorConfig config,
})

Generates the constructors for List and Map types

Implementation

List<MapEntry<Expression, Code>> generateDeserialization(
  bool serverCode, {
  required GeneratorConfig config,
}) {
  if (isRecordType) {
    return [
      MapEntry(
        refer('getType', serverpodUrl(serverCode))
            .call([], {}, [reference(serverCode, config: config)]),
        Block.of(
          [
            if (nullable) const Code(' (data == null) ? null as T : '),
            const Code('('),
            for (final (i, positionalField)
                in positionalRecordFields.indexed) ...[
              if (positionalField.nullable)
                Code(
                    "((data ${i == 0 ? 'as Map' : ''})['p'] as List)[$i] == null ? null : "),
              const Code('deserialize<'),
              positionalField
                  .reference(serverCode, config: config, nullable: false)
                  .code,
              const Code('>('),
              if (i == 0 && !positionalField.nullable) ...[
                Code("((data as Map)['p'] as List)[$i]"),
              ] else
                Code("data['p'][$i]"),
              const Code(')'),
              const Code(','),
            ],
            if (namedRecordFields.isNotEmpty) ...[
              for (final (i, namedField) in namedRecordFields.indexed) ...[
                Code(namedField.recordFieldName!),
                const Code(':'),
                if (namedField.nullable)
                  Code(
                      "((data ${i == 0 && positionalRecordFields.isEmpty ? 'as Map' : ''})['n'] as Map)['${namedField.recordFieldName!}'] == null ? null : "),
                const Code('deserialize<'),
                namedField
                    .reference(serverCode, config: config, nullable: false)
                    .code,
                const Code('>('),
                if (i == 0 &&
                    positionalRecordFields.isEmpty &&
                    !namedField.nullable)
                  Code(
                      "((data as Map)['n'] as Map)['${namedField.recordFieldName!}']")
                else
                  Code("data['n']['${namedField.recordFieldName!}']"),
                const Code(')'),
                const Code(','),
              ],
            ],
            const Code(') as T'),
          ],
        ),
      ),
    ];
  } else if ((className == ListKeyword.className ||
          className == SetKeyword.className) &&
      generics.length == 1) {
    return [
      MapEntry(
        nullable
            ? refer('getType', serverpodUrl(serverCode))
                .call([], {}, [reference(serverCode, config: config)])
            : reference(serverCode, config: config),
        Block.of([
          nullable
              ? Block.of([
                  // using Code.scope only sets the generic to List
                  const Code('(data!=null?'
                      '(data as List).map((e) =>'
                      'deserialize<'),
                  generics.first.reference(serverCode, config: config).code,
                  Code('>(e))${className == 'Set' ? '.toSet()' : '.toList()'}'
                      ':null) as T')
                ])
              : Block.of([
                  const Code('(data as List).map((e) =>'
                      'deserialize<'),
                  generics.first.reference(serverCode, config: config).code,
                  Code(
                      '>(e))${className == 'Set' ? '.toSet()' : '.toList()'} as T'),
                ])
        ]),
      ),
      ...generics.first.generateDeserialization(serverCode, config: config),
    ];
  } else if (className == MapKeyword.className && generics.length == 2) {
    return [
      MapEntry(
        nullable
            ? refer('getType', serverpodUrl(serverCode))
                .call([], {}, [reference(serverCode, config: config)])
            : reference(serverCode, config: config),
        Block.of([
          generics.first.className == 'String'
              ? nullable
                  ? Block.of([
                      // using Code.scope only sets the generic to List
                      const Code('(data!=null?'
                          '(data as Map).map((k,v) =>'
                          'MapEntry(deserialize<'),
                      generics.first
                          .reference(serverCode, config: config)
                          .code,
                      const Code('>(k),deserialize<'),
                      generics[1].reference(serverCode, config: config).code,
                      const Code('>(v)))' ':null) as T')
                    ])
                  : Block.of([
                      // using Code.scope only sets the generic to List
                      const Code('(data as Map).map((k,v) =>'
                          'MapEntry(deserialize<'),
                      generics.first
                          .reference(serverCode, config: config)
                          .code,
                      const Code('>(k),deserialize<'),
                      generics[1].reference(serverCode, config: config).code,
                      const Code('>(v))) as T')
                    ])
              : // Key is not String -> stored as list of map entries
              nullable
                  ? Block.of([
                      // using Code.scope only sets the generic to List
                      const Code('(data!=null?'
                          'Map.fromEntries((data as List).map((e) =>'
                          'MapEntry(deserialize<'),
                      generics.first
                          .reference(serverCode, config: config)
                          .code,
                      const Code('>(e[\'k\']),deserialize<'),
                      generics[1].reference(serverCode, config: config).code,
                      const Code('>(e[\'v\']))))' ':null) as T')
                    ])
                  : Block.of([
                      // using Code.scope only sets the generic to List
                      const Code('Map.fromEntries((data as List).map((e) =>'
                          'MapEntry(deserialize<'),
                      generics.first
                          .reference(serverCode, config: config)
                          .code,
                      const Code('>(e[\'k\']),deserialize<'),
                      generics[1].reference(serverCode, config: config).code,
                      const Code('>(e[\'v\'])))) as T')
                    ])
        ]),
      ),
      ...generics.first.generateDeserialization(serverCode, config: config),
      ...generics[1].generateDeserialization(serverCode, config: config),
    ];
  } else if (customClass) {
    // This is the only place the customClass bool is used.
    // It could be moved as we already know that we are working on custom classes
    // when we generate the deserialization.
    // But the additional functionality we get here is that we generate resolves for lists and maps
    // if the custom class is used as a generic type. The day we create a more generic way to resolve generics
    // in lists, maps, etc the customClass bool can be removed which will simplify the code.
    return [
      MapEntry(
          nullable
              ? refer('getType', serverpodUrl(serverCode))
                  .call([], {}, [reference(serverCode, config: config)])
              : reference(serverCode, config: config),
          Code.scope((a) => nullable
              ? '(data!=null?'
                  '${a(reference(serverCode, config: config))}'
                  '.fromJson(data):null)as T'
              : '${a(reference(serverCode, config: config))}'
                  '.fromJson(data) as T'))
    ];
  } else {
    return [];
  }
}