db_serializer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|