Spatial
foundry spatial works with Geometry/Geography column data from a table. It has three subcommands: view plots Point values on a terminal canvas for a quick visual check, export writes the full geometry plus other column values to a GeoJSON file for use in a GIS tool or web map, and import reads a GeoJSON file back into a table.
foundry spatial view [options]
foundry spatial export [options]
foundry spatial import [options]
View
foundry spatial view plots Point values from a Geometry or Geography column directly in the terminal, using a character-cell canvas. It's useful for a quick "where are my points" sanity check on spatial data without opening a GIS tool.
foundry spatial view [options]
Options
| Option | Short | Description |
|---|---|---|
--datasource <FILE> |
-d |
Datasource JSON file |
--conn <STRING> |
-c |
ADO.NET connection string |
--db <TYPE> |
-b |
Database engine type |
--schema <NAME> |
-s |
Name of the schema containing the table (required) |
--table <NAME> |
-t |
Name of the table containing the spatial column (required) |
--geo-column <COLUMN> |
-g |
Name of the Geometry or Geography column to plot (required) |
--limit <N> |
-l |
Maximum number of rows to fetch and plot (default: 2000) |
--width <N> |
-W |
Canvas width in characters (default: current terminal width, or 80 if not running in a terminal) |
--height <N> |
-H |
Canvas height in characters (default: current terminal height minus three lines for the status/summary output, or 40 if not running in a terminal) |
--log-config <FILE> |
-L |
Log configuration file |
--verbose |
-v |
Print SQL as it executes |
Examples
# Plot a Geometry column
foundry spatial view --datasource connection.json --schema public --table locations --geo-column geom
# Plot a Geography column with a larger canvas
foundry spatial view \
--datasource SqlServer_16.0.json \
--schema dbo --table sites --geo-column geog \
--limit 5000 --width 100 --height 50
# Inline connection string
foundry spatial view \
--conn "Server=localhost;Database=mydb;User Id=sa;Password=pass" \
--db SQLServer \
--schema dbo --table sites --geo-column geog
Sample output:
▀
▄▀▄ ▀ ▀ ▀
▄ ▄
▄ ▄ ▄ ▄ ▄ ▄▄▄▄▄ ▄ ▀ ▀▄ ▀
▄▀ ▀ ▄ ▄ ▀▀▀ ▀ ▄ ▄▀ ▀▄ ▄ ▄
▄ ▀ ▀ ▄ ▀ ▀ ▄ ▀ ▄ ▄ ▄ ▄ ▀
X: -124.0321 to -121.1789 Y: 36.2002 to 38.2875 | 151 points plotted, 30 null or non-point values skipped
How Points Are Plotted
For each row, Foundry reads the value of --geo-column and extracts its coordinate. The full result set's bounding box (min/max X and Y) is computed first, then every point is normalized into that range and mapped onto the canvas — so the plot always fills the requested --width/--height regardless of the data's real-world scale. The Y axis is flipped so that higher latitude/Y values render toward the top, matching how a map normally looks.
The axis range printed beneath the canvas (X: ... to ... Y: ... to ...) is the bounding box of the plotted points only, not the column's full domain — useful for sanity-checking how spread out your data actually is.
If a table has fewer than two distinct X or Y values (e.g. every point shares the same longitude), Foundry pads the range slightly so the plot doesn't divide by zero — you'll see a single column or row of points rather than a crash.
Polygons and Lines Are Not Plotted
foundry spatial view only plots Point geometries. Any row whose geometry is a Polygon, LineString, MultiPoint, MultiPolygon, or other non-Point type is skipped entirely — it is not approximated by its centroid or first vertex, just left out of the plot. Skipped rows (along with NULL values in the column) are counted and reported together at the end, alongside the axis range, on a single line below the canvas:
X: -124.0321 to -121.1789 Y: 36.2002 to 38.2875 | 151 points plotted, 30 null or non-point values skipped
If every row in the result set is non-Point (or NULL), no canvas is drawn at all — Foundry prints No point geometries found to plot. and exits cleanly with status 0, rather than rendering an empty canvas.
Note
Rendering LineString/Polygon geometries as actual shapes — rather than skipping them — would require rasterizing line and polygon edges onto the canvas (Foundry's canvas only supports setting individual points), which foundry spatial view does not currently do. If your column is mixed-geometry and you specifically want polygon/line boundaries preserved, use foundry spatial export to write the full geometry to a GeoJSON file instead.
Choosing --limit
The canvas has a fixed resolution (--width × --height character cells), so plotting more points than there are cells mostly just slows down the query without improving the picture — multiple points landing in the same cell simply overwrite each other. The default --limit of 2000 is a reasonable balance for most tables; raise it for a denser sample, or lower it for a faster preview on a very large table.
Canvas Sizing
When --width/--height are omitted, Foundry sizes the canvas to fill the current terminal — the whole plot fits on screen without scrolling. Height is set three lines short of the terminal's full height, leaving room for the status line printed while fetching, the axis-range/summary line printed below the canvas, and the shell prompt line that follows. When output isn't a terminal (piped to a file, redirected in a script, or run in CI), Foundry falls back to a fixed 80×40 canvas instead, since there's no real terminal size to read. Pass --width/--height explicitly to override either default.
Export
foundry spatial export exports the geometry/geography data and other column values from a table to a GeoJSON file, ready to load into a GIS tool, web map, or another system that consumes GeoJSON.
foundry spatial export [options]
Options
| Option | Short | Description |
|---|---|---|
--datasource <FILE> |
-d |
Datasource JSON file |
--conn <STRING> |
-c |
ADO.NET connection string |
--db <TYPE> |
-b |
Database engine type |
--schema <NAME> |
-s |
Name of the schema containing the table (required) |
--table <NAME> |
-t |
Name of the table containing the spatial column (required) |
--geo-column <COLUMN> |
-g |
Name of the Geometry or Geography column to export (required) |
--id-column <COLUMN> |
-i |
Name of the column promoted to each GeoJSON Feature's top-level id (default: a column literally named id, if present) |
--property-columns <COLUMNS> |
-p |
Comma-separated list of columns to include as GeoJSON feature properties (default: all columns) |
--format <FORMAT> |
-F |
Output format (default: GeoJson, currently the only supported value) |
--out <FILE> |
-o |
Output file path (required) |
--log-config <FILE> |
-L |
Log configuration file |
--verbose |
-v |
Print SQL as it executes |
Examples
# Export every column as GeoJSON properties
foundry spatial export \
--datasource connection.json \
--schema public --table locations --geo-column geom \
--out locations.geojson
# Promote a column to the Feature's top-level "id"
foundry spatial export \
--datasource SqlServer_16.0.json \
--schema dbo --table sites --geo-column geog \
--id-column SiteID --out sites.geojson
# Limit which columns become properties
foundry spatial export \
--datasource SqlServer_16.0.json \
--schema dbo --table sites --geo-column geog \
--property-columns "Name,Category" --out sites.geojson
# Inline connection string
foundry spatial export \
--conn "Server=localhost;Database=mydb;User Id=sa;Password=pass" \
--db SQLServer \
--schema dbo --table sites --geo-column geog \
--out sites.geojson
How Export Works
Foundry queries the table for the geometry/geography column plus whichever other columns are selected, then streams the result set to the output file as a GeoJSON FeatureCollection — one row at a time, so memory use stays flat regardless of table size. Each row becomes one GeoJSON Feature: the value of --geo-column becomes the Feature's geometry, and every other selected column becomes an entry in the Feature's properties object.
Unlike foundry spatial view, which only handles Point values, spatial export supports any geometry type — Point, LineString, Polygon, and their Multi* counterparts all export correctly, since GeoJSON itself can represent all of them.
Choosing Properties
By default, every column in the table is included as a GeoJSON property. Use --property-columns to export only specific columns — useful for large tables where most columns aren't relevant to the map/GIS use case:
foundry spatial export --datasource connection.json --schema public --table locations --geo-column geom \
--property-columns "name,category,last_updated"
--geo-column is always included in the query regardless of --property-columns (it becomes the Feature's geometry, not a property). If --id-column is specified, it's likewise always included even if omitted from --property-columns.
Feature IDs
GeoJSON Features can carry an optional top-level id alongside their properties. By default, Foundry looks for a column literally named id (exact case) among the selected properties and promotes it automatically. Use --id-column to promote a different column instead — matched against the exact column name as it appears in the table:
foundry spatial export --datasource connection.json --schema dbo --table sites --geo-column geog \
--id-column SiteID --out sites.geojson
The promoted column is removed from properties once promoted — it appears only as the Feature's top-level id, not duplicated in both places.
Import
foundry spatial import reads a GeoJSON file — such as one written by foundry spatial export — back into a table, writing each Feature's geometry to a Geometry/Geography column and its properties to matching columns.
foundry spatial import [options]
Options
| Option | Short | Description |
|---|---|---|
--datasource <FILE> |
-d |
Datasource JSON file |
--conn <STRING> |
-c |
ADO.NET connection string |
--db <TYPE> |
-b |
Database engine type |
--schema <NAME> |
-s |
Name of the schema containing the target table (required) |
--table <NAME> |
-t |
Name of the target table (required) |
--file <FILE> |
-f |
Path to the GeoJSON file to import (required) |
--geo-column <COLUMN> |
-g |
Name of the Geometry or Geography column that receives each feature's geometry (required) |
--id-column <COLUMN> |
-i |
Name of the column that receives each feature's top-level id (default: id is not imported) |
--property-columns <COLUMNS> |
-p |
Comma-separated list of table columns to map from a feature property of the same name (default: every non-autogenerated column except --geo-column/--id-column) |
--import-config <FILE> |
-I |
Path to a geojson-import-config JSON file with explicit property mappings and format/identity/full-text settings. Cannot be used with --property-columns; overrides every option below |
--date-format-type <TYPE> |
-T |
Iso or Culture (default: Iso) |
--number-separator <STRING> |
-S |
Thousands separator to strip from numeric property values before parsing, e.g. , for values like 1,450 (default: none) |
--keep-identity |
-k |
Insert identity/auto-increment values from feature properties as-is rather than letting the database generate them |
--no-full-text-update |
-u |
Skip updating full-text indexes after import completes |
--date-format <FORMAT> |
-a |
Date format string (default: yyyy-MM-dd) |
--time-format <FORMAT> |
-m |
Time format string (default: HH:mm:ss) |
--interval-format <FORMAT> |
-N |
Interval/TimeSpan format string (default: c) |
--datetime-format <FORMAT> |
-y |
DateTime format string (default: yyyy-MM-dd HH:mm:ss) |
--timestamp-format <FORMAT> |
-Y |
DateTimeOffset timestamp format string (default: yyyy-MM-dd HH:mm:ss zzz) |
--stream |
-r |
Stream the import instead of loading the whole file into memory first |
--log-config <FILE> |
-L |
Log configuration file |
--verbose |
-v |
Print SQL as it executes |
All options other than --schema/--table/--file/--geo-column/--id-column/--property-columns/--import-config/--stream come directly from Velocity's ImportConfig class, which GeoJSONImportConfig inherits — they behave identically to their foundry import table (CSV) counterparts.
Examples
# Import every matching property automatically
foundry spatial import \
--datasource connection.json \
--schema public --table locations --file locations.geojson --geo-column geom
# Promote a feature's top-level "id" into a column
foundry spatial import \
--datasource SqlServer_16.0.json \
--schema dbo --table sites --file sites.geojson --geo-column geog \
--id-column SiteID
# Limit which properties are mapped
foundry spatial import \
--datasource SqlServer_16.0.json \
--schema dbo --table sites --file sites.geojson --geo-column geog \
--property-columns "Name,Category"
# Explicit mappings via a geojson-import-config file
foundry spatial import \
--datasource SqlServer_16.0.json \
--schema dbo --table sites --file sites.geojson --geo-column geog \
--import-config sites-import.json
# Inline connection string
foundry spatial import \
--conn "Server=localhost;Database=mydb;User Id=sa;Password=pass" \
--db SQLServer \
--schema dbo --table sites --file sites.geojson --geo-column geog
How Property Mapping Works
By default, spatial import maps every non-autogenerated column in the table (other than --geo-column and --id-column) to a feature property of the same name — the GeoJSON equivalent of the automatic header mapping foundry import table uses for CSV files. Autogenerated (identity) columns are skipped unless --keep-identity is set, exactly as for a CSV import. A feature missing a given property, or one whose value doesn't resolve along a nested path, simply leaves that column unset (NULL) for that row rather than failing the import. Use --property-columns to restrict automatic mapping to specific columns, or --import-config to specify explicit property → column mappings — including nested property paths, e.g. address.city, or a property name that differs from the column name. --import-config and --property-columns are mutually exclusive.
An import config file (validated against schemas/geojson-import-config.schema.json) covers everything the CLI format/identity/full-text flags cover, plus explicit mappings:
{
"$schema": "schemas/geojson-import-config.schema.json",
"dateFormatType": "Iso",
"keepIdentity": false,
"updateFullTextIndex": true,
"properties": [
{ "property": "name", "column": "Name" },
{ "property": "address.city", "column": "City" }
]
}
Geometry and Id Columns
--geo-column must reference a Geometry or Geography column — every Feature's geometry is written there using that column's data type. --id-column, when given, receives the Feature's top-level id (the counterpart of --id-column on foundry spatial export); Features without an id leave that column unset.
Supported GeoJSON Documents
Every object GeoJSON allows at the top level is accepted, not just a FeatureCollection:
| Document | Rows imported |
|---|---|
FeatureCollection |
One per feature |
Feature |
One |
Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection |
One |
A bare geometry document has neither an id nor properties, so only --geo-column receives anything — every other mapped column imports as NULL for that row. A top-level JSON array, or an object whose type isn't one of the above, is rejected.
Note
DB2 cannot store a GeometryCollection, so a document of that type can't be imported there — that's a property of DB2 itself, and applies equally to a CSV import of the same shape.
Streaming Large Files
--stream behaves exactly like foundry import table's --stream: the file is read and sent to the database in chunks (sized by the datasource's importBatchSize setting) instead of being parsed into memory whole, with no change to the rows imported or their order.
Limitations
- Arrays are not supported. A property holding an array, or a path that runs through one, imports as
NULL. Only nested objects can be traversed with a dottedpropertypath. String,Query,Expression, andGuidcolumns cannot be targeted. These aren't real storage types in Velocity — they're used elsewhere in the framework for query construction — so--geo-column/--id-column/property mappings must resolve to an actual column type instead.- GeoJSON import requires the Full Edition of Velocity (not the free Community Edition). Foundry always ships against a Full Edition package, so this only matters if you're building Foundry yourself against a different Velocity reference.