Grounding
Configure database introspection to provide rich context for SQL generation
Grounding is Text2SQL's database introspection system. It extracts schema metadata, statistics, and relationships from your database to give the AI rich context for generating accurate SQL queries.
Why Grounding Matters
Without grounding, the AI would need to guess table names, column types, and relationships. Grounding provides:
- Schema awareness - Tables, columns, and their types
- Relationship mapping - Foreign keys and join paths
- Performance hints - Indexes, row counts, and size classifications
- Data patterns - Low cardinality values (enums) and column statistics
Quick Start
Each database adapter (PostgreSQL, SQLite, SQL Server, MySQL/MariaDB) exports grounding factory functions. Import them and pass to your adapter:
Reuse the shared model setup from
Getting Started in the examples below.
import { Text2Sql } from '@deepagents/text2sql';
import { Postgres } from '@deepagents/text2sql/postgres';
import * as postgres from '@deepagents/text2sql/postgres';
const text2sql = new Text2Sql({
version: 'v1',
model,
adapters: {
main: new Postgres({
execute: async (sql) => pool.query(sql).then(r => r.rows),
grounding: [
postgres.tables(),
postgres.views(),
postgres.info(),
postgres.indexes(),
postgres.constraints(),
postgres.rowCount(),
postgres.columnStats(),
postgres.columnValues(),
],
}),
},
});import { Text2Sql } from '@deepagents/text2sql';
import { Sqlite } from '@deepagents/text2sql/sqlite';
import * as sqlite from '@deepagents/text2sql/sqlite';
const text2sql = new Text2Sql({
version: 'v1',
model,
adapters: {
main: new Sqlite({
execute: (sql) => db.prepare(sql).all(),
grounding: [
sqlite.tables(),
sqlite.views(),
sqlite.info(),
sqlite.indexes(),
sqlite.constraints(),
sqlite.rowCount(),
sqlite.columnStats(),
sqlite.columnValues(),
],
}),
},
});import { Text2Sql } from '@deepagents/text2sql';
import { SqlServer } from '@deepagents/text2sql/sqlserver';
import * as sqlserver from '@deepagents/text2sql/sqlserver';
const text2sql = new Text2Sql({
version: 'v1',
model,
adapters: {
main: new SqlServer({
execute: async (sql) => {
const result = await pool.request().query(sql);
return result.recordset;
},
grounding: [
sqlserver.tables(),
sqlserver.views(),
sqlserver.info(),
sqlserver.indexes(),
sqlserver.constraints(),
sqlserver.rowCount(),
sqlserver.columnStats(),
sqlserver.columnValues(),
],
}),
},
});import { Text2Sql } from '@deepagents/text2sql';
import { Mysql } from '@deepagents/text2sql/mysql';
import * as mysqlGrounding from '@deepagents/text2sql/mysql';
const text2sql = new Text2Sql({
version: 'v1',
model,
adapters: {
main: new Mysql({
execute: async (sql) => {
const [rows] = await pool.query(sql);
return rows;
},
grounding: [
mysqlGrounding.tables(),
mysqlGrounding.views(),
mysqlGrounding.info(),
mysqlGrounding.indexes(),
mysqlGrounding.constraints(),
mysqlGrounding.rowCount(),
mysqlGrounding.columnStats(),
mysqlGrounding.columnValues(),
],
}),
},
});import { BigQuery as BigQueryClient } from '@google-cloud/bigquery';
import { Text2Sql } from '@deepagents/text2sql';
import { BigQuery } from '@deepagents/text2sql/bigquery';
import * as bigquery from '@deepagents/text2sql/bigquery';
const client = new BigQueryClient({ projectId: process.env.BQ_PROJECT_ID });
const text2sql = new Text2Sql({
version: 'v1',
model,
adapters: {
main: new BigQuery({
projectId: process.env.BQ_PROJECT_ID,
datasets: ['analytics'],
execute: async (sql) => {
const [job] = await client.createQueryJob({ query: sql });
const [rows] = await job.getQueryResults();
return rows;
},
validate: async (sql) => {
await client.createQueryJob({ query: sql, dryRun: true, useQueryCache: false });
},
grounding: [
bigquery.tables(),
bigquery.views(),
bigquery.info(),
bigquery.indexes(),
bigquery.constraints(),
bigquery.rowCount(),
],
}),
},
});Available Groundings
Core Groundings
These groundings discover your database structure:
tables(config?)
Discovers tables and their relationships via foreign key traversal. This is the foundational grounding that other groundings depend on.
tables({
// Filter tables - array of names, regex, or predicate function
filter: ['users', 'orders', 'products'],
// or
filter: /^app_/,
// or
filter: (name) => !name.startsWith('_'),
// Traverse forward (child → parent) following FK direction
// true = unlimited depth, number = max depth
forward: 2,
// Traverse backward (parent → child) finding referencing tables
backward: 1,
})| Option | Type | Description |
|---|---|---|
filter | string[] | RegExp | (name: string) => boolean | Select which tables to include |
forward | boolean | number | Follow FKs from child to parent tables |
backward | boolean | number | Find tables that reference these tables |
views(config?)
Discovers database views and their columns.
views({
// Same filter options as tables()
filter: ['active_users', 'sales_summary'],
})info()
Collects database dialect, version, and connection info. Helps the AI understand database-specific SQL syntax.
info()
// Returns: { dialect: 'postgresql', version: '15.0', database: 'mydb' }Metadata Groundings
These groundings enhance the schema with performance-relevant metadata. They run after tables() and annotate the discovered tables.
indexes()
Marks which columns have indexes. Helps the AI generate queries that use indexed columns for filtering and sorting.
indexes()
// Annotates columns with isIndexed: trueconstraints()
Collects CHECK, UNIQUE, NOT NULL, DEFAULT, PRIMARY KEY, and FOREIGN KEY constraints.
constraints()
// Annotates tables with constraint informationrowCount()
Counts rows per table and classifies by size. Helps the AI avoid expensive full table scans on large tables.
rowCount()
// Annotates tables with rowCount and sizeHintSize classifications:
| Size Hint | Row Count |
|---|---|
| tiny | < 100 |
| small | 100 - 999 |
| medium | 1,000 - 9,999 |
| large | 10,000 - 99,999 |
| huge | >= 100,000 |
columnStats()
Collects min/max values and null fraction for numeric and date columns.
columnStats()
// Annotates columns with stats: { min, max, nullFraction }columnValues()
Detects enum-like and low-cardinality columns (like status, type, or category columns) and caches their values.
columnValues()
// Annotates columns with kind: 'LowCardinality' and values: ['active', 'inactive', ...]Execution Order
Groundings execute in the order you specify. Some groundings depend on others:
tables()must run first - discovers the base schemaviews()can run independentlyinfo()can run independentlyindexes(),constraints(),rowCount()- run aftertables(), annotate discovered tablescolumnStats(),columnValues()- run aftertables(), annotate columns
Filtering Tables
All filter options work the same way across tables() and views():
// Include specific tables by name
tables({ filter: ['users', 'orders', 'products'] })
// Include tables matching a pattern
tables({ filter: /^public\./ })
// Custom predicate
tables({ filter: (name) => !name.includes('_archive') })Relationship Traversal
The forward and backward options control how tables() discovers related tables:
// Start with 'orders' and follow FKs to find 'users', 'products', etc.
tables({
filter: ['orders'],
forward: 2, // Follow FKs up to 2 levels deep
})
// Start with 'users' and find all tables that reference it
tables({
filter: ['users'],
backward: 1, // Find immediate children only
})
// Both directions
tables({
filter: ['orders'],
forward: true, // Unlimited forward traversal
backward: true, // Unlimited backward traversal
})Minimal Configuration
For simple use cases, you can use a minimal grounding setup:
import * as postgres from '@deepagents/text2sql/postgres';
grounding: [
postgres.tables(),
postgres.info(),
]import * as sqlite from '@deepagents/text2sql/sqlite';
grounding: [
sqlite.tables(),
sqlite.info(),
]import * as sqlserver from '@deepagents/text2sql/sqlserver';
grounding: [
sqlserver.tables(),
sqlserver.info(),
]import * as mysqlGrounding from '@deepagents/text2sql/mysql';
grounding: [
mysqlGrounding.tables(),
mysqlGrounding.info(),
]import * as bigquery from '@deepagents/text2sql/bigquery';
grounding: [
bigquery.tables(),
bigquery.info(),
]Empty Grounding
Pass an empty array to disable all automatic introspection:
grounding: []This is useful when providing custom introspection via the adapter's introspect option.
Next Steps
- PostgreSQL Adapter - PostgreSQL-specific configuration
- SQLite Adapter - SQLite-specific configuration
- SQL Server Adapter - SQL Server-specific configuration
- MySQL/MariaDB Adapter - MySQL and MariaDB-specific configuration
- BigQuery Adapter - BigQuery-specific configuration
- Teach the System - Add domain knowledge