Skip to content

FMOData: inconsistent error handling for invalid table/field references #147

@eluce2

Description

@eluce2

Summary

When using FMServerConnection with useEntityIds: true, two error scenarios produce inconsistent or unhelpful behavior compared to other error paths (bad credentials, unreachable server, missing record, etc.), which all correctly return { data, error } tuples.

Status (verified against v0.1.0-beta.34 on main)

Both issues are still present as of the current codebase.

Issue 1: Non-existent table throws instead of returning { error }

resolveTableId() in packages/fmodata/src/client/builders/table-utils.ts (line 23) still throws:

throw new Error(`useEntityIds is true but table "${getTableName(table)}" does not have entity IDs configured`);

Call sites (url-builder.ts, query-builder.ts) don't catch this, so .execute() throws instead of returning { error }.

Expected: .execute() should return { error } like all other error conditions.

Issue 2: Standalone field reference in eq() serializes as [object Object]

_operandToString() in packages/fmodata/src/orm/operators.ts falls through to String(value) for non-Column, non-primitive operands. If a field created with textField().entityId(...) is used in a filter via eq() without being part of a table schema, it serializes as [object Object] in the OData URL.

Expected: Either validate at URL-build time that the field reference is resolvable, or catch this at the type level so eq() only accepts fields from a defined table schema.

Reproduction

import { FMServerConnection, fmTableOccurrence, textField, eq } from "@proofkit/fmodata";

const connection = new FMServerConnection({ serverUrl: "...", auth: { username: "...", password: "..." } });
const db = connection.database("SomeFile.fmp12", { useEntityIds: true });

// Issue 1: throws instead of returning { error }
const FakeTable = fmTableOccurrence("NonExistent", {
  id: textField().primaryKey().entityId("FMFID:999999999"),
});
const result1 = await db.from(FakeTable).list().execute(); // throws!

// Issue 2: [object Object] in URL
const looseField = textField().entityId("FMFID:000000001");
const result2 = await db.from(RealTable).list().where(eq(looseField, "test")).execute();
// sends: $filter=[object Object] eq 'test'

Environment

  • @proofkit/fmodata version: 0.1.0-beta.34 (current main)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions