lca 0.2.1 → 0.2.5
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 +4 -4
- data/Gemfile +4 -1
- data/README.md +46 -30
- data/lib/generators/lca/templates/migration.rb.tt +25 -7
- data/lib/lca/active_record.rb +5 -5
- data/lib/lca/models/concerns/lcable.rb +1 -1
- data/lib/lca/models/concerns/statusable.rb +5 -0
- data/lib/lca/models/cycle.rb +1 -1
- data/lib/lca/models/exchange.rb +2 -2
- data/lib/lca/models/impact.rb +2 -2
- data/lib/lca/models/metadata.rb +12 -0
- data/lib/lca/models/model.rb +13 -4
- data/lib/lca/models/process.rb +4 -5
- data/lib/lca/models/stage.rb +2 -2
- data/lib/lca/version.rb +1 -1
- data/lib/lca.rb +3 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62afb1561f978b69743ea334e439cc449375f0b4bc1cad29601b174a5d231a41
|
4
|
+
data.tar.gz: 1f18a6226d1fee18f3e2d226616c34dd3cae9ba99389ef9ffb17cf828c586e34
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e190b6449f86a075d6582276747f6f17b1d617cf404f1db04ef7600f7ac9a84490d60535901a9b1e3fc212fb855b381fb80f78d583db391a159b27c75b63e9a3
|
7
|
+
data.tar.gz: b2fc67ead55300e549192c8f1b37e2971e11bc4da9ed08956ea46a601fc6aba1596a56106822f1b085e2c82d94560975bcc301ef8df3946121a331ddcd925a7f
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
Storing, processing and working with life-cycle assessment data has always been challenging. A multitude of data models and implementations exist already but every one of them makes huge compromises or lacks functionality.
|
6
6
|
|
7
|
-
This gem implements a denormalized database model for life-cycle assessment data as well as several
|
7
|
+
This gem implements a denormalized database model for life-cycle assessment data as well as several vectors for convenient querying.
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
@@ -42,42 +42,42 @@ Include the LCA concern into one of your models which will own lifecycle trees (
|
|
42
42
|
This will extend your model and enable the following functionality:
|
43
43
|
|
44
44
|
```ruby
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
# query with ActiveRecord syntax
|
46
|
+
User.last.lca_cycles
|
47
|
+
User.find_by(name: "Acme").lca_cycles.impacts.select("impact_unit, sum(impact_amount) as total_impact").group(:impact_unit)
|
48
|
+
User.last.lca_cycles.where(...)
|
49
|
+
User.last.lca_cycles.where(...).group(...)
|
50
|
+
User.last.lca_cycles.where(...).limit(...).offset(...)
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
52
|
+
# AR query with ltree syntax
|
53
|
+
User.last.lca_cycles.disabled.match_path("*.CustomProcess.*")
|
54
|
+
User.last.lca_cycles.match_path("*{5,10}.CustomProcess.*.Ecosphere.*")
|
55
|
+
User.last.lca_cycles.active.match_path("*.WhateverProcess.*.Ecosphere.*.CO2Emission.*").where( impact_amount: [100..150]).sum(:impact_amount)
|
56
|
+
|
57
|
+
Lca::Cycle.match_path("Top.Electric Vehicle.*").impacts.match_path("*.CO2*").where( impact_amount: [ 1000..10000 ]).average(:impact_amount)
|
58
|
+
Lca::Cycle::Product.where(name: "Electric Vehicle Battery").impacts.match_path("*.Cobalt.*").sum(:impact_amount)
|
59
|
+
Lca::Process.where(owner: User.last).match_path("*{10,20}.*Assembly, automated.*")
|
60
|
+
Lca::Impact.match_path("*.Transport by truck.*")
|
61
|
+
Lca::Exchange.match_path("*.Oil.*.Ecosphere.*").impacts.sum(:impact_amount)
|
62
|
+
Lca::Product.match_path("*.ElectricVehicle.*").processes.match_path("*.Processing.*").where(location: "EU").impacts.match_path("*.Lithium.*").where(location: ["CN", "Africa"]).sum(:impact_amount)
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
# pg_ltree queries
|
65
|
+
User.last.lca_cycles.last.parent
|
66
|
+
Lca::Process.match_path("*.Manual assembly.*").children
|
67
67
|
|
68
|
-
|
69
|
-
|
68
|
+
# pg_ltree combined with AR syntax
|
69
|
+
User.last.lca_cycles(type: "Lca::Product").children.match_path("*.Retail").children.exchanges
|
70
70
|
|
71
|
-
|
72
|
-
|
71
|
+
# all queries can be directed to a specific partition:
|
72
|
+
Lca::Process.owned_by( owner_id ).match_path("*.Recycling.*").where(impact_unit: "tons CO2/year").impacts.sum(:impact_amount)
|
73
73
|
|
74
74
|
```
|
75
75
|
|
76
76
|
The gem also creates some default models:
|
77
77
|
|
78
78
|
```ruby
|
79
|
-
|
80
|
-
|
79
|
+
Lca::Process::Transport::ByAir.match_path("*.CO2Emission.*").impacts.sum(:impact_amount)
|
80
|
+
Lca::Impact::Ecosphere::Fauna.match_path("*.ResourceExtraction.*").where(impact_unit: "Species killed/year").sum(:impact_amount)
|
81
81
|
```
|
82
82
|
|
83
83
|
To see what syntax to use for path traversal please check out the following resources:
|
@@ -88,14 +88,30 @@ The LCA gem is designed to be compatible with PostgREST. PostgREST is an amazing
|
|
88
88
|
|
89
89
|
If the `create_postgrest_roles` setting is on each new owner will be assigned a Postgres role allowing them to access data within their partition using PostgREST. Your owner model will be extended with a `.generate_jwt` method you can use to generate the PostgREST authentication token.
|
90
90
|
|
91
|
+
## Caveats
|
92
|
+
|
93
|
+
`pg_ltree` .child / .parent queries do not work across different models due to an ActiveRecord limitation that requires results to be related via inheritance.
|
94
|
+
|
95
|
+
The following behaviors have been observed:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
|
99
|
+
Lca::Process.last.children.impacts.where(impact_amount: 50)
|
100
|
+
# => nil
|
101
|
+
|
102
|
+
Lca::Process.last.children.unscope(where: :type).impacts.where(impact_amount: 50)
|
103
|
+
# => ActiveRecord::SubclassNotFound (Invalid single-table inheritance type: Lca::Impact is not a subclass of Lca::Process)
|
104
|
+
```
|
105
|
+
|
91
106
|
## Roadmap
|
92
107
|
|
93
|
-
*
|
108
|
+
* .child / .parent query support across models unrelated through inheritance
|
109
|
+
* more model templates for various LCA cycles, processes and impacts
|
94
110
|
* model validations
|
95
|
-
* query objects
|
111
|
+
* query objects
|
112
|
+
* postgres RECURSIVE queries
|
96
113
|
* builders
|
97
114
|
* seeds/fixtures
|
98
|
-
* automated tests
|
99
115
|
|
100
116
|
|
101
117
|
## Contributing
|
@@ -14,19 +14,23 @@ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version
|
|
14
14
|
id serial,
|
15
15
|
|
16
16
|
owner_id integer,
|
17
|
-
|
17
|
+
owner_type character varying,
|
18
|
+
|
19
|
+
status integer,
|
18
20
|
|
19
|
-
data_external_id
|
20
|
-
data_provider
|
21
|
+
data_external_id character varying,
|
22
|
+
data_provider character varying,
|
21
23
|
|
22
|
-
type
|
24
|
+
type character varying,
|
23
25
|
name text,
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
+
parent_entity_id integer,
|
28
|
+
parent_entity_type character varying,
|
27
29
|
|
28
30
|
path ltree,
|
29
31
|
path_slug text,
|
32
|
+
|
33
|
+
metadata_inline jsonb,
|
30
34
|
|
31
35
|
impact_amount decimal,
|
32
36
|
impact_amount_unit text,
|
@@ -44,7 +48,7 @@ SQL
|
|
44
48
|
add_index LCA_OPTIONS[:table_name], :id
|
45
49
|
add_index LCA_OPTIONS[:table_name], :owner_id
|
46
50
|
add_index LCA_OPTIONS[:table_name], :type
|
47
|
-
add_index LCA_OPTIONS[:table_name], :
|
51
|
+
add_index LCA_OPTIONS[:table_name], :parent_entity_id
|
48
52
|
|
49
53
|
# next two indexes unfortunately can't be unique since a cycle can appear several times under an owner
|
50
54
|
add_index LCA_OPTIONS[:table_name], :path, using: :gist
|
@@ -57,5 +61,19 @@ SQL
|
|
57
61
|
execute "create role postgrest_anon nologin"
|
58
62
|
execute "grant postgrest_anon to #{ LCA_OPTIONS[:database_user] }"
|
59
63
|
end
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
#
|
68
|
+
create_table "#{ LCA_OPTIONS[:table_name] }_metadata" do |t|
|
69
|
+
t.string :model_type
|
70
|
+
t.integer :model_id
|
71
|
+
t.string :key
|
72
|
+
t.text :value
|
73
|
+
|
74
|
+
t.timestamps
|
75
|
+
end
|
76
|
+
add_index "#{ LCA_OPTIONS[:table_name] }_metadata", [ :model_type, :model_id ]
|
77
|
+
add_index "#{ LCA_OPTIONS[:table_name] }_metadata", [ :key ]
|
60
78
|
end
|
61
79
|
end
|
data/lib/lca/active_record.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# this still needed?
|
2
1
|
# we include the concern manually so there should be no need for this anymore
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
# besides, no need to polute other classes with our stuff.
|
3
|
+
|
4
|
+
# ActiveSupport.on_load(:active_record) do
|
5
|
+
# extend Lca::Lcable
|
6
|
+
# end
|
@@ -12,7 +12,7 @@ module Lca
|
|
12
12
|
|
13
13
|
included do
|
14
14
|
|
15
|
-
has_many :lca_cycles, class_name: "::Lca::
|
15
|
+
has_many :lca_cycles, class_name: "::Lca::Model", foreign_key: :owner_id, as: :owner
|
16
16
|
after_create :lca_create_storage
|
17
17
|
before_destroy :lca_delete_storage
|
18
18
|
|
@@ -13,8 +13,13 @@ module Lca::Statusable
|
|
13
13
|
alias_method :disable!, :inactive!
|
14
14
|
alias_method :off!, :inactive!
|
15
15
|
alias_method :toggle?, :toggle_status!
|
16
|
+
|
17
|
+
before_create :set_default_status
|
16
18
|
end
|
17
19
|
|
20
|
+
def set_default_status
|
21
|
+
self.status ||= 1
|
22
|
+
end
|
18
23
|
|
19
24
|
def toggle_status!
|
20
25
|
if active?
|
data/lib/lca/models/cycle.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Lca::Cycle < Lca::Model
|
2
2
|
|
3
|
-
has_many :stages, class_name: "::Lca::Stage", foreign_key: :
|
3
|
+
has_many :stages, class_name: "::Lca::Stage", foreign_key: :parent_entity_id, dependent: :destroy
|
4
4
|
|
5
5
|
def subcycles
|
6
6
|
::Lca::Cycle.match_path("#{path}.*")
|
data/lib/lca/models/exchange.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
class Lca::Exchange < Lca::Model
|
2
|
-
belongs_to :process, class_name: "::Lca::Process", foreign_key: :
|
3
|
-
has_many :impacts, class_name: "::Lca::Impact", foreign_key: :
|
2
|
+
belongs_to :process, class_name: "::Lca::Process", foreign_key: :parent_entity_id, required: true
|
3
|
+
has_many :impacts, class_name: "::Lca::Impact", foreign_key: :parent_entity_id, dependent: :destroy
|
4
4
|
end
|
data/lib/lca/models/impact.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Lca::Impact < Lca::Model
|
2
|
-
belongs_to :exchange, class_name: "::Lca::Exchange", foreign_key: :
|
3
|
-
|
2
|
+
belongs_to :exchange, class_name: "::Lca::Exchange", foreign_key: :parent_entity_id, required: true
|
3
|
+
|
4
4
|
validates_presence_of :impact_amount
|
5
5
|
validates_presence_of :impact_amount_unit, allow_blank: false
|
6
6
|
validates_presence_of :impact_factor
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Lca::Metadata < ActiveRecord::Base
|
2
|
+
|
3
|
+
belongs_to :model, polymorphic: true, required: true
|
4
|
+
|
5
|
+
def self.table_name
|
6
|
+
return "#{ ::LCA_OPTIONS[:table_name] }_metadata" if defined? ::LCA_OPTIONS
|
7
|
+
return "lca_models_metadata"
|
8
|
+
end
|
9
|
+
|
10
|
+
validates_presence_of :key
|
11
|
+
|
12
|
+
end
|
data/lib/lca/models/model.rb
CHANGED
@@ -4,12 +4,14 @@ class Lca::Model < ActiveRecord::Base
|
|
4
4
|
|
5
5
|
self.primary_key = :id
|
6
6
|
|
7
|
+
ltree :path
|
8
|
+
|
7
9
|
def self.table_name
|
8
10
|
return ::LCA_OPTIONS[:table_name] if defined? ::LCA_OPTIONS
|
9
11
|
return "lca_models"
|
10
12
|
end
|
11
13
|
|
12
|
-
belongs_to :owner, polymorphic: :true
|
14
|
+
belongs_to :owner, polymorphic: :true, required: true
|
13
15
|
|
14
16
|
scope :match_path, -> (some_path) { where("path ~ ?", "#{some_path}") }
|
15
17
|
|
@@ -19,10 +21,13 @@ class Lca::Model < ActiveRecord::Base
|
|
19
21
|
validates_presence_of :name, allow_blank: false
|
20
22
|
validates_presence_of :path, allow_blank: false
|
21
23
|
|
22
|
-
|
24
|
+
has_many :metadata, class_name: "::Lca::Metadata", dependent: :destroy, as: :model
|
25
|
+
|
26
|
+
before_validation :set_defaults
|
23
27
|
def set_defaults
|
24
|
-
self.path ||= name.
|
25
|
-
self.path_slug = path.parameterize
|
28
|
+
self.path ||= name.delete(" ").gsub(/[^0-9a-z ]/i, '') if name
|
29
|
+
self.path_slug = path.parameterize if path
|
30
|
+
self.metadata_inline ||= {}
|
26
31
|
end
|
27
32
|
|
28
33
|
|
@@ -57,6 +62,10 @@ class Lca::Model < ActiveRecord::Base
|
|
57
62
|
class_name
|
58
63
|
end
|
59
64
|
|
65
|
+
model_class.define_singleton_method(:sti_name) do
|
66
|
+
original_class_name
|
67
|
+
end
|
68
|
+
|
60
69
|
# override the STI name lmfao
|
61
70
|
model_class.define_singleton_method(:find_sti_class) do |p|
|
62
71
|
original_class_name.constantize
|
data/lib/lca/models/process.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
class Lca::Process < Lca::Model
|
2
2
|
|
3
|
-
has_many :exchanges, class_name: "::Lca::Exchange", foreign_key: :
|
3
|
+
has_many :exchanges, class_name: "::Lca::Exchange", foreign_key: :parent_entity_id, dependent: :destroy
|
4
4
|
has_many :impacts, through: :exchanges
|
5
|
-
belongs_to :stage, class_name: "::Lca::Stage", foreign_key: :parent_id
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
has_many :subprocesses, class_name: "::Lca::Process", foreign_key: :parent_entity_id, dependent: :destroy, as: :parent_entity
|
7
|
+
belongs_to :parent_entity, polymorphic: true, required: true
|
8
|
+
|
10
9
|
end
|
data/lib/lca/models/stage.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Lca::Stage < Lca::Model
|
2
2
|
|
3
|
-
belongs_to :cycle, class_name: "::Lca::Cycle", foreign_key: :
|
4
|
-
has_many :processes, class_name: "::Lca::Process", foreign_key: :
|
3
|
+
belongs_to :cycle, class_name: "::Lca::Cycle", foreign_key: :parent_entity_id, required: true
|
4
|
+
has_many :processes, class_name: "::Lca::Process", foreign_key: :parent_entity_id
|
5
5
|
|
6
6
|
end
|
data/lib/lca/version.rb
CHANGED
data/lib/lca.rb
CHANGED
@@ -3,9 +3,12 @@ require "active_support/all"
|
|
3
3
|
|
4
4
|
require "active_record"
|
5
5
|
|
6
|
+
require "pg_ltree"
|
7
|
+
|
6
8
|
require_relative "lca/version"
|
7
9
|
|
8
10
|
require_relative "lca/models/concerns/statusable"
|
11
|
+
require_relative "lca/models/metadata"
|
9
12
|
require_relative "lca/models/model"
|
10
13
|
require_relative "lca/models/cycle"
|
11
14
|
require_relative "lca/models/stage"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick @ Earthster
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-09-
|
11
|
+
date: 2021-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -118,6 +118,7 @@ files:
|
|
118
118
|
- lib/lca/models/impact/human_health/cancer.rb
|
119
119
|
- lib/lca/models/impact/technosphere.rb
|
120
120
|
- lib/lca/models/impact/technosphere/resource_availability.rb
|
121
|
+
- lib/lca/models/metadata.rb
|
121
122
|
- lib/lca/models/model.rb
|
122
123
|
- lib/lca/models/process.rb
|
123
124
|
- lib/lca/models/process/raw_resource.rb
|