Custom queries
By default, Kottster manages data fetching internally. You can also define custom fetching logic, such as using raw SQL or extracting data from an external resource.
To do this, pass an executeQuery
function to defineTableController
:
import { TablePage } from '@kottster/react';
import { app } from '../../.server/app';
import dataSource from '../../.server/data-sources/postgres';
export const action = app.defineTableController(dataSource, {
rootTable: {
executeQuery: async () => {
// Fetch data here
const sampleRecords = [
{ id: 1, '[email protected]' },
{ id: 2, '[email protected]' },
{ id: 3, '[email protected]' },
];
// Return the records
return {
records: sampleRecords,
};
},
// Specify the columns to display in the table
columns: [
{ column: 'id' },
{ column: 'email' },
],
},
});
export default () => (
<TablePage />
);
To enabling pagination, pass a pageSize
property and return the totalRecords
property in the executeQuery
function:
export const action = app.defineTableController(dataSource, {
rootTable: {
pageSize: 25,
executeQuery: async ({ page }) => {
return {
records: [/* ... */],
totalRecords: 100
};
},
},
});
To enable CRUD operations and other built-in table features, the table
property must be set:
export const action = app.defineTableController(dataSource, {
rootTable: {
table: 'users',
executeQuery: async () => {
// Fetch data here
const sampleRecords = [
{ id: 1, '[email protected]' },
{ id: 2, '[email protected]' },
{ id: 3, '[email protected]' },
];
// Return the records
return {
records: sampleRecords,
};
},
},
});
executeQuery
-
Arguments:
An object with the following optional properties:
- page (
number
, optional): The current page number, passed if pagination is enabled. - search (
string
, optional): A search term, passed if search is enabled.
- page (
-
Return value:
An object with the following properties:
- records (
array
): An array of records to display in the table. - totalRecords (
number
, optional): The total number of records. Providing this enables pagination.
- records (
Custom SQL query
This example demonstrates how to use a raw SQL query with Knex to fetch data.
Here we extend the existing table configuration to include a custom query for fetching data from a MySQL, PostgreSQL, or SQLite database. The SQL query is executed using Knex's raw
method, which allows for raw SQL execution.
MySQL example
import { TablePage } from '@kottster/react';
import { app } from '../../.server/app';
import dataSource from '../../.server/data-sources/mysql';
import pageSettings from './settings.json';
const pageSize = 25;
export const action = app.defineTableController(dataSource, {
...pageSettings,
rootTable: {
...pageSettings.rootTable,
pageSize,
executeQuery: async ({ page }) => {
const knex = dataSource.adapter.getClient();
const offset = page ? (page - 1) * pageSize : 0;
const [records] = await knex.raw(`
SELECT
id, first_name, email
FROM
users
LIMIT :pageSize OFFSET :offset
`, { pageSize, offset });
const [[{ count: totalRecords }]] = await knex.raw(`
SELECT
COUNT(*) AS count
FROM
users
`);
return {
records,
totalRecords,
}
}
}
});
export default () => (
<TablePage />
);
PostgreSQL example
import { TablePage } from '@kottster/react';
import { app } from '../../.server/app';
import dataSource from '../../.server/data-sources/postgres';
import pageSettings from './settings.json';
const pageSize = 25;
export const action = app.defineTableController(dataSource, {
...pageSettings,
rootTable: {
...pageSettings.rootTable,
pageSize,
executeQuery: async ({ page }) => {
const knex = dataSource.adapter.getClient();
const offset = page ? (page - 1) * pageSize : 0;
const { rows: records } = await knex.raw(`
SELECT
id, first_name, email
FROM
users
LIMIT :pageSize OFFSET :offset
`, { pageSize, offset });
const { rows: [{ count: totalRecords }] } = await knex.raw(`
SELECT
COUNT(*) AS count
FROM
users
`);
return {
records,
totalRecords,
}
}
}
});
export default () => (
<TablePage />
);
Sqlite example
import { TablePage } from '@kottster/react';
import { app } from '../../.server/app';
import dataSource from '../../.server/data-sources/sqlite';
import pageSettings from './settings.json';
const pageSize = 25;
export const action = app.defineTableController(dataSource, {
...pageSettings,
rootTable: {
...pageSettings.rootTable,
pageSize,
executeQuery: async ({ page }) => {
const knex = dataSource.adapter.getClient();
const offset = page ? (page - 1) * pageSize : 0;
const records = await knex.raw(`
SELECT
id, first_name, email
FROM
users
LIMIT :pageSize OFFSET :offset
`, { pageSize, offset });
const [{ count: totalRecords }] = await knex.raw(`
SELECT
COUNT(*) AS count
FROM
users
`);
return {
records,
totalRecords,
}
}
}
});
export default () => (
<TablePage />
);
Please notice that in the examples above, we are using the
raw
method from Knex to execute raw SQL queries. This method has diffirent return for each database adapter. For MySQL, it returns an array of records, while for PostgreSQL, it returns an object with arows
property containing the records.
Custom fetching logic
You can also define completely custom fetching logic. For example, you can fetch data from an external API or a different database.
import { TablePage } from '@kottster/react';
import { app } from '../../.server/app';
import dataSource from '../../.server/data-sources/postgres';
const pageSize = 25;
export const action = app.defineTableController(dataSource, {
rootTable: {
pageSize,
executeQuery: async ({ page }) => {
// Fetch data here
const sampleRecords = [
{ id: 1, '[email protected]' },
{ id: 2, '[email protected]' },
{ id: 3, '[email protected]' },
];
return {
records: sampleRecords,
totalRecords: sampleRecords.length,
}
},
// Specify the columns to display in the table
columns: [
{ column: 'id' },
{ column: 'email' },
],
}
});
export default () => (
<TablePage />
);