feat: campos de usuario por su definición en SAP (valores válidos y tabla de usuario enlazada): endpoint sapdb/user-fields y campo udfField en cabeceras de documentos y maestros
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3caf94609d
commit
0629ce4068
17 files changed
+517
-11
No files matched your search
@@ -0,0 +1,82 @@
|
||||
import type { SapDbAdapter, SapDbEngine } from './sapdb.types.js';
|
||||
|
||||
/** Lo que SAP sabe de un campo de usuario: su tipo, sus valores válidos y la tabla de usuario a la que está enlazado. */
|
||||
export interface UserFieldInfo {
|
||||
table: string;
|
||||
alias: string;
|
||||
description: string;
|
||||
/** Tipo de SAP: `A` alfanumérico, `N` numérico, `D` fecha… */
|
||||
type: string;
|
||||
size: number;
|
||||
/** Valores válidos del campo (vacío si acepta cualquier valor). */
|
||||
validValues: { value: string; description: string }[];
|
||||
/** Tabla de usuario enlazada (`SIS_REGSAN`), si el campo está vinculado a una. */
|
||||
linkedTable: string | null;
|
||||
/** Filas (`Code` y `Name`) de la tabla enlazada. */
|
||||
linkedRows: { code: string; name: string }[];
|
||||
/** La tabla enlazada tiene más filas de las que se entregan. */
|
||||
linkedTruncated: boolean;
|
||||
}
|
||||
|
||||
/** Una tabla de SAP (`OBTN`, `@MI_TABLA`) y el alias de un campo de usuario (`SIS_ESTLOT`, sin el `U_`). */
|
||||
export const TABLE_ID = /^@?[A-Za-z0-9_]{1,30}$/;
|
||||
export const FIELD_ALIAS = /^[A-Za-z0-9_]{1,30}$/;
|
||||
/** Una tabla enlazada se escribe en el SQL entre comillas: solo letras, dígitos y «_». */
|
||||
const LINKED = /^[A-Za-z0-9_]{1,30}$/;
|
||||
|
||||
interface Sql {
|
||||
info: string;
|
||||
values: string;
|
||||
linked: (table: string) => string;
|
||||
}
|
||||
|
||||
/** El SQL de cada motor (`CUFD` define los campos de usuario y `UFD1` sus valores válidos; existen igual en HANA y MSSQL). */
|
||||
const SQL: Record<SapDbEngine, Sql> = {
|
||||
hana: {
|
||||
info: 'SELECT "FieldID", "Descr", "TypeID", "EditSize", "RTable" FROM "CUFD" WHERE "TableID" = ? AND "AliasID" = ?',
|
||||
values: 'SELECT "FldValue", "Descr" FROM "UFD1" WHERE "TableID" = ? AND "FieldID" = ? ORDER BY "IndexID"',
|
||||
linked: (t) => `SELECT "Code", "Name" FROM "@${t}" ORDER BY "Code"`,
|
||||
},
|
||||
};
|
||||
|
||||
const text = (v: unknown): string => (v === null || v === undefined ? '' : String(v));
|
||||
|
||||
/**
|
||||
* Lee de la base la definición de un campo de usuario. Devuelve `null` si el campo no existe. La tabla enlazada sale de
|
||||
* la propia definición del campo (no la elige quien llama), así que no se puede leer una tabla cualquiera.
|
||||
*/
|
||||
export async function readUserField(
|
||||
adapter: SapDbAdapter,
|
||||
engine: SapDbEngine,
|
||||
table: string,
|
||||
alias: string,
|
||||
opts: { timeoutMs: number; maxRows: number },
|
||||
): Promise<UserFieldInfo | null> {
|
||||
const sql = SQL[engine];
|
||||
const [field] = await adapter.query(sql.info, [table, alias], opts);
|
||||
if (!field) return null;
|
||||
const values = await adapter.query(sql.values, [table, field['FieldID']], opts);
|
||||
const linkedTable = text(field['RTable']) || null;
|
||||
let linkedRows: UserFieldInfo['linkedRows'] = [];
|
||||
let linkedTruncated = false;
|
||||
if (linkedTable && LINKED.test(linkedTable)) {
|
||||
try {
|
||||
const rows = await adapter.query(sql.linked(linkedTable), [], opts);
|
||||
linkedTruncated = rows.length > opts.maxRows;
|
||||
linkedRows = rows.slice(0, opts.maxRows).map((r) => ({ code: text(r['Code']), name: text(r['Name']) }));
|
||||
} catch {
|
||||
/* el enlace no es a una tabla de usuario con Code y Name: el campo se trata como de valores libres */
|
||||
}
|
||||
}
|
||||
return {
|
||||
table,
|
||||
alias,
|
||||
description: text(field['Descr']),
|
||||
type: text(field['TypeID']),
|
||||
size: Number(field['EditSize'] ?? 0) || 0,
|
||||
validValues: values.map((v) => ({ value: text(v['FldValue']), description: text(v['Descr']) })),
|
||||
linkedTable,
|
||||
linkedRows,
|
||||
linkedTruncated,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user