Несовпадение типов с проекцией на свойство байта [] - PullRequest
0 голосов
/ 08 октября 2019

У меня есть следующая структура

  type MyEntity struct {
     PF []byte `json:"-" datastore:"_pf"`
  }

Запросы без проекции работают нормально. Однако, когда я запрашиваю с проекцией на поле "_pf", я получаю ошибку "несоответствие типов: строка против [] uint8". Я реализовал PropertyLoadSaver и проверил свойство prop.Value "_pf" и обнаружил, что некоторые строки возвращают тип байта [], а некоторую возвращаемую строку. Итак, почему проецируемый запрос терпит неудачу с этой ошибкой, тогда как непрогнозируемые запросы в порядке? В настоящий момент я решаю эту проблему путем реализации интерфейса PropertyLoadSaver и явной проверки типов и преобразования строкового типа в тип байта [] для решения этой проблемы.

Вот полный тестовый пример. Это воспроизводится на эмуляторе облачного хранилища данных. Используйте соответствующее значение для переменной datastoreProject ниже. Остальное все должно работать напрямую. Вы можете увидеть поведение, вставив обе сущности или один из типов сущностей. Отображаемая ошибка:

panic: datastore: cannot load field "_pf" into a "tests.MyEntity": type mismatch: string versus []uint8 [recovered]
    panic: datastore: cannot load field "_pf" into a "tests.MyEntity": type mismatch: string versus []uint8

Ниже приведен код.

type MyEntity struct {
    PF []byte `json:"-" datastore:"_pf"`
}

func TestPackedField(t *testing.T) {
    e1 := &MyEntity{PF: []byte{83, 0, 0, 0, 93, 150, 154, 206, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 3}} // returns []byte on projection
    e2 := &MyEntity{PF: []byte{83, 0, 0, 0, 93, 120, 79, 87, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 3}}   // returns string on projection

    ctx := context.Background()

    conn, err := datastore.NewClient(ctx, datastoreProject)
    if err != nil {
        panic(err)
    }

    bkey := datastore.NameKey("Bytes", "bytearray", nil)
    if true {
        conn.Put(ctx, bkey, e1)
    }
    skey := datastore.NameKey("Bytes", "string", nil)
    if true {
        conn.Put(ctx, skey, e2)
    }

    q1 := datastore.NewQuery("Bytes").Order("-_pf").Limit(2)
    var elfull []*MyEntity
    if _, err := conn.GetAll(ctx, q1, &elfull); err != nil {
        panic(err)
    }

    q2 := datastore.NewQuery("Bytes").Project("_pf").Order("-_pf").Limit(2)
    var elprojected []*MyEntity
    if _, err := conn.GetAll(ctx, q2, &elprojected); err != nil {
        conn.Delete(ctx, bkey)
        conn.Delete(ctx, skey)
        panic(err)
    }
}

1 Ответ

0 голосов
/ 10 октября 2019

Чтобы понять, почему это работает нормально на обычных запросах, а не на проекционных запросах, вы можете сначала прочитать о том, какова реальная разница между этими двумя. Как упоминается в этом посте :

В то время как «обычные» (что я имею в виду SELECT * ...) запросы к Cloud Datastore обычно используют индексы, которые толькосодержат отсортированное подмножество свойств запрашиваемых сущностей, а также указатели на полные сущности, запросы проекций выполняются для индексов, которые содержат все поля, запрошенные запросом. Похоже, что значительный выигрыш в задержке достигается за счет устранения необходимости извлекать запрашиваемые объекты, как только набор объектов, соответствующих запросу, был обнаружен через индекс.

Итак, в основном, когда вы делаетеваш запрос проекции, ваши запрашиваемые объекты не выбираются.

Когда я читал эту официальную документацию , я нашел несколько действительно интересных фраз, связанных с вашим вопросом:

Поле типа слайса соответствует хранилищу данныхсвойство массива, за исключением байта [], который соответствует BLOB-объекту хранилища данных. Если в поле слайса загружено не массивное значение, результатом будет слайс с одним элементом, содержащим значение.

Ключевое поле Если структура содержит поле * datastore.Key, помеченное именем " key", его значение будет игнорироваться при Put. При чтении сущности обратно в структуру Go, поле будет заполнено значением * datastore.Key, используемым для запроса сущности.

Отсюда я понял, что, возможно, в вашем случаеполя заполняются значением ключа для этого запроса (строка).

Еще одна интересная вещь, которую я обнаружил, заключается в том, что согласно документации по свойствам и значениям типа байт типа [] равенне индексируется. И как сказано здесь , неиндексированные свойства не могут быть спроецированы. Таким образом, прогнозируемые запросы вообще не должны работать для этого конкретного варианта использования.

...