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
Spatial support for PostgreSQL using PostGIS #2423
Changes from 10 commits
1e20c6b
b371c06
a266a5a
c51dfcc
cfbea13
84e9386
0d8b343
ce94295
430b8cd
f935457
bcae80f
61f64d2
7893c66
4a5c7ec
c8b87c8
e1f6aa4
53e2b36
2e069ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
* Options for spatial columns. | ||
*/ | ||
export interface SpatialColumnOptions { | ||
|
||
/** | ||
* Column type's feature type. | ||
* Geometry, Point, Polygon, etc. | ||
*/ | ||
spatialFeatureType?: string; | ||
|
||
/** | ||
* Column type's SRID. | ||
* Spatial Reference ID or EPSG code. | ||
*/ | ||
srid?: number; | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -145,13 +145,18 @@ export class PostgresDriver implements Driver { | |
"numrange", | ||
"tsrange", | ||
"tstzrange", | ||
"daterange" | ||
"daterange", | ||
"geometry", | ||
"geography" | ||
]; | ||
|
||
/** | ||
* Gets list of spatial column data types. | ||
*/ | ||
spatialTypes: ColumnType[] = []; | ||
spatialTypes: ColumnType[] = [ | ||
"geometry", | ||
"geography" | ||
]; | ||
|
||
/** | ||
* Gets list of column data types that support length by a driver. | ||
|
@@ -283,7 +288,10 @@ export class PostgresDriver implements Driver { | |
const hasHstoreColumns = this.connection.entityMetadatas.some(metadata => { | ||
return metadata.columns.filter(column => column.type === "hstore").length > 0; | ||
}); | ||
if (hasUuidColumns || hasCitextColumns || hasHstoreColumns) { | ||
const hasGeometryColumns = this.connection.entityMetadatas.some(metadata => { | ||
return metadata.columns.filter(column => this.spatialTypes.indexOf(column.type) >= 0).length > 0; | ||
}); | ||
if (hasUuidColumns || hasCitextColumns || hasHstoreColumns || hasGeometryColumns) { | ||
await Promise.all([this.master, ...this.slaves].map(pool => { | ||
return new Promise((ok, fail) => { | ||
pool.connect(async (err: any, connection: any, release: Function) => { | ||
|
@@ -307,6 +315,12 @@ export class PostgresDriver implements Driver { | |
} catch (_) { | ||
logger.log("warn", "At least one of the entities has hstore column, but the 'hstore' extension cannot be installed automatically. Please install it manually using superuser rights"); | ||
} | ||
if (hasGeometryColumns) | ||
try { | ||
await this.executeQuery(connection, `CREATE EXTENSION IF NOT EXISTS "postgis"`); | ||
} catch (_) { | ||
logger.log("warn", "At least one of the entities has a geometry column, but the 'postgis' extension cannot be installed automatically. Please install it manually using superuser rights"); | ||
} | ||
release(); | ||
ok(); | ||
}); | ||
|
@@ -370,7 +384,7 @@ export class PostgresDriver implements Driver { | |
|| columnMetadata.type === "timestamp without time zone") { | ||
return DateUtils.mixedDateToDate(value); | ||
|
||
} else if (columnMetadata.type === "json" || columnMetadata.type === "jsonb") { | ||
} else if (this.spatialTypes.concat(["json", "jsonb"]).indexOf(columnMetadata.type) >= 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. previous one was better =) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. waits for Local style should be: } else if (columnMetadata.type === "json" ||
columnMetadata.type === "jsonb" ||
this.spatialTypes.indexOf(columnMetadata.type) >= 0) { ❓ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, thats fine as well, you can keep it. I simply don't like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, right, I always forget about spreads in this context. |
||
return JSON.stringify(value); | ||
|
||
} else if (columnMetadata.type === "hstore") { | ||
|
@@ -622,6 +636,14 @@ export class PostgresDriver implements Driver { | |
|
||
} else if (column.type === "timestamp with time zone") { | ||
type = "TIMESTAMP" + (column.precision !== null && column.precision !== undefined ? "(" + column.precision + ")" : "") + " WITH TIME ZONE"; | ||
} else if (this.spatialTypes.indexOf(column.type as ColumnType) >= 0) { | ||
if (column.spatialFeatureType != null && column.srid != null) { | ||
type = `${column.type}(${column.spatialFeatureType},${column.srid})`; | ||
} else if (column.spatialFeatureType != null) { | ||
type = `${column.type}(${column.spatialFeatureType})`; | ||
} else { | ||
type = column.type; | ||
} | ||
} | ||
|
||
if (column.isArray) | ||
|
@@ -699,7 +721,9 @@ export class PostgresDriver implements Driver { | |
|| tableColumn.isNullable !== columnMetadata.isNullable | ||
|| tableColumn.isUnique !== this.normalizeIsUnique(columnMetadata) | ||
|| (tableColumn.enum && columnMetadata.enum && !OrmUtils.isArraysEqual(tableColumn.enum, columnMetadata.enum)) | ||
|| tableColumn.isGenerated !== columnMetadata.isGenerated; | ||
|| tableColumn.isGenerated !== columnMetadata.isGenerated | ||
|| (tableColumn.spatialFeatureType || "").toLowerCase() !== (columnMetadata.spatialFeatureType || "").toLowerCase() | ||
|| tableColumn.srid !== columnMetadata.srid; | ||
}); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess somebody else can easily create a PR for the feature with specific extension and put another docker image with that extension, but without gis let's say. So better solution would be to have a base postgres image with all modifications applied
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed.
mdillon/postgis
is justpostgres
+ PostGIS (pretty sure it doesn't include any other additional extensions). Is this worth punting on until someone else needs to add another extension? (We can add a note/apology here ;-)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha yeah... I hope it won't be me 😆