db_serializer 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +71 -0
- data/lib/db_serializer.rb +16 -0
- data/lib/db_serializer/geo_json.rb +72 -0
- data/lib/db_serializer/utilities.rb +125 -0
- data/lib/db_serializer/version.rb +5 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 455c86988e110584438e1edbbf8ef7c894e5a32ca6f69f49644d01e35cf9553a
|
4
|
+
data.tar.gz: c2b95f504f522e38992fe027f72cae332c8e7c96017ea1287fb9de6fab5b3b1a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e35adc11a93293124fe2f39be8aee789fd1b02ddad3028cc111aad698e58d9d28a501870ffb2ab7381948d995fcfe0c6c49ab72951fc26b15310021453b042cd
|
7
|
+
data.tar.gz: 30ad4440828d712480b39b1588502ba5aebfc1a724f0e53661072670dc515e3ae8ea4a891d490479cb15193ddf196d0c0510c5d3b120bee9a734e611f9e6a969
|
data/README.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Db Serializer
|
2
|
+
|
3
|
+
This gem provide a blazing fast way to serialize Active Record models.
|
4
|
+
At the moment only a GeoJSON serializer is implemented
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'db_serializer'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
```bash
|
17
|
+
$ bundle install
|
18
|
+
```
|
19
|
+
|
20
|
+
Then you need to include the concern `DbSerializer::GeoJSON` to your model:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
# In this example the City model has:
|
24
|
+
# - an attribute name of type string
|
25
|
+
# - an attribute boundaries of type geometry
|
26
|
+
class City < ActiveRecord::Base
|
27
|
+
# Include this concern
|
28
|
+
include DbSerializer::JSON
|
29
|
+
|
30
|
+
# Specify which column contains the geometry
|
31
|
+
# If you don't specify it, by default it will be :geometry
|
32
|
+
db_serializer :boundaries
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
puts City.all.to_geojson([:id, :name])
|
40
|
+
|
41
|
+
# If you had such a model, it would output something like this:
|
42
|
+
# {
|
43
|
+
# "type": "FeatureCollection", "features": [{
|
44
|
+
# "id": 1, "type": "Feature", "geometry": {
|
45
|
+
# "type": "MultiLineString", "coordinates": [[[x1,y1],[x2,y2]]]
|
46
|
+
# },
|
47
|
+
# "properties": {"id": 1, "name": "Paris"}
|
48
|
+
# }]
|
49
|
+
# }
|
50
|
+
```
|
51
|
+
Note: the output has been pretty printed for readability but please keep in mind that `to_geojson` returns a *string* containing a valid serialized JSON.
|
52
|
+
It means that you do not need to use `to_json` on it and that it can be parse with `JSON.parse`.
|
53
|
+
|
54
|
+
## Development
|
55
|
+
|
56
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
57
|
+
|
58
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
59
|
+
|
60
|
+
## Contributing
|
61
|
+
|
62
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/leonard-henriquez/db_serializer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/leonard-henriquez/db_serializer/blob/master/CODE_OF_CONDUCT.md).
|
63
|
+
|
64
|
+
|
65
|
+
## License
|
66
|
+
|
67
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
68
|
+
|
69
|
+
## Code of Conduct
|
70
|
+
|
71
|
+
Everyone interacting in the db_serializer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/leonard-henriquez/db_serializer/blob/master/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_record'
|
5
|
+
|
6
|
+
##
|
7
|
+
# Module that contains spatial serializers for ActiveRecord models.
|
8
|
+
# The extended class must be an ActiveRecord::Base.
|
9
|
+
# It must also have a geometry column (the name of this column can be customized).
|
10
|
+
module DbSerializer
|
11
|
+
extend ActiveSupport::Autoload
|
12
|
+
|
13
|
+
autoload :Version
|
14
|
+
autoload :GeoJSON
|
15
|
+
autoload :Utilities
|
16
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DbSerializer
|
4
|
+
# JSON Serializer
|
5
|
+
module GeoJSON
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
@db_serializer_options = {
|
10
|
+
field: :geometry
|
11
|
+
}
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
##
|
16
|
+
# Adds a geojson attribute to the current ActiveRecord::Relation
|
17
|
+
# @param columns [Array<Symbol, String>] list of the columns to include in the GeoJSON
|
18
|
+
# @return [ActiveRecord::Relation] relation with a new attribute named geojson
|
19
|
+
scope :set_geojson_attribute, ->(columns = nil) do
|
20
|
+
columns = select_values if columns.nil?
|
21
|
+
params = {
|
22
|
+
geometry_column: db_serializer_options[:field],
|
23
|
+
field_name: :geojson
|
24
|
+
}
|
25
|
+
|
26
|
+
attribute = DbSerializer::Utilities::SQL.geojson_attribute(columns, params)
|
27
|
+
|
28
|
+
_select!(attribute)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class_methods do
|
33
|
+
##
|
34
|
+
# Allows to set the options for this gem
|
35
|
+
# @param field [Symbol] name of the attribute containing geometry
|
36
|
+
# @return [Hash]
|
37
|
+
def db_serializer(field = :geometry)
|
38
|
+
@db_serializer_options = {}
|
39
|
+
@db_serializer_options[:field] = field.to_sym
|
40
|
+
db_serializer_options
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Allows to get the options for this gem
|
45
|
+
# @return [Hash] contains keys :field
|
46
|
+
def db_serializer_options
|
47
|
+
if defined?(@db_serializer_options)
|
48
|
+
@db_serializer_options
|
49
|
+
elsif superclass.respond_to?(:db_serializer_options)
|
50
|
+
superclass.db_serializer_options || {}
|
51
|
+
else
|
52
|
+
{}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Creates a json serialized FeatureCollection of the ActiveRecord::Relation.
|
58
|
+
#
|
59
|
+
# FeatureCollection specs: http://wiki.geojson.org/GeoJSON_draft_version_6#FeatureCollection
|
60
|
+
#
|
61
|
+
# It is already serialized so there is no need to apply +.to_json+.
|
62
|
+
#
|
63
|
+
# @param columns [Array<Symbol, String>]
|
64
|
+
# @return [String] JSON serialized FeatureCollection
|
65
|
+
def to_geojson(columns = nil)
|
66
|
+
features = set_geojson_attribute(columns)
|
67
|
+
query = DbSerializer::Utilities::SQL.feature_collection(features)
|
68
|
+
ActiveRecord::Base.connection.query_value(query)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DbSerializer
|
4
|
+
##
|
5
|
+
# Module defining geographic tools
|
6
|
+
module Utilities
|
7
|
+
##
|
8
|
+
# SQL utilities for spatial queries
|
9
|
+
module SQL
|
10
|
+
class << self
|
11
|
+
##
|
12
|
+
# This method returns a string containing a SQL query to build a GeoJSON FeatureCollection.
|
13
|
+
#
|
14
|
+
# The result of the SQL query generated by this method contains one row with one
|
15
|
+
# column. It contains a serialized GeoJSON FeatureCollection.
|
16
|
+
#
|
17
|
+
# Example of GeoJSON FeatureCollection:
|
18
|
+
# <code>
|
19
|
+
# {"type": "FeatureCollection", "features": [{"id": 1, "type":
|
20
|
+
# "Feature", "geometry": {"type": "MultiLineString", "coordinates": [[[x,y]]]},
|
21
|
+
# "properties": {"id": 1, "name": "Paris"}}]}
|
22
|
+
# </code>
|
23
|
+
#
|
24
|
+
# To learn more about FeatureCollections see the specifications:
|
25
|
+
# http://wiki.geojson.org/GeoJSON_draft_version_6#FeatureCollection
|
26
|
+
#
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# features = MyActiveRecordModel.select(geojson_attribute([:id]))
|
30
|
+
# query = feature_collection(features)
|
31
|
+
# ActiveRecord::Base.connection.query_value(query)
|
32
|
+
#
|
33
|
+
# @param features [String, ActiveRecord::Relation] query of the features to include
|
34
|
+
# @param opts [Hash]
|
35
|
+
# @option opts [String, Symbol] :geojson_column name of the column containing
|
36
|
+
# the GeoJSON features to include in the collection
|
37
|
+
# @option opts [String, Symbol] :output_column name of the output column
|
38
|
+
# @return [String] SQL to get a FeatureCollection
|
39
|
+
def feature_collection(features, opts = {})
|
40
|
+
opts = {
|
41
|
+
geojson_column: :geojson,
|
42
|
+
output_column: :json
|
43
|
+
}.merge(opts)
|
44
|
+
|
45
|
+
geojson_column = opts[:geojson_column]
|
46
|
+
output_column = opts[:output_column]
|
47
|
+
inner_query = features.is_a?(String) ? features : features.to_sql
|
48
|
+
|
49
|
+
<<-SQL
|
50
|
+
SELECT jsonb_build_object(
|
51
|
+
'type', 'FeatureCollection',
|
52
|
+
'features', COALESCE(jsonb_agg(features.#{geojson_column}), '[]')
|
53
|
+
) AS #{output_column} FROM (#{inner_query}) features
|
54
|
+
SQL
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# This method returns a string containing part of a SQL query that can be used
|
59
|
+
# in a +SELECT+ statement to add a GeoJSON feature column to a query.
|
60
|
+
#
|
61
|
+
# The SQL column generated by this method contains a serialized GeoJSON feature.
|
62
|
+
#
|
63
|
+
# Example of GeoJSON feature:
|
64
|
+
# <code>
|
65
|
+
# {"id": 1, "type": "Feature", "geometry":
|
66
|
+
# {"type": "MultiLineString", "coordinates": [[[x,y]]]},
|
67
|
+
# "properties": {"id": 1, "name": "Paris"}}
|
68
|
+
# </code>
|
69
|
+
#
|
70
|
+
# To learn more about GeoJSON features see the specifications:
|
71
|
+
# http://wiki.geojson.org/GeoJSON_draft_version_6#Feature
|
72
|
+
#
|
73
|
+
# @example with SQL:
|
74
|
+
# geojson = DbSerializer::Utilities::SQL.geojson_attribute([:id])
|
75
|
+
# records = ActiveRecord::Base.connection.exec_query(
|
76
|
+
# "SELECT id, geometry, #{geojson} FROM table"
|
77
|
+
# )
|
78
|
+
# record = records.first
|
79
|
+
#
|
80
|
+
# # print a String containing a serialized GeoJSON feature, check example in the note
|
81
|
+
# puts record['geojson']
|
82
|
+
#
|
83
|
+
# @example with an +ActiveRecord::Base+
|
84
|
+
# geojson = DbSerializer::Utilities::SQL.geojson_attribute([:id])
|
85
|
+
# records = Model.select(geojson)
|
86
|
+
# record = records.first
|
87
|
+
#
|
88
|
+
# # print a String containing a serialized GeoJSON feature, check example in the note
|
89
|
+
# puts record.geojson_before_type_cast
|
90
|
+
#
|
91
|
+
# # print a Hash
|
92
|
+
# puts record.geojson
|
93
|
+
#
|
94
|
+
# @param columns [Array<String, Symbol>] SQL columns to include in the properties
|
95
|
+
# of the GeoJSON feature, must be accessible in the underlying table
|
96
|
+
# @param opts [Hash]
|
97
|
+
# @option opts [Symbol] :geometry_column defaults to :geometry
|
98
|
+
# @option opts [Symbol] :output_column defaults to :geojson
|
99
|
+
# @return [String] SQL +SELECT+ statement to add a column named +geojson+ to a SQL query
|
100
|
+
def geojson_attribute(columns, opts = {})
|
101
|
+
opts = {
|
102
|
+
geometry_column: :geometry,
|
103
|
+
output_column: :geojson
|
104
|
+
}.merge(opts)
|
105
|
+
|
106
|
+
filtered_columns = columns.reject { |column| column.to_s == opts[:geometry_column].to_s }
|
107
|
+
columns = filtered_columns.map { |column| "'#{column}',#{column}" }.join(',')
|
108
|
+
|
109
|
+
geometry = "ST_AsGeoJSON(#{opts[:geometry_column]})::jsonb"
|
110
|
+
properties = "json_build_object(#{columns})"
|
111
|
+
output_column = opts[:output_column]
|
112
|
+
|
113
|
+
<<-SQL
|
114
|
+
jsonb_build_object(
|
115
|
+
'type', 'Feature',
|
116
|
+
'id', id,
|
117
|
+
'geometry', #{geometry},
|
118
|
+
'properties', #{properties}
|
119
|
+
) AS #{output_column}
|
120
|
+
SQL
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: db_serializer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leonard Henriquez
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-05-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord-postgis-adapter
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Add geometry features on Active Record models
|
42
|
+
email:
|
43
|
+
- leonard@flatlooker.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- README.md
|
49
|
+
- lib/db_serializer.rb
|
50
|
+
- lib/db_serializer/geo_json.rb
|
51
|
+
- lib/db_serializer/utilities.rb
|
52
|
+
- lib/db_serializer/version.rb
|
53
|
+
homepage: https://github.com/Flatlooker/db_serializer
|
54
|
+
licenses:
|
55
|
+
- MIT
|
56
|
+
metadata:
|
57
|
+
homepage_uri: https://github.com/Flatlooker/db_serializer
|
58
|
+
source_code_uri: https://github.com/Flatlooker/db_serializer.git
|
59
|
+
changelog_uri: https://github.com/Flatlooker/db_serializer
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.3.0
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubygems_version: 3.1.3
|
76
|
+
signing_key:
|
77
|
+
specification_version: 4
|
78
|
+
summary: Add geometry features on Active Record models
|
79
|
+
test_files: []
|