-
Notifications
You must be signed in to change notification settings - Fork 112
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
Associate spatial functions to each type #396
Comments
@adrien-berchet I've started to dig into this, but I'm noticing a build inconsistency which is preventing progress. The GitHub actions yml is set to test python versions 3.7 - 3.11 https://github.com/geoalchemy/geoalchemy2/blob/master/.github/workflows/test_and_publish.yml#L32, but the pre-commit hooks are configured to use only python 3.8 https://github.com/geoalchemy/geoalchemy2/blob/master/.pre-commit-config.yaml#L2. Can the 3.8 restriction be loosened? My local setup is using 3.11. |
Hi @papacodebear ! |
@adrien-berchet Gotcha, sounds good and noted. I'm trying to create a branch, but I don't have permissions to. Would you mind adding me as a contributor? Also, I assume that I should be branching off of and creating PR's into master, correct? |
Could you create a fork on your side to make the branch there? Actually I don't have permissions to add you as a contributor (I will try to ask for it, it would make sense that I get them now). |
Hi @papacodebear, did you have some time to work on this? (just to know, no pressure |
Hi @adrien-berchet , no worries! Yeah I've started to work on this, but the scope has definitely expanded. The way I've started to tackle this is to define which functions actually belong to each type, which has been the majority of the effort. I started by taking the "master" list of functions from here, and tried to associate them with the right types, but then realized that PostGIS has also made updates over time, and so pulled the new list of functions directly from PostGIS. Rasters I sent you an invite to the forked repository if you'd like to take a quick look at the progress. Any word on getting the collaborator access? Edit: I realize the forked repository is public, my branch is here: https://github.com/papacodebear/geoalchemy2/tree/papacodebear/issue396 |
Very nice! |
Apologies for the delay, I moved the spatial types into individual files mostly for readability reasons, using the one class per module pattern. It can be helpful to know what types exist by looking in the directory. It's also helpful to reduce merge conflicts when multiple people are working on different types. I sort of see it as the same benefit as splitting the dialects here: https://github.com/geoalchemy/geoalchemy2/tree/master/geoalchemy2/types/dialects . It's also going to become more important as we split the spatial functions per type, since the _FUNCTIONS variable is so large, we would want them in separate files for separate types. I don't want to step on any toes, so let me know if you want me to change it back, but I think there are benefits to splitting it. |
Ok, I see, that's interesting. In our case the type classes are very simple so it may be an overkill but we can still try this new organization. |
Hi @adrien-berchet , I've split the functions per type, but now I'm running into an issue where I could use some guidance. I'm trying to accommodate the As an example, take ST_Intersection, which applies to both rasters and geometries. Geometry: http://postgis.net/docs/manual-3.3/ST_Intersection.html If we're in a position where a user could write an expression like
It's not obvious what the return type is unless either the user specifies it, or we keep a list of potential argument types and known return types. For instance the example here should return a set of geometry values, even though the first argument is a raster. By my estimation, it looks like we're having to guess what the return type is based on arguments to the function. This problem would occur in varying degrees of confusion for the following functions:
Should I look into building the list of possible arguments and corresponding return types? |
Hi @papacodebear ! |
Responding here to a question asked in #478 as to whether I don't think it can be used to solve this problem as It looks like this should be possible at least in some situations: SQLAlchemy provides |
Interesting, thanks! |
@adrien-berchet Sure thing. Let me take a look and see what's possible with it! Thanks for finding this @mbway |
Hey @adrien-berchet, sorry for the crazy delay here, but I think I've made quite a bit of progress over the holidays. I think there's going to be a lot of overlap with the work @mbway has done, and I'd love to incorporate what he's done here: #478. I took a quick look at the suggested Rather than manually create the argument overloads and their respective return types, I figured out an automatic way of parsing available postgis functions. The documentation isn't readily queryable, but I think I figured out a general way to maintain the list of functions and argument types. This also required adding a few unimplemented types like GeomVal though.
It does solve the original issue, but in one case requires providing a little more information about column types. As an example for a GeometryTest table: class GeometryTest(Base):
__tablename__ = "geometrytest"
id = Column(Integer, primary_key=True)
geom = Column(Geometry)
rast = Column(Raster)
with Session(engine) as session:
# This doesn't work, we can't infer the type of the columns. They resolve as NullType():
geometry_test = table("geometrytest", column("id"), column("geom"), column("rast"))
query = select(func.ST_Intersection(geometry_test.c.rast, geometry_test.c.geom))
# This works because we specify the type of the columns. We don't have to specify the return type though
geometry_test = table(
"geometrytest", column("id"), column("geom", type_=Geometry), column("rast", type_=Raster)
)
query = select(func.ST_Intersection(geometry_test.c.rast, geometry_test.c.geom))
# This works because the type of the columns comes from the table definition
query = select(func.ST_Intersection(GeometryTest.rast, GeometryTest.geom))
geom_row = session.scalars(query).one()
print(geom_row) Essentially, if using the "table" construct, the column types have to be provided:
It's not cleaned up, but before I go further I wanted to check in and make sure I'm not way out there. I think this could simplify a lot of function maintenance! Let me know what you think! |
Hi @papacodebear As far as I am concerned, I have no objection about changing the data structure used to store the functions (in your About the Finally, your branch is quite far behind our master branch, it would be nice to try to update it so it will be easier to understand what you changed. Thanks again! |
@adrien-berchet Fair enough! I back-merged from master, so it should be up to date now. Let me know what you think! I haven't incorporated the automated type stub generation yet, but am happy to add it |
A nice improvement would be to associate only the relevant functions to each spatial type, instead of associating all functions to all types. With this feature we wouldn't have to specify the target type when it is different from
Geometry
(as described here: https://geoalchemy-2.readthedocs.io/en/latest/core_tutorial.html#use-raster-functions).The text was updated successfully, but these errors were encountered: