On Mon, Apr 13, 2020, at 6:25 PM, Adrien Berchet wrote: > Hello there > > I tried to integrate your POC in GeoAlchemy2 in the following PR: > https://github.com/geoalchemy/geoalchemy2/pull/258 > > It is almost working but the ST_AsGeoJSON() function needs a record, not a > list of columns. So the query should be like: >> SELECT ST_AsGeoJSON(t.*) FROM t; > while the example you provided gives: >> SELECT ST_AsGeoJSON(t.id, t.geom) FROM t; > which is not accepted by PostGIS (Error: the function st_asgeojson(integer, > geometry) does not exist). > > I was able to make it work in the PR by adding a call to the ROW() function, > which leads to the following query: >> SELECT ST_AsGeoJSON(ROW(t.id, t.geom)) FROM t; > This query is properly executed by PostGIS but the column names are lost. For > example I will get the following result: >> {"type": "Feature", "geometry": {"type":"Point","coordinates":[1,1]}, >> "properties": {*"f1"*: 1}} => "f1" property should be name "id" > instead of: >> {"type": "Feature", "geometry": {"type":"Point","coordinates":[1,1]}, >> "properties": {*"id"*: 1}} > > Do you have any idea to overcome this issue? I did not find how to produce a > "t.*" with SQLAlchemy...
There should definitely be some way for this to work without doing "*". what if "t" didn't have the columns in that specific order? the "ROW" function seems like what should be used but I don't understand the "column names" issue, is this regarding what goes into the JSON structure that the PG function returns? there should be a way to affect that at the SQL level. > > Thanks :-) > > `` > > Le lundi 20 janvier 2020 18:05:31 UTC+1, Mike Bayer a écrit : >> >> >> On Sun, Jan 19, 2020, at 12:23 PM, Stephan Hügel wrote: >>> >>> >>> On Sunday, 19 January 2020 16:13:40 UTC, Mike Bayer wrote: >>>> >>>> >>>> On Sun, Jan 19, 2020, at 11:10 AM, Mike Bayer wrote: >>>>> >>>>> >>>>> On Sun, Jan 19, 2020, at 10:54 AM, Stephan Hügel wrote: >>>>>> I'm trying to define a GenericFunction that calls a PostGIS 3.0 function >>>>>> (ST_AsGeoJson <https://postgis.net/docs/ST_AsGeoJSON.html>). The latest >>>>>> version can be called in two different ways: >>>>>> >>>>>> SELECT ST_AsGeoJSON(t.geom) FROM foo as t WHERE t.id = 1; >>>>>> SELECT ST_AsGeoJSON(t.*) FROM foo as t WHERE t.id = 1; >>>>>> >>>>>> where the first example returns a GeoJSON Geometry, and the second >>>>>> returns a GeoJSON Feature. I'm only interested in making use of the >>>>>> second type / am happy to define the two variants separately. >>>>>> >>>>>> I should be able to subclass GenericFunction in order to do this, but >>>>>> I'm missing two details: >>>>>> >>>>>> 1. What should the return type of my subclass be? >>>>>> 2. How can I specify that I want to pass the record / row / all columns, >>>>>> as opposed to just the geom column to the underlying function? >>>>>> Ordinarily, attempting something like >>>>>> >>>>>> sess.query(func.MyGeojson(Foo)).all() >>>>>> >>>>>> Will give me an error: >>>>>> >>>>>> Object <class 'models.Foo'> is not legal as a SQL literal value >>>>> >>>>> >>>>> by "return type" I think you're referring to the "type" attribute, so in >>>>> SQL if you were to make a database column that stores the result of the >>>>> ST_AsGeoJSON function, a quick google shows it as "text", so for >>>>> SQLAlchemy you could make the return type String, VARCHAR, TEXT, etc. >>>> >>>> OK well looking at https://postgis.net/docs/ST_AsGeoJSON.html it says >>>> "Return the geometry as a GeoJSON "geometry" object, or the row as a >>>> GeoJSON "feature" object", even though the signatures say "text". OK so I >>>> see you want to change the type based on the arguments. It's safe to do >>>> that in your constructor as well; "if this_looks_like_a_row(args): >>>> self.type = Feature else: self.type=Geometry". >>>> >>>> >>>> >>>>> >>>>> for the column expansion you override the constructor and inspect the >>>>> object(s) given and do what you want with them. SQLAlchemy has some >>>>> built-in systems for "how to expand an ORM model or Selectable into Table >>>>> columns" but only in 1.4 is there a new system for this that is organized >>>>> and predictable, so for the moment you'd want to roll it yourself: >>>>> >>>>> from sqlalchemy import inspect >>>>> >>>>> class MyFunction(GenericFunction): >>>>> def __init__(self, *args, **kw): >>>>> pass_args = [] >>>>> for arg in args: >>>>> insp = inspect(arg) >>>>> if hasattr(insp, "selectable"): >>>>> pass_args.extend(selectable.c.) >>>>> else: >>>>> pass_args.append(arg) >>>>> super(MyFunction, self).__init__(*pass_args, **kw) >>>>> >>>>> also note there's been a lot of call for Geo support lately (not sure if >>>>> you were the person that filed an issue re: SQL Server) but we are really >>>>> looking for help to get geoalchemy2 up to date and supporting more >>>>> backends. >>>>> >>>>> >>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> SQLAlchemy - >>>>>> The Python SQL Toolkit and Object Relational Mapper >>>>>> >>>>>> http://www.sqlalchemy.org/ >>>>>> >>>>>> To post example code, please provide an MCVE: Minimal, Complete, and >>>>>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>>>>> description. >>>>>> --- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "sqlalchemy" group. >>>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>>> an email to sqlal...@googlegroups.com. >>>>>> To view this discussion on the web visit >>>>>> https://groups.google.com/d/msgid/sqlalchemy/f3718ff7-a252-41a9-8ac4-1ee2ee1e7f9f%40googlegroups.com >>>>>> >>>>>> <https://groups.google.com/d/msgid/sqlalchemy/f3718ff7-a252-41a9-8ac4-1ee2ee1e7f9f%40googlegroups.com?utm_medium=email&utm_source=footer>. >>>>> >>>> >>> >>> Thanks for the quick response Mike! >>> >>> OK so far I've got: >>> https://gist.github.com/urschrei/782989d0b3bee8e4208eb2bea945b65b. Requires >>> PostGIS 3.0.x as an extension, and requires GeoAlchemy2. >>> >>> On line 15, I fixed what I assume was a typo for selectable in your >>> original suggestion. I still get the expected >>> >>> Object <class '__main__.Hardinfra'> is not legal as a SQL literal value >>> >>> error though. I don't follow your suggestion about >>> >>> "if this_looks_like_a_row(args): self.type = Feature else: >>> self.type=Geometry" >> >> that was pseudocode. If the incoming argument is a "selectable", that is, >> has a .c attribute, it's a set of columns, therefore, it's a row. otherwise, >> it's not. >> >> Here's complete POC >> >> from sqlalchemy import Column >> from sqlalchemy import func >> from sqlalchemy import inspect >> from sqlalchemy import Integer >> from sqlalchemy import String >> from sqlalchemy.ext.declarative import declarative_base >> from sqlalchemy.sql.functions import GenericFunction >> from sqlalchemy.types import UserDefinedType >> >> >> class Feature(UserDefinedType): >> pass >> >> >> class Geometry(UserDefinedType): >> pass >> >> >> class MyGj(GenericFunction): >> def __init__(self, *args, **kw): >> pass_args = [] >> for arg in args: >> insp = inspect(arg) >> if hasattr(insp, "selectable"): >> pass_args.extend(insp.selectable.c) >> self.type = Feature >> else: >> self.type = Geometry >> pass_args.append(arg) >> super(MyGj, self).__init__(*pass_args, **kw) >> >> name = "ST_AsGeoJson" >> >> >> Base = declarative_base() >> >> >> class A(Base): >> __tablename__ = "a" >> >> id = Column(Integer, primary_key=True) >> data = Column(String) >> >> >> function = func.ST_AsGeoJson(A) >> >> assert isinstance(function.type, Feature) >> >> >> print(function) >> >> >>> >>> possibly because I'm not well-versed in SQLA's internals – is there an easy >>> way to distinguish between a row and a column? That still leaves the issue >>> of the "Geometry" vs "Feature" distinction in self.types: Geoalchemy2 >>> defines a "Geometry" type, but not a "Feature" type, because "Feature" is >>> only a part of the GeoJSON spec, but I doubt that either of these things >>> are causing the problem. I've also tried executing the SQL query on my db >>> to make sure it's working and both >>> >>> SELECT ST_AsGeoJSON(t.*) FROM hardinfra as t WHERE t.id = 1; >>> SELECT ST_AsGeoJSON(t.geom) FROM hardinfra as t WHERE t.id = 1; >>> >>> work, returning a GeoJSON Feature and Geometry respectively. >>> >>> I didn't open the issue about SQL Server, but I use GeoAlchemy regularly, >>> so if there are intro issues available I'm happy to help out when I can. >>> >>> >>> -- >>> SQLAlchemy - >>> The Python SQL Toolkit and Object Relational Mapper >>> >>> http://www.sqlalchemy.org/ >>> >>> To post example code, please provide an MCVE: Minimal, Complete, and >>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>> description. >>> --- >>> You received this message because you are subscribed to the Google Groups >>> "sqlalchemy" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to sqlal...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/sqlalchemy/795a8d14-17da-4c47-a917-78f355e88951%40googlegroups.com >>> >>> <https://groups.google.com/d/msgid/sqlalchemy/795a8d14-17da-4c47-a917-78f355e88951%40googlegroups.com?utm_medium=email&utm_source=footer>. >> > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/fedacdfa-5bd6-4f6c-9c0a-e2f8287585b7%40googlegroups.com > > <https://groups.google.com/d/msgid/sqlalchemy/fedacdfa-5bd6-4f6c-9c0a-e2f8287585b7%40googlegroups.com?utm_medium=email&utm_source=footer>. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/44d065c7-0512-4039-8941-b2cfac313fd3%40www.fastmail.com.