2016-08-26 13 views
5

Mam proste zapytanie do tabeli zawierającej kolumnę typu bigint.pg-promise zwraca liczby całkowite jako ciągi znaków

Jednak gdy go wypytuje, pg-promise zwraca wartości tej kolumny jako ciąg. Nie mogę znaleźć informacji na ten temat w dokumentacji. Czy to standardowe zachowanie?

var ids = [180, 120]; 

db.any('SELECT id_brand, brand from catalog_brand WHERE id_brand in ($1:csv)', [ids]) 
    .then((data) => { 
     // return results 
    }); 

data przyjmuje następującą postać, o identyfikatorze jako ciąg zamiast int:

[{id_brand: "180", brand: "Ford"}, {id_brand: "120", brand: "Nike"}] 

Czy jest coś polecić pg-promise aby powrócić do rzeczywistego typu?

Odpowiedz

11

Jest to rzeczywiście standardowe zachowanie.

bigint jest 64-bitowy, a wszystkie 64-bitowe liczby całkowite są zwracane przez leżącej node-postgres kierowcy jako typ string, natomiast te, 32-bitowe są zwracane jako number.

Powodem tego jest to, że 64-bitowa liczba całkowita nie ma dokładnej natywnej prezentacji w JavaScript, która może prezentować tylko 64-bitowe liczby z pewną precyzją, i która nie jest odpowiednia do reprezentowania pełnego zakresu 64- liczby bitowe.

Zobacz także: How to do 64bit Integer arithmetic in Node.js?


Istnieją trzy możliwe rozwiązania tego problemu ...

Rozwiązanie 1

Nie używać 64-bitowe liczby całkowite przechowywanie ID-s , jeśli twoja tabela nie ma nigdy więcej niż 4 miliardy rekordów, użyj domyślnie typu int, który jest 32-bitowy i zostanie automatycznie zwrócony jako liczba całkowita.

Rozwiązanie 2

Konwersja zwrócony id-s do liczb całkowitych on-the-fly, ale należy pamiętać, że kiedyś swój identyfikator-s numery zasięgu wystarczająco wysokie (53 bitów), wartości skonwertowane staną zniekształcony/zmieniony.

Można jednak użyć wyspecjalizowanej biblioteki, która może poprawnie przekonwertować ciąg na 64-bitową liczbę całkowitą (zobacz powyższy link), ale korzystanie z zapytań może być niewygodne.


Przykład konwersja id-s on-the-fly:

db.each('SELECT id_brand FROM catalog_brand WHERE id_brand in ($1:csv)', [ids], cat=> { 
    cat.id_brand = parseInt(cat.id_brand) 
}) 
    .then(rows => { 
     // id_brand is now an integer in each row 
    }); 

Zobacz Database.each.

Jako inny przykład, liczy rekord są zawsze zwracane jako bigint, więc najlepszym sposobem na uzyskanie tych jest poprzez transformację w linii wartości + nawrócenia, tak:

db.one('SELECT count(*) FROM catalog_brand', [], c => +c.count) 
    .then(count => { 
     // count = a proper integer value, rather than an object with a string 
    }); 

Zobacz Database.one.

Rozwiązanie 3

Można dokonać bazowego lekceważenie node-postgres Kierowca bezpieczeństwo konwersji i konwertować do takich rodzajów liczb wszędzie. Nie mogę powiedzieć, czy jest to dobry pomysł w ogóle, tylko, że można to zrobić łatwo, poprzez pgp.pg.types.setTypeParser(...) (patrz pg-types):

// Convert bigserial + bigint (both with typeId = 20) to integer: 
pgp.pg.types.setTypeParser(20, parseInt); 

Należy zauważyć, że rozwiązania 2 i 3 zrobić to samo, ale na dwóch różnych poziomach:

  • wyraźnej lokalnej konwersji w roztworze 2
  • niejawna konwersja globalny w roztworze 3
Powiązane problemy