@everystack/cli 0.4.38 → 0.4.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,52 @@
1
+ /**
2
+ * pg-argtypes — function identity is name + ARGUMENT TYPES.
3
+ *
4
+ * PostgreSQL identifies a function by `schema.name(argtypes)`, not by name. The derived
5
+ * layer keyed on `schema.name` alone, so two overloads collapsed onto one identity: the
6
+ * generated `DROP FUNCTION IF EXISTS api.get_user` errored ("function name is not
7
+ * unique"), `derived_provenance` (identity is its PRIMARY KEY) held one row for two live
8
+ * objects so drift could never see the second, and db:pull rendered duplicate consts.
9
+ *
10
+ * The identity spelling is the CATALOG's: `format_type(oid, NULL)` over `proargtypes` —
11
+ * `integer`, `character varying`, `double precision`, `text[]`. The live side reads it
12
+ * straight from pg_proc; the DECLARED side has only what the author typed, so
13
+ * `@everystack/model`'s `normalizeArgType` maps the SQL aliases (`int`, `varchar`,
14
+ * `timestamptz`) onto the same spelling and drops typmods (a function argument carries
15
+ * none — PostgreSQL discards length/precision, so `varchar(20)` and `varchar` are ONE
16
+ * type here).
17
+ *
18
+ * Known limit: a custom type outside the search_path prints QUALIFIED (`api.my_enum`)
19
+ * while a hand-written `arg('x', 'my_enum')` does not, and the two read as different
20
+ * functions. db:pull-rendered args are already catalog-spelled, so this only reaches a
21
+ * hand-authored declaration; the reconciler names the pair loudly rather than diffing it
22
+ * in silence (see planReconcile's spelling-mismatch warning).
23
+ *
24
+ * Pure and database-free — the identity must be computable in db:diff's CI-pure path.
25
+ */
26
+
27
+ import { normalizeArgType } from '@everystack/model';
28
+
29
+ // The spelling itself lives in @everystack/model, next to `arg()` — it is part of the
30
+ // DECLARED vocabulary, and defineModule needs it to tell an overload from a duplicate.
31
+ export { normalizeArgType };
32
+
33
+ /** `api.get_user(integer, text)` — the identity, from the DECLARED argument types. */
34
+ export function functionIdentity(schema: string, name: string, argTypes: readonly string[]): string {
35
+ return `${schema}.${name}(${argTypes.map(normalizeArgType).join(', ')})`;
36
+ }
37
+
38
+ /**
39
+ * Split a function identity into its qualified name and its argument list.
40
+ * `args` is null for a LEGACY identity that carries no signature (a pre-signature
41
+ * provenance row) — callers keep the old rendering for those.
42
+ */
43
+ export function splitFunctionIdentity(identity: string): { qualified: string; args: string | null } {
44
+ const open = identity.indexOf('(');
45
+ if (open === -1 || !identity.endsWith(')')) return { qualified: identity, args: null };
46
+ return { qualified: identity.slice(0, open), args: identity.slice(open + 1, -1) };
47
+ }
48
+
49
+ /** The pre-signature identity of a function — `schema.name`. The provenance upgrade's lookup key. */
50
+ export function legacyFunctionIdentity(identity: string): string {
51
+ return splitFunctionIdentity(identity).qualified;
52
+ }