Record-transformation and value-preparation helpers shared across the
import paths in ConnectionNotifier.
Three concerns:
value/4,key_value/2,value/3andvalue/1— convert JSON-transported scalars back into Postgrex-ready terms. A string is read by the type of the column it goes into, never by its shape: ISO8601 text becomes a DateTime / Date / Time only in a timestamp / date / time column, and a numeric string a%Decimal{}(numeric, decimal) or a float (double precision, real) only in a numeric one."2026-01-01"in atextcolumn stays text.value/3andvalue/1are the forms for a caller with no column type to go by; they read by shape.numeric_column_types/1— maps each numeric column of a table to:decimalor:float. Cached once per table-import by the importer; empty map on error (safe "don't coerce" fallback).- Record field helpers (
get_field/2,put_field/3,drop_field/2,normalize_keys/1) — records arrive with either string or atom keys depending on whether they came through JSON or internal code. These helpers access/modify fields uniformly without creating atoms from untrusted data.
All functions are pure or depend only on SchemaInspector (for column
introspection) — none touch HTTP, the socket, or the websocket client.
Summary
Types
A column's type as the importer names it: the information_schema
data_type, or {:array, element_type} for an array column.
Functions
Prepares a key value (a primary key, a unique column) for a lookup in a
column of SQL type type. Read by that type like value/4; by shape
when type is nil.
Maps each numeric column of table_name to the term a numeric string in
it should become: :decimal for numeric/decimal, :float for double
precision/real. Empty map on error.
Prepares value for column, whose SQL type column_types names
(%{column => information_schema data_type}). A string is parsed only as
what that type holds; in any other column (text, varchar, citext, an
enum, ...) it is passed as it came. numeric_cols is the map
numeric_column_types/1 returns.
Types
Functions
@spec key_value(any(), column_type() | nil) :: any()
Prepares a key value (a primary key, a unique column) for a lookup in a
column of SQL type type. Read by that type like value/4; by shape
when type is nil.
Maps each numeric column of table_name to the term a numeric string in
it should become: :decimal for numeric/decimal, :float for double
precision/real. Empty map on error.
@spec value(any(), String.t(), %{required(String.t()) => :decimal | :float}, %{ required(String.t()) => column_type() | nil }) :: any()
Prepares value for column, whose SQL type column_types names
(%{column => information_schema data_type}). A string is parsed only as
what that type holds; in any other column (text, varchar, citext, an
enum, ...) it is passed as it came. numeric_cols is the map
numeric_column_types/1 returns.
A column column_types does not name is read by shape, as value/3 does.
An array column is named {:array, element_type} and takes a list, whose
elements are read by the element type
(PhoenixKitSync.DataImporter.prepare_array/2). A list for any other
column (a json value) is passed as it came.
A map is read as the base64 wrapper of bytes
(%{"__phoenix_kit_binary__" => ...}) only in a bytea or uuid column;
in any other column the type of which is known it is passed as it came,
so a json object of that shape stays an object.