Невозможно преобразовать результат dynamodb в структуру с полем, определенным как интерфейс типа

У меня есть следующие определения структуры:

type Job struct {
    ID         string            `json:"id" dynamodbav:"id"`
    Ref        string            `json:"ref_id" dynamodbav:"ref_id"`
    Created    string            `json:"created_at,omitempty" dynamodbav:"created_at"`
    Stages     map[string]Status `json:"stages,omitempty" dynamodbav:"stages"`
}

// Status interface
type Status interface {
    GetMessage() string
}

// Failure struct
type Failure struct {
    Message string `json:"error_message,omitempty" dynamodbav:"message"`
}

// GetMessage returns the error message
func (f *Failure) GetMessage() string {
    return f.Message
}

// Success struct
type Success struct {
    Message string `json:"success_message,omitempty" dynamodbav:"message"`
}

// GetMessage returns the success message
func (s *Success) GetMessage() string {
    return s.Message
}

Где структуры Failure и Success удовлетворяют интерфейсу Status

Я пытаюсь разобрать ответ dynamodb в структуру Job следующим образом:

func getJobByID(id, table string) (*Job, error) {
    var (
        db = dynamodb.New(sess)

        key = map[string]*dynamodb.AttributeValue{
            "id": {
                S: aws.String(id),
            },
        }

        ip = &dynamodb.GetItemInput{
            TableName: aws.String(table),
            Key:       key,
        }
    )

    res, err := db.GetItem(ip)
    if err != nil {
        return nil, err
    }

    if res.Item == nil {
        return nil, errors.New("Not found")
    }

    var j *Job
    if err := dynamodbattribute.UnmarshalMap(res.Item, &j); err != nil {
        return nil, err
    }

    return j, nil
}

Объект Dynamodb выглядит примерно так

{
  "created_at": {
    "S": "2020-07-21T06:40:53Z"
  },
  "id": {
    "S": "ca237361-7deb-4a28-872d-a602b9b1df67"
  },
  "stages": {
    "M": {
      "stage1": {
        "M": {
          "message": {
            "S": "Completed"
          }
        }
      },
      "stage2": {
        "M": {
          "message": {
            "S": "Completed"
          }
        }
      },
      "stage3": {
        "M": {
          "message": {
            "S": "Completed"
          }
        }
      }
    }
  },
  "ref_id": {
    "S": "test-reference"
  }
}

Ошибка, которую я получаю: panic: reflect.Set: value of type map[string]interface {} is not assignable to type main.Status

Я думаю, проблема в том, что я пытаюсь преобразовать тип string в interface, и он не может получить конкретный тип интерфейса, который вызывает панику.

Мой вопрос в том, как я могу решить эту проблему идиоматическим образом.

Спасибо вам всем.


person Saurav Ghosh    schedule 23.07.2020    source источник


Ответы (1)


Не глядя на реализацию dynamodbattribute.UnmarshalMap, окончательный вариант Unmarshal завершится ошибкой, поскольку вы пытаетесь выполнить демаршалирование в пользовательский интерфейс Status. Это не сработает, поскольку среда выполнения не может узнать базовую структуру, в которую нужно выполнить демаршалирование.

Вот пример аналогичной настройки Playground только с json.

Даже при визуальном осмотре вашего json вы не можете быть уверены, является ли "message": {"S": "Completed"} успехом или ошибкой.

Вы должны заменить Status в map[string]Status структурой (как показано ниже) или даже map[string]string для работы unmarshal

{
    Message string
}

Основываясь на неудачном примере, которым я поделился ранее, здесь приведен один из способов заставить его работать. .

person poWar    schedule 23.07.2020
comment
спасибо за ответ .. я смог заставить Unmarshal работать, заменив Status на map[string]string, но проблема в том, что это определение, которое использовалось во всей кодовой базе, и есть логика, основанная на переключении интерфейса. Таким образом, искал, существует ли идиоматический способ заставить это работать. Теперь я понимаю, что для этого необходимо реализовать обходной путь. Спасибо .. - person Saurav Ghosh; 23.07.2020
comment
Если остальная часть вашего кода использует то же определение, вы можете сделать что-то вроде этой модификации образец, которым я поделился в ответе. - person poWar; 23.07.2020
comment
это именно то, как я справился с этим на самом деле. Спасибо за ответ. Я чувствую, что моя работа не является странным способом заставить его работать. :) - person Saurav Ghosh; 24.07.2020