Hi–
I’ve run into a Postgrex documentation question related to if my error parsing is legit enough to rely upon. To be clear, this is a “because I can, should I?” question… from a functional perspective everything currently works as desired.
The Scenario:
In the application I’m developing, I use a fair number of PostgreSQL functions, mostly in the form of INSTEAD OF
trigger functions. These are chiefly aimed at “must never be violated/must always happen” data integrity rules which cannot be satisfied using simple database constraints. Really, the kind of functions and triggers aren’t very relevant to the question, but serve as context.
Unsurprisingly, When the PL/pgSQL functions find some non-conformance/error condition/problem, they will RAISE EXCEPTION
halting any in-progress transaction and typically causing a Postgrex.Error
exception to be raised in the application. All of this is good and desirable. I’ve written the PL/pgSQL exceptions to return my own SQL Error Codes (simplified example):
IF old.syst_defined AND new.internal_name != old.internal_name THEN
RAISE EXCEPTION
USING
MESSAGE = 'The requested data update included changes to fields disallowed ' ||
'by the business rules of the API View.',
ERRCODE = 'PM003'
END IF;
Where the PM003
value is the SQL Error Code for this exception.
In the Elixir application, if this exception gets thrown, I get something along the lines of (again, simplified): %Postgrex.Error{postgres: %{pg_code: "PM003"}}
.
Great! I can work with that in the application by rescuing (or similar) the exception from Postgrex and return an error in a non-fatal way, assuming that the database exception shouldn’t be treated as fatal. But…
The Question:
When I look at the Postgrex documentation for Postgrex.Error.t()
, or the exception generally (Postgrex.Error — Postgrex v0.19.3), I only see:
@type t() :: %Postgrex.Error{
__exception__: true,
connection_id: term(),
message: term(),
postgres: term(),
query: term()
}
In which the postgres
field is simply documented as term()
. If I understand Elixir conventions correctly, “undocumented” in a library like this typically means internal implementation detail which shouldn’t be relied upon by client applications. Is this really the case here? I know of some instances of struct members being undocumented and really being considered private, but in this case I’m not sure that’s intended to be true in this case. I’m kinda hoping that deconstructing the database exception to this degree is just rare enough in Elixir applications that nobody thought it worthwhile to document rather than the absence of documentation being a signal that this should be considered an internal implementation detail.
So either I’m trying to get some sort of comfort that interrogating the returned postgres
map is OK or that there are enough others doing similar parsing that changes there will be treated like a change to any other public function or struct for practical reasons (I expect the latter to be unlikely, to be fair).
Thanks!
Steve