Repository: directus/directus
File: api/src/database/run-ast/lib/apply-query/filter/operator.test.ts (TypeScript)

Code before:
				c.field('likes').integer();
				c.field('links').o2m('links', 'article_id');
			})
			.build();

		const db = vi.mocked(knex.default({ client: Client_SQLite3 }));
		const queryBuilder = db.queryBuilder();

		applyOperator(db, queryBuilder, schema, field, operator, value);

		const rawQuery = queryBuilder.toSQL();

		expect(rawQuery.sql).toEqual(sql);
		expect(rawQuery.bindings).toEqual(bindings);
	});
}

test('applyOperator throws InvalidQueryError for non-numeric value on function-based numeric field', async () => {
	const schema = new SchemaBuilder()
		.collection('articles', (c) => {
			c.field('id').id();
			c.field('title').string();
			c.field('likes').integer();
			c.field('links').o2m('links', 'article_id');
		})
		.build();

	const db = vi.mocked(knex.default({ client: Client_SQLite3 }));
	const queryBuilder = db.queryBuilder();

	expect(() => applyOperator(db, queryBuilder, schema, 'articles.count(links)', '_eq', 'not-a-number')).toThrow(
		InvalidQueryError,
	);
});

test('applyOperator throws InvalidQueryError for non-numeric array value on function-based numeric field', async () => {
	const schema = new SchemaBuilder()
		.collection('articles', (c) => {
			c.field('id').id();
			c.field('title').string();
			c.field('likes').integer();
			c.field('links').o2m('links', 'article_id');
		})
		.build();

	const db = vi.mocked(knex.default({ client: Client_SQLite3 }));
	const queryBuilder = db.queryBuilder();

	expect(() => applyOperator(db, queryBuilder, schema, 'articles.count(links)', '_eq', ['abc', '123'])).toThrow(
		InvalidQueryError,
	);

Review comment (refactor):
Instead of having duplicate schemas for each test, we should move the schema top level and reuse it.

Code after:
		sql: `select * where "articles"."likes" = ?`,
		bindings: [[]],
	},
]) {
	test(`applyOperator on ${field} ${operator} ${value}`, async () => {
		const db = vi.mocked(knex.default({ client: Client_SQLite3 }));
		const queryBuilder = db.queryBuilder();

		applyOperator(db, queryBuilder, schema, field, operator, value);

		const rawQuery = queryBuilder.toSQL();

		expect(rawQuery.sql).toEqual(sql);
		expect(rawQuery.bindings).toEqual(bindings);
	});
}

test('applyOperator throws InvalidQueryError for non-numeric value on function-based numeric field', async () => {
	const db = vi.mocked(knex.default({ client: Client_SQLite3 }));
	const queryBuilder = db.queryBuilder();

	expect(() => applyOperator(db, queryBuilder, schema, 'articles.count(links)', '_eq', 'not-a-number')).toThrow(
		InvalidQueryError,
	);
});

test('applyOperator throws InvalidQueryError for non-numeric array value on function-based numeric field', async () => {
	const db = vi.mocked(knex.default({ client: Client_SQLite3 }));
	const queryBuilder = db.queryBuilder();

	expect(() => applyOperator(db, queryBuilder, schema, 'articles.count(links)', '_eq', ['abc', '123'])).toThrow(
		InvalidQueryError,
	);
});

test('applyOperator throws InvalidQueryError for non-numeric value on integer field', async () => {
	const db = vi.mocked(knex.default({ client: Client_SQLite3 }));
	const queryBuilder = db.queryBuilder();

	expect(() => applyOperator(db, queryBuilder, schema, 'articles.likes', '_eq', 'not-a-number')).toThrow(
		InvalidQueryError,
	);
});

test('applyOperator throws InvalidQueryError for non-numeric array value on integer field', async () => {
	const db = vi.mocked(knex.default({ client: Client_SQLite3 }));
	const queryBuilder = db.queryBuilder();

	expect(() => applyOperator(db, queryBuilder, schema, 'articles.likes', '_eq', ['abc', '123'])).toThrow(
		InvalidQueryError,
	);