Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 7 additions & 24 deletions packages/cubejs-backend-native/test/bridge/args-names.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,51 +29,34 @@ describeBridge('bridge: args_names parser', () => {
});
});

// The skipped tests below assert how a correct parser should behave.
// They are buggy today because both this bridge and the JS-side
// schema-compiler use the same regex; a fix must touch both.
describe('known bugs (skip = expected behavior after fix)', () => {
// The named-function branch of the regex captures [A-Za-z0-9_,]* —
// no whitespace allowed. V8 renders `function f(x, y)` with a space
// after the comma, so capture stops after the first arg.
it.skip('parses named function declaration with multiple args', () => {
describe('edge cases', () => {
it('parses named function declaration with multiple args', () => {
function named(x: any, y: any) {
return [x, y];
}
expect(parseArgsNames(named)).toEqual(['x', 'y']);
});

it.skip('parses async named function declaration with multiple args', () => {
it('parses async named function declaration with multiple args', () => {
async function named(x: any, y: any) {
return [x, y];
}
expect(parseArgsNames(named)).toEqual(['x', 'y']);
});

// Default args land inside the (...) capture as a single token "x = 1"
// and survive the comma split unchanged. Special names like
// SECURITY_CONTEXT in this position fail to dispatch.
it.skip('parses default args, returning just the identifier', () => {
it('parses default args, returning just the identifier', () => {
expect(parseArgsNames((x: any = 1) => x)).toEqual(['x']);
});

// Rest args keep their leading dots after capture+split, yielding
// "...args" instead of "args".
it.skip('parses rest args, dropping the spread dots', () => {
it('parses rest args, dropping the spread dots', () => {
expect(parseArgsNames((...args: any[]) => args)).toEqual(['args']);
});

// Destructuring patterns get split by the comma inside the braces,
// breaking the pattern into half-tokens.
it.skip('parses destructuring args, returning the destructured identifiers', () => {
it('parses destructuring args, returning the destructured identifiers', () => {
expect(parseArgsNames(({ a, b }: any) => [a, b])).toEqual(['a', 'b']);
});

// Anonymous function expressions (`function (x){}`) match no branch
// of the regex at all. Today Rust silently returns []; the JS side
// throws `Can't match args for: ...`. Neither is the desired
// behavior — the parser should just return the args.
it.skip('parses anonymous function expressions', () => {
it('parses anonymous function expressions', () => {
// eslint-disable-next-line func-names, prefer-arrow-callback
const fn = function (x: any) { return x; };
expect(parseArgsNames(fn)).toEqual(['x']);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ describeBridge('bridge: multi-arg dispatch', () => {
);

expect(result.template).toBe(
'SUM({arg:0}) WHERE {fp:0} AND t = {sv:1}'
'SUM({arg:0}) WHERE {fp:0} AND t = {sv:0}'
);
expect(result.args.symbol_paths).toEqual([['CUBE', 'amount']]);
expect(result.args.filter_params).toEqual([
{ cube_name: 'orders', name: 'status', column: 'col' },
]);
expect(result.args.security_context.values).toEqual(['acme', 'acme']);
expect(result.args.security_context.values).toEqual(['acme']);
});

it('throws an internal error from the StubBaseTools when SQL_UTILS is referenced', () => {
Expand Down
38 changes: 12 additions & 26 deletions packages/cubejs-backend-native/test/bridge/result-shape.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,20 @@ describeBridge('bridge: result shape', () => {
expect(result.args.symbol_paths).toEqual([['orders', 'status']]);
});

it('errors when the user function returns a primitive number', () => {
// Bug: bridge eagerly coerces the return value via convert_to_string,
// which only handles JsString and null — it then tries to call
// toString as a struct method, which errors on primitives. JS
// reference returns the value unchanged and lets downstream template
// literals coerce naturally. See skipped 'JS-ref: numeric return…'.
expect(() => compileMemberSql(() => 42 as any)).toThrow(
/Object is not the Struct object/
);
it('coerces a numeric return to its string form', () => {
const integerResult = compileMemberSql(() => 42 as any);
const decimalResult = compileMemberSql(() => 1.5 as any);

expect(integerResult.template).toBe('42');
expect(decimalResult.template).toBe('1.5');
});

it('errors when the user function returns a primitive boolean', () => {
expect(() => compileMemberSql(() => true as any)).toThrow(
/Object is not the Struct object/
);
it('coerces a boolean return to its string form', () => {
const trueResult = compileMemberSql(() => true as any);
const falseResult = compileMemberSql(() => false as any);

expect(trueResult.template).toBe('true');
expect(falseResult.template).toBe('false');
});

it('returns an empty string template when the user function returns null', () => {
Expand All @@ -49,17 +48,4 @@ describeBridge('bridge: result shape', () => {
expect(result.template).toBe('');
expect(result.args.symbol_paths).toEqual([]);
});

// JS reference does no coercion at the bridge boundary — the user
// function's return value flows through resolveSymbolsCall verbatim and
// is later embedded via template literal, which yields String(value).
it.skip('JS-ref: numeric return is coerced to its string form', () => {
const result = compileMemberSql(() => 42 as any);
expect(result.template).toBe('42');
});

it.skip('JS-ref: boolean return is coerced to its string form', () => {
const result = compileMemberSql(() => true as any);
expect(result.template).toBe('true');
});
});
Loading
Loading