Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
cab46b0
remove some unused branches
aseigo Jan 13, 2026
a5ed7c7
Add a function to raise a std "this feature unsupported by .." message
aseigo Jan 13, 2026
1fea7f0
add an optional dep on myxql
aseigo Jan 13, 2026
1d8c786
add myxql to the test matrix
aseigo Jan 13, 2026
4d373e7
add the geometry codec for myxql
aseigo Jan 13, 2026
2a74784
mysql does not require additional en/decoding of geometries
aseigo Jan 13, 2026
ca2cd03
mark a few unsupported functions
aseigo Jan 13, 2026
b3f181c
spiffy up
aseigo Jan 13, 2026
fddf366
update the version recommendation in the README.md
aseigo Jan 13, 2026
b3cc8bc
accommodate MysSQL in common queries
aseigo Jan 16, 2026
e0ec3e1
accommodate MysSQL in MM queries
aseigo Jan 16, 2026
4500cae
bump version to 0.8.1, update CHANGELOG and description
aseigo Mar 11, 2026
bf30541
add CI workflow
aseigo Mar 11, 2026
406c1c2
add excoveralls and dialyxir
aseigo Mar 11, 2026
541b5a3
myxql-related fixups
aseigo Mar 11, 2026
5b1691b
pass with MyXQL
aseigo Mar 11, 2026
a694a72
note the ZM support in DBs
aseigo Mar 11, 2026
00a5267
remove an unused config line
aseigo Mar 11, 2026
6ac8987
add mysql
aseigo Mar 11, 2026
7117ae1
repo-specific query arg placeholders
aseigo Mar 11, 2026
d2d0190
pass tests with mysql
aseigo Mar 11, 2026
394cc95
typo
aseigo Mar 11, 2026
2522422
pass with MySQL
aseigo Mar 11, 2026
0c0833d
get tests to pass with mysql. lots of exclusions. *sigh*
aseigo Mar 11, 2026
2cff816
credo fixes
aseigo Mar 11, 2026
5d9cc8f
eh, skip CI. for these db workloads and weird macro src, it is not he…
aseigo Mar 11, 2026
215a248
eh, skip CI. for these db workloads and weird macro src, it is not he…
aseigo Mar 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [1.8.0] 11-03-2026

* Improvements
* MySQL / MariaDB is now supported via a MyXQL extension.

## [1.7.0] 14-02-2026
* Dependencies
Expand Down
119 changes: 60 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ level functions for features such as generating Mapbox vector tiles.
The goals of this library are:

* Ease: fast to get started, hide complexity where possible
* Portability: currently supports PostGIS and SpatiaLite.
* Portability: currently supports PostGIS, SpatiaLite, MariaDB/MySQL, and GeoPackage.
* Completeness: extensive support for GIS SQL functions, not just the most common ones.
* Clarity: Functions organized by their availability and standards compliance
* Utility: Provide out-of-the-box support for complete worfklows. Mapbox vector tile
Expand All @@ -21,19 +21,19 @@ The goals of this library are:
Not-goals include:

* Having the fewest possible dependencies. Ecto adapters are pulled in as necessary,
along with other dependencies such as `Jason` in order to ease use.
and other quality-of-life libraries may also be used internally.

## Usage

Add `GeoSQL` to your project by adding the following to the `deps` section in `mix.exs` (or equivalent):

```
{:geo_sql, "~> 0.1"}
```elixir
{:geo_sql, "~> 1.0"}
```

Run the usual `mix deps.get`!
and then run the usual `mix deps.get`.

Full documentation can be generated locally with `mix docs`.
Full documentation is available [online](https://hexdocs.pm/geo_sql).

### Ecto Schemas

Expand Down Expand Up @@ -75,45 +75,7 @@ Example:
end
```

#### Geo

If the `geo` library is included in the build, `%Geo.{}` stucts are supported for writes to
the database. Libraries and Ecto schemas which still use `%Geo.{}` structs can therefore be
used with `GeoSQL`'s database extentions.

#### Geopackage

The Geopackage standard defines its own binary format for serializing geometries in SQLite3
databases. GeoSQL provides access to these types via the `GeoSQL.Geometry.Geopackage` type
allowing Ecto schemas to contain geometry fields that are stored as Geopackage data.

Example:

```elixir
defmodule MyApp.Geopackage do
use Ecto.Schema

@primary_key false
schema "some_table_in_geopackage" do
field(:id, :integer, source: :OBJECTID)
field(:name, :string)
field(:shape, GeoSQL.Geometry.Geopackage, source: :Shape)
end
end
```

This schema can now be used in queries like any other:

```elixir
from(g in MyApp.Geopackage) |> MyApp.GeopackageRepo.all()
```

Due to being tied to SQLite3, only SQLite3 databases are supported and the Spatialite
module must be available as it is (currently) used to do the serialization in memory.
The Spatialite module does not need to be initialized on a Geopackage database, but
it does need to be available on the system for GeoSQL to use.

### Readying the Repo with `GeoSQL.init/1`
### Readying an Ecto Repo with `GeoSQL.init/1`

Once added to your project, an `Ecto.Repo` can be readied for use by calling
`GeoSQL.init/2`. This can be done once the repo has been started by implementing
Expand Down Expand Up @@ -154,7 +116,7 @@ will still need to be called after the repo has been started.
Dynamic Ecto repositories are also supported, and `GeoSQL.init/1` can be
called after the call to `Repo.put_dynamic_repo/1` has completed.

### Macro usage
### Ecto Queries

Once initialized, the wide array of macros can be used with `Ecto` queries:

Expand Down Expand Up @@ -348,7 +310,50 @@ with the `MVT` vector tile layer format.
Database prefixes ("schemas" in PostgreSQL) are also supported both on the whole tile query
as well as per-layer.

## Building
#### Geopackage

The Geopackage standard defines its own binary format for serializing geometries in SQLite3
databases. GeoSQL provides access to these types via the `GeoSQL.Geometry.Geopackage` type
allowing Ecto schemas to contain geometry fields that are stored as Geopackage data.

Example:

```elixir
defmodule MyApp.Geopackage do
use Ecto.Schema

@primary_key false
schema "some_table_in_geopackage" do
field(:id, :integer, source: :OBJECTID)
field(:name, :string)
field(:shape, GeoSQL.Geometry.Geopackage, source: :Shape)
end
end
```

This schema can now be used in queries like any other:

```elixir
from(g in MyApp.Geopackage) |> MyApp.GeopackageRepo.all()
```

Due to being tied to SQLite3, only SQLite3 databases are supported and the Spatialite
module must be available as it is (currently) used to do the serialization in memory.
The Spatialite module does not need to be initialized on a Geopackage database, but
it does need to be available on the system for GeoSQL to use.

#### Support for the Geo library

If the application includes the `geo` library as a dependency, `%Geo.{}` stucts are supported for writes to
the database. Libraries and Ecto schemas which still use `%Geo.{}` structs can therefore be
used with `GeoSQL`'s database extentions.

## Contributing

If you would like to contribute support for more functions (PostGIS and
SpatiaLite both provide a frighteningly impressive amount of them!) or
support for other databases, do not hesitate to make a PR and it will be
reviewed in a timely fashion.

To build and interact with the library locally:

Expand All @@ -358,14 +363,16 @@ To build and interact with the library locally:
mix compile
iex -S mix

Documentation can be generated locally with `mix docs`.

### Unit Tests

## Unit Tests

Unit tests currently assume a working PostGIS installation is available locally.
Unit tests currently assume that working installations of PostGIS, SpatiaLite, and MariaDB/Mysql are running on the local machine.

The URL for the test database is defined in `config/test.exs`.
The locations of the test databases are defined in `config/test.exs` and may be
changed to suit your own dev environment.

**Note** that this database will be created and **dropped** on every run of the tests.
**Note** that databases will be created and **dropped** on every run of the tests.
Do NOT point it to an existing database!

The migrations in `priv/repo/migrations` are run on each test run.
Expand All @@ -390,13 +397,7 @@ Current the following backends are recognized:

* `pgsql`
* `sqlite3`

## Contributing

If you would like to contribute support for more functions (PostGIS and
SpatiaLite both provide a frighteningly impressive amount of them!) or
support for other databases, do not hesitate to make a PR and the author
will review and merge in a timely fashion.
* `mysql`

## Acknowledgements

Expand Down
14 changes: 13 additions & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import Config

test_repos =
(System.get_env("GEOSQL_TEST_BACKENDS") || "pgsql,sqlite3")
(System.get_env("GEOSQL_TEST_BACKENDS") || "pgsql,sqlite3,mysql")
|> String.split(",")
|> Enum.reduce([], fn backend, acc ->
case backend do
"pgsql" -> [GeoSQL.Test.PostGIS.Repo | acc]
"mysql" -> [GeoSQL.Test.MySQL.Repo | acc]
"sqlite3" -> [GeoSQL.Test.SpatiaLite.Repo, GeoSQL.Test.Geopackage.Repo | acc]
end
end)
Expand All @@ -19,6 +20,17 @@ config :geo_sql, GeoSQL.Test.PostGIS.Repo,
priv: "priv/repo/postgis",
testing_primary: true

config :geo_sql, GeoSQL.Test.MySQL.Repo,
host: "localhost",
username: "testing",
password: "testing",
protocol: :tcp,
database: "geosql_tests",
pool: Ecto.Adapters.SQL.Sandbox,
priv: "priv/repo/mysql",
testing_primary: true,
show_sensitive_data_on_connection_error: true

config :geo_sql, GeoSQL.Test.SpatiaLite.Repo,
database: "geo_sql_test.sqlite3",
pool_size: 20,
Expand Down
16 changes: 10 additions & 6 deletions lib/geo_sql.ex
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,18 @@ defmodule GeoSQL do
adapter
end

if Code.ensure_loaded?(MyXQL) do
defp register_types(Ecto.Adapters.MyXQL, _repo, _opts) do
Application.put_env(:myxql, :geometry_codec, GeoSQL.MySQL.GeometryCodec)
end
end

defp register_types(adapter, _repo, _opts), do: adapter

defp run_query(repo, sql) do
try do
Ecto.Adapters.SQL.query!(repo.get_dynamic_repo(), sql)
:ok
rescue
_ -> :error
end
Ecto.Adapters.SQL.query!(repo.get_dynamic_repo(), sql)
:ok
rescue
_ -> :error
end
end
Loading