Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type mismatch between Field and Ref #366

Open
willium opened this issue Apr 29, 2024 · 0 comments
Open

Type mismatch between Field and Ref #366

willium opened this issue Apr 29, 2024 · 0 comments

Comments

@willium
Copy link
Member

willium commented Apr 29, 2024

I've using Mosaic from within TypeScript so I authored some type declarations.

I don't stand by their correctness, but in the process of doing so, I noticed a type mismatch that might lead to bugs.

Coordinator calls a client's fields() method, and expects the client to return an array of objects with roughly this type:

	export interface Field {
		table: string;
		column: string;
		stats?: Set<keyof typeof Stats> | (keyof typeof Stats)[];
	}

As you can see here:

const fields = client.fields();
if (fields?.length) {
client.fieldInfo(await queryFieldInfo(this, fields));
}

and here:

export async function queryFieldInfo(mc, fields) {
if (fields.length === 1 && `${fields[0].column}` === '*') {
return getTableInfo(mc, fields[0].table);
} else {
return (await Promise
.all(fields.map(f => getFieldInfo(mc, f))))
.filter(x => x);
}
}

and here:

async function getTableInfo(mc, table) {
const result = await mc.query(`DESCRIBE ${asRelation(table)}`);
return Array.from(result).map(desc => ({
table,
column: desc.column_name,
sqlType: desc.column_type,
type: jsType(desc.column_type),
nullable: desc.null === 'YES'
}));
}


However, in some of the clients, like Table, the fields method implementation looks like this:

fields() {
return this.columns.map(name => column(this.from, name));
}

which uses this method on Ref that returns a new instance of Ref:

export function column(table, column = null) {
if (arguments.length === 1) {
column = table;
table = null;
}
return new Ref(table, column);
}

However, Ref does not require that the table and column properties are non-null, as you can see in the toString() method:

toString() {
const { table, column } = this;
if (column) {
const col = column.startsWith('*') ? column : `"${column}"`;
return `${table ? `${quoteTableName(table)}.` : ''}${col}`;
} else {
return table ? quoteTableName(table) : 'NULL';
}
}
}

So, in cases like this where we use a Ref as if it implemented Field without any checks, we might end up using null as if it were a string.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant