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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions