mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-06 14:09:25 +08:00
feat: support GEOGRAPHY
This commit is contained in:
parent
d49d841bd8
commit
ac6bbfa44e
@ -923,7 +923,7 @@ export class Collection<
|
|||||||
public getTableNameWithSchemaAsString() {
|
public getTableNameWithSchemaAsString() {
|
||||||
const tableName = this.model.tableName;
|
const tableName = this.model.tableName;
|
||||||
|
|
||||||
if (this.collectionSchema() && (this.db.inDialect('postgres') || this.db.inDialect('mssql'))) {
|
if (this.collectionSchema() && this.db.inDialect('postgres', 'mssql')) {
|
||||||
return `${this.collectionSchema()}.${tableName}`;
|
return `${this.collectionSchema()}.${tableName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ export class MagicAttributeModel extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async save(options?: SaveOptions<any>) {
|
async save(options?: SaveOptions<any>) {
|
||||||
if (!options.hooks) {
|
if (!options?.hooks) {
|
||||||
this.db.emit('magicAttributeModel.beforeSave', this, options);
|
this.db.emit('magicAttributeModel.beforeSave', this, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +531,7 @@ describe('dumper', () => {
|
|||||||
await db.getRepository('collections').create({
|
await db.getRepository('collections').create({
|
||||||
values: {
|
values: {
|
||||||
name: 'tests',
|
name: 'tests',
|
||||||
sql: `select count(*) as count
|
sql: `select 1 as id,count(*) as count
|
||||||
from ${userCollection.getTableNameWithSchemaAsString()}`,
|
from ${userCollection.getTableNameWithSchemaAsString()}`,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
|
@ -13,12 +13,13 @@ import moment from 'moment/moment';
|
|||||||
|
|
||||||
type WriterFunc = (val: any, database: Database) => any;
|
type WriterFunc = (val: any, database: Database) => any;
|
||||||
|
|
||||||
const getMapFieldWriter = (field: Field) => {
|
const getMapFieldWriter = (field: Field, database: Database) => {
|
||||||
return (val) => {
|
return (val) => {
|
||||||
const mockObj = {
|
const mockObj = {
|
||||||
setDataValue: (name, newVal) => {
|
setDataValue: (name, newVal) => {
|
||||||
val = newVal;
|
val = newVal;
|
||||||
},
|
},
|
||||||
|
database,
|
||||||
};
|
};
|
||||||
|
|
||||||
field.options.set.call(mockObj, val);
|
field.options.set.call(mockObj, val);
|
||||||
@ -31,9 +32,14 @@ export class FieldValueWriter {
|
|||||||
|
|
||||||
static write(field: Field, val, database) {
|
static write(field: Field, val, database) {
|
||||||
if (val === null) return val;
|
if (val === null) return val;
|
||||||
|
const getGeographyType = () => {
|
||||||
if (field.type == 'point' || field.type == 'lineString' || field.type == 'circle' || field.type === 'polygon') {
|
if (field.rawDataType.key?.toLowerCase() === DataTypes.GEOGRAPHY.key.toLowerCase()) {
|
||||||
return getMapFieldWriter(field)(lodash.isString(val) ? JSON.parse(val) : val);
|
return field.rawDataType.type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const geographyType = getGeographyType();
|
||||||
|
if (geographyType) {
|
||||||
|
return getMapFieldWriter(field, database)(lodash.isString(val) ? JSON.parse(val) : val);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fieldType = field.typeToString();
|
const fieldType = field.typeToString();
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { BaseColumnFieldOptions, DataTypes, Field, FieldContext } from '@nocobase/database';
|
import { BaseColumnFieldOptions, DataTypes, Field, FieldContext } from '@nocobase/database';
|
||||||
import { isPg, toValue } from '../helpers';
|
import { isMssql, isPg, toValue } from '../helpers';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
class Circle extends DataTypes.ABSTRACT {
|
class Circle extends DataTypes.ABSTRACT {
|
||||||
key = 'Circle';
|
key = 'Circle';
|
||||||
@ -34,6 +35,9 @@ export class CircleField extends Field {
|
|||||||
if (!value?.length) value = null;
|
if (!value?.length) value = null;
|
||||||
else if (isPg(context)) {
|
else if (isPg(context)) {
|
||||||
value = value.join(',');
|
value = value.join(',');
|
||||||
|
} else if (isMssql(context)) {
|
||||||
|
const [lat, lng] = value;
|
||||||
|
value = this.database?.sequelize.literal(`geography::Point(${lat}, ${lng}, 4326)`);
|
||||||
}
|
}
|
||||||
this.setDataValue(name, value);
|
this.setDataValue(name, value);
|
||||||
},
|
},
|
||||||
@ -46,10 +50,23 @@ export class CircleField extends Field {
|
|||||||
get dataType() {
|
get dataType() {
|
||||||
if (isPg(this.context)) {
|
if (isPg(this.context)) {
|
||||||
return Circle;
|
return Circle;
|
||||||
|
} else if (isMssql(this.context)) {
|
||||||
|
return DataTypes.STRING;
|
||||||
} else {
|
} else {
|
||||||
return DataTypes.JSON;
|
return DataTypes.JSON;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get rawDataType() {
|
||||||
|
return DataTypes.GEOGRAPHY;
|
||||||
|
}
|
||||||
|
|
||||||
|
setter(value, options) {
|
||||||
|
if (isMssql(this.context) && _.isObjectLike(value)) {
|
||||||
|
return JSON.stringify(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CircleFieldOptions extends BaseColumnFieldOptions {
|
export interface CircleFieldOptions extends BaseColumnFieldOptions {
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { BaseColumnFieldOptions, DataTypes, Field, FieldContext } from '@nocobase/database';
|
import { BaseColumnFieldOptions, DataTypes, Field, FieldContext } from '@nocobase/database';
|
||||||
import { isMysql, isPg, joinComma, toValue } from '../helpers';
|
import { isMssql, isMysql, isPg, joinComma, toValue } from '../helpers';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
class LineString extends DataTypes.ABSTRACT {
|
class LineString extends DataTypes.ABSTRACT {
|
||||||
key = 'Path';
|
key = 'Path';
|
||||||
@ -38,6 +39,10 @@ export class LineStringField extends Field {
|
|||||||
type: 'LineString',
|
type: 'LineString',
|
||||||
coordinates: value,
|
coordinates: value,
|
||||||
};
|
};
|
||||||
|
} else if (isMssql(context)) {
|
||||||
|
const [lat, lng] = value;
|
||||||
|
const coordStr = `${lng} ${lat}`;
|
||||||
|
value = this.database?.sequelize.literal(`geography::STLineFromText('LINESTRING(${coordStr})', 4326)`);
|
||||||
}
|
}
|
||||||
this.setDataValue(name, value);
|
this.setDataValue(name, value);
|
||||||
},
|
},
|
||||||
@ -51,12 +56,26 @@ export class LineStringField extends Field {
|
|||||||
if (isPg(this.context)) {
|
if (isPg(this.context)) {
|
||||||
return LineString;
|
return LineString;
|
||||||
}
|
}
|
||||||
|
if (isMssql(this.context)) {
|
||||||
|
return DataTypes.STRING;
|
||||||
|
}
|
||||||
if (isMysql(this.context)) {
|
if (isMysql(this.context)) {
|
||||||
return DataTypes.GEOMETRY('LINESTRING');
|
return DataTypes.GEOMETRY('LINESTRING');
|
||||||
} else {
|
} else {
|
||||||
return DataTypes.JSON;
|
return DataTypes.JSON;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get rawDataType() {
|
||||||
|
return DataTypes.GEOGRAPHY;
|
||||||
|
}
|
||||||
|
|
||||||
|
setter(value, options) {
|
||||||
|
if (isMssql(this.context) && _.isObjectLike(value)) {
|
||||||
|
return JSON.stringify(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LineStringOptions extends BaseColumnFieldOptions {
|
export interface LineStringOptions extends BaseColumnFieldOptions {
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { BaseColumnFieldOptions, DataTypes, Field, FieldContext } from '@nocobase/database';
|
import { BaseColumnFieldOptions, DataTypes, Field, FieldContext } from '@nocobase/database';
|
||||||
import { isMysql, isPg, joinComma, toValue } from '../helpers';
|
import { isMssql, isMysql, isPg, joinComma, toValue } from '../helpers';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
class Point extends DataTypes.ABSTRACT {
|
class Point extends DataTypes.ABSTRACT {
|
||||||
key = 'Point';
|
key = 'Point';
|
||||||
@ -36,6 +37,9 @@ export class PointField extends Field {
|
|||||||
if (!value?.length) value = null;
|
if (!value?.length) value = null;
|
||||||
else if (isPg(context)) {
|
else if (isPg(context)) {
|
||||||
value = joinComma(value);
|
value = joinComma(value);
|
||||||
|
} else if (isMssql(context)) {
|
||||||
|
const [lat, lng] = value;
|
||||||
|
value = this.database?.sequelize.literal(`geography::Point(${lat}, ${lng}, 4326)`);
|
||||||
} else if (isMysql(context)) {
|
} else if (isMysql(context)) {
|
||||||
value = {
|
value = {
|
||||||
type: 'Point',
|
type: 'Point',
|
||||||
@ -54,12 +58,26 @@ export class PointField extends Field {
|
|||||||
if (isPg(this.context)) {
|
if (isPg(this.context)) {
|
||||||
return Point;
|
return Point;
|
||||||
}
|
}
|
||||||
|
if (isMssql(this.context)) {
|
||||||
|
return DataTypes.STRING;
|
||||||
|
}
|
||||||
if (isMysql(this.context)) {
|
if (isMysql(this.context)) {
|
||||||
return DataTypes.GEOMETRY('POINT');
|
return DataTypes.GEOMETRY('POINT');
|
||||||
} else {
|
} else {
|
||||||
return DataTypes.JSON;
|
return DataTypes.JSON;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get rawDataType() {
|
||||||
|
return DataTypes.GEOGRAPHY;
|
||||||
|
}
|
||||||
|
|
||||||
|
setter(value, options) {
|
||||||
|
if (isMssql(this.context) && _.isObjectLike(value)) {
|
||||||
|
return JSON.stringify(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PointFieldOptions extends BaseColumnFieldOptions {
|
export interface PointFieldOptions extends BaseColumnFieldOptions {
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { BaseColumnFieldOptions, DataTypes, Field, FieldContext } from '@nocobase/database';
|
import { BaseColumnFieldOptions, DataTypes, Field, FieldContext } from '@nocobase/database';
|
||||||
import { isMysql, isPg, joinComma, toValue } from '../helpers';
|
import { isMssql, isMysql, isPg, joinComma, toValue } from '../helpers';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
class Polygon extends DataTypes.ABSTRACT {
|
class Polygon extends DataTypes.ABSTRACT {
|
||||||
key = 'Polygon';
|
key = 'Polygon';
|
||||||
@ -38,6 +39,10 @@ export class PolygonField extends Field {
|
|||||||
type: 'Polygon',
|
type: 'Polygon',
|
||||||
coordinates: [value.concat([value[0]])],
|
coordinates: [value.concat([value[0]])],
|
||||||
};
|
};
|
||||||
|
} else if (isMssql(context)) {
|
||||||
|
const [lat, lng] = value;
|
||||||
|
const coordStr = `${lng} ${lat}`;
|
||||||
|
value = this.database?.sequelize.literal(`geography::STPolyFromText('POLYGON((${coordStr}))', 4326)`);
|
||||||
}
|
}
|
||||||
this.setDataValue(name, value);
|
this.setDataValue(name, value);
|
||||||
},
|
},
|
||||||
@ -52,9 +57,22 @@ export class PolygonField extends Field {
|
|||||||
return Polygon;
|
return Polygon;
|
||||||
} else if (isMysql(this.context)) {
|
} else if (isMysql(this.context)) {
|
||||||
return DataTypes.GEOMETRY('POLYGON');
|
return DataTypes.GEOMETRY('POLYGON');
|
||||||
} else {
|
|
||||||
return DataTypes.JSON;
|
|
||||||
}
|
}
|
||||||
|
if (isMssql(this.context)) {
|
||||||
|
return DataTypes.STRING;
|
||||||
|
}
|
||||||
|
return DataTypes.JSON;
|
||||||
|
}
|
||||||
|
|
||||||
|
get rawDataType() {
|
||||||
|
return DataTypes.GEOGRAPHY;
|
||||||
|
}
|
||||||
|
|
||||||
|
setter(value, options) {
|
||||||
|
if (isMssql(this.context) && _.isObjectLike(value)) {
|
||||||
|
return JSON.stringify(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,3 +32,7 @@ export const isSqlite = (ctx) => {
|
|||||||
export const isMysql = (ctx) => {
|
export const isMysql = (ctx) => {
|
||||||
return getDialect(ctx) === 'mysql';
|
return getDialect(ctx) === 'mysql';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isMssql = (ctx) => {
|
||||||
|
return getDialect(ctx) === 'mssql';
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user