lca 0.2.2 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c465bce714b41f2b8ac878d9ba5df4f6d4797fd29005ce325bc4d415354a144
4
- data.tar.gz: 7d5e3cb3aefaa080899483e3031f0d93a81b2907fadac1f43c27cdc819f5a87b
3
+ metadata.gz: 3d5a7b8821030f1d77f41f6fda374ffa6179bf8f412355380dbabb17618d820f
4
+ data.tar.gz: 1a16958b8df53caa76ade2b50ab6e8a3e522267ba16ae03c19da3667a6f13ea9
5
5
  SHA512:
6
- metadata.gz: ea29b421a25379cc4891d94113a49fbd73c8f4ee7dbc0bb5e3cffb6d80a0841e7bd9aca05dc1c2fb09d7091f863b9a888b8980770ede5369baf2bff993e9e331
7
- data.tar.gz: f4124579adc16d992dddfca9740e3212bb91098d06095f965ef2704a7a0a66a90ecd71cbe0d574a98cf8c1e7fe294bee1f654e4f1c1531cdfbc8cbcab000ed72
6
+ metadata.gz: a16076c63779cd5dd152e6c4a95a0a332274659648155ff69b61b2d9540e72f74a726155eeac7ae71287d634aceeb5227e2f174e7ff6b418ff2e72b2ec7c1704
7
+ data.tar.gz: 194fa4db64be6e462c6be6dfc17eeb4acc7e4861778fd6b292830af20ef394e3a82db564a9199bea8f7fee75e884400058809540b3bc161a54bb007f6c1b1811
data/Gemfile CHANGED
@@ -9,4 +9,7 @@ gem "rspec", "~> 3.0"
9
9
 
10
10
  gem "activerecord", "~> 6.0"
11
11
  gem "activestorage", "~> 6.0"
12
- gem "actiontext", "~> 6.0"
12
+ gem "actiontext", "~> 6.0"
13
+
14
+ gem "jwt"
15
+ gem "pg_ltree"
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 innovative query interfaces.
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
- # 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(...)
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
- # 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)
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
- # pg_ltree queries
65
- User.last.lca_cycles.last.parent
66
- Lca::Process.match_path("*.Manual assembly.*").children
64
+ # pg_ltree queries
65
+ User.last.lca_cycles.last.parent
66
+ Lca::Process.match_path("*.Manual assembly.*").children
67
67
 
68
- # pg_ltree combined with AR syntax
69
- User.last.lca_cycles(type: "Lca::Product").children.match_path("*.Retail").children.exchanges
68
+ # pg_ltree combined with AR syntax
69
+ User.last.lca_cycles(type: "Lca::Product").children.match_path("*.Retail").children.exchanges
70
70
 
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)
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
- 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)
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
- * more models for various LCA cycles, processes and impacts
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, including postgres RECURSIVE queries
111
+ * query objects
112
+ * postgres RECURSIVE queries
96
113
  * builders
97
114
  * seeds/fixtures
98
- * automated tests
99
115
 
100
116
 
101
117
  ## Contributing
@@ -3,53 +3,66 @@ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version
3
3
 
4
4
  # enable ltree extension
5
5
  begin
6
- execute "create extension ltree"
6
+ execute "create extension ltree"
7
7
  rescue
8
- p "LTREE was already enabled"
8
+ p "LTREE was already enabled"
9
9
  end
10
+
10
11
 
11
- # LCA_OPTIONS[:table_name]
12
+ # create the main table as set up within LCA_OPTIONS[:table_name]
12
13
  execute <<-SQL
13
14
  create table #{ LCA_OPTIONS[:table_name] } (
14
15
  id serial,
15
16
 
16
17
  owner_id integer,
17
- owner_type text,
18
+ owner_type character varying,
19
+
20
+ status integer,
18
21
 
19
- data_external_id text,
20
- data_provider text,
22
+ data_external_id character varying,
23
+ data_provider character varying,
21
24
 
22
- type text,
25
+ type character varying,
23
26
  name text,
24
27
 
25
- parent_id integer,
26
- parent_type text,
28
+ parent_entity_id integer,
29
+ parent_entity_type character varying,
27
30
 
28
31
  path ltree,
29
32
  path_slug text,
33
+
34
+ metadata_inline jsonb,
30
35
 
31
36
  impact_amount decimal,
37
+ impact_amount_previous decimal,
32
38
  impact_amount_unit text,
33
39
  impact_factor decimal,
34
40
  impact_precision decimal,
41
+
42
+ created_at timestamp(6) without time zone not null,
43
+ updated_at timestamp(6) without time zone not null,
44
+
35
45
 
36
46
  primary key (id, owner_id)
37
47
  ) partition by list(owner_id)
38
48
  SQL
39
49
 
40
- # TODO do we want to also create an "others" partition?
41
- # "CREATE TABLE #{LCA_OPTIONS[:table_name]}_others PARTITION OF #{LCA_OPTIONS[:table_name]} DEFAULT"
50
+ # create an "others" partition for when the owner is undefined/unknown? just in case / may help in some edge cases
51
+ execute "CREATE TABLE #{LCA_OPTIONS[:table_name]}_others PARTITION OF #{LCA_OPTIONS[:table_name]} DEFAULT"
52
+
42
53
 
43
54
  # add indexes
44
55
  add_index LCA_OPTIONS[:table_name], :id
45
56
  add_index LCA_OPTIONS[:table_name], :owner_id
46
57
  add_index LCA_OPTIONS[:table_name], :type
47
- add_index LCA_OPTIONS[:table_name], :parent_id
58
+ add_index LCA_OPTIONS[:table_name], :parent_entity_id
48
59
 
49
60
  # next two indexes unfortunately can't be unique since a cycle can appear several times under an owner
50
61
  add_index LCA_OPTIONS[:table_name], :path, using: :gist
51
62
  add_index LCA_OPTIONS[:table_name], [:data_provider, :data_external_id]
52
63
 
64
+
65
+ # when postgrest is enabled...
53
66
  if LCA_OPTIONS[:create_postgrest_roles]
54
67
  # create postgrest anon user with no privs
55
68
  # postgrest may pass an user's role using JWT
@@ -57,5 +70,49 @@ SQL
57
70
  execute "create role postgrest_anon nologin"
58
71
  execute "grant postgrest_anon to #{ LCA_OPTIONS[:database_user] }"
59
72
  end
73
+
74
+
75
+ # snapshots table
76
+ # maybe this should only store the impacts?
77
+ execute <<-SQL
78
+ create table #{ LCA_OPTIONS[:table_name] }_snapshots (
79
+ id serial,
80
+
81
+ impact_id integer,
82
+
83
+ owner_id integer,
84
+ owner_type character varying,
85
+
86
+ impact_amount decimal,
87
+ impact_amount_previous decimal,
88
+ impact_amount_unit text,
89
+ impact_factor decimal,
90
+ impact_precision decimal,
91
+
92
+ created_at timestamp(6) without time zone not null,
93
+ updated_at timestamp(6) without time zone not null,
94
+
95
+ primary key (id, owner_id)
96
+ ) partition by list(owner_id)
97
+ SQL
98
+
99
+ # index the snapshots table
100
+ add_index "#{LCA_OPTIONS[:table_name]}_snapshots", :id
101
+ add_index "#{LCA_OPTIONS[:table_name]}_snapshots", :owner_id
102
+ add_index "#{LCA_OPTIONS[:table_name]}_snapshots", :impact_id
103
+ add_index "#{LCA_OPTIONS[:table_name]}_snapshots", :created_at
104
+
105
+
106
+ # metadata table
107
+ create_table "#{ LCA_OPTIONS[:table_name] }_metadata" do |t|
108
+ t.string :model_type
109
+ t.integer :model_id
110
+ t.string :key
111
+ t.text :value
112
+
113
+ t.timestamps
114
+ end
115
+ add_index "#{ LCA_OPTIONS[:table_name] }_metadata", [ :model_type, :model_id ]
116
+ add_index "#{ LCA_OPTIONS[:table_name] }_metadata", [ :key ]
60
117
  end
61
118
  end
@@ -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
- ActiveSupport.on_load(:active_record) do
4
- puts "tf is AR still being extended?"
5
- extend Lca::Lcable
6
- end
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
@@ -1,18 +1,14 @@
1
1
  require "jwt"
2
2
 
3
+ # read https://www.postgresqltutorial.com/postgresql-schema/
4
+
3
5
  module Lca
4
6
  module Lcable
5
7
  extend ActiveSupport::Concern
6
8
 
7
- # def self.included(base)
8
- # ::Lca::Model.class_exec do
9
- # @@owner_class = base.name
10
- # end
11
- # end
12
-
13
9
  included do
14
10
 
15
- has_many :lca_cycles, class_name: "::Lca::Cycle", foreign_key: :owner_id, as: :owner
11
+ has_many :lca_cycles, class_name: "::Lca::Model", foreign_key: :owner_id, as: :owner
16
12
  after_create :lca_create_storage
17
13
  before_destroy :lca_delete_storage
18
14
 
@@ -41,16 +37,21 @@ module Lca
41
37
  lca_sql "create table if not exists #{lca_table_name}_#{id} partition of #{lca_table_name} for values in (#{id})"
42
38
  # TODO create partition indexes
43
39
 
44
- if LCA_OPTIONS[:create_postgrest_roles]
45
- # drop role if it exists
46
- lca_sql "drop role if exists #{ lca_role }"
40
+ # create snapshots partition
41
+ lca_sql "create table if not exists #{lca_table_name}_snapshots_#{id} partition of #{lca_table_name}_snapshots for values in (#{id})"
42
+ # TODO create partition indexes
43
+
44
+ if LCA_OPTIONS[:create_postgrest_roles]
45
+ # drop role if it exists
46
+ lca_sql "drop role if exists #{ lca_role }"
47
47
 
48
- # create role
49
- lca_sql "create role #{ lca_role }"
48
+ # create role
49
+ lca_sql "create role #{ lca_role }"
50
50
 
51
- # grant privs
52
- lca_sql "grant all privileges on #{lca_table_name}_#{id} to #{ lca_role }"
53
- end
51
+ # grant privs
52
+ lca_sql "grant all privileges on #{lca_table_name}_#{id} to #{ lca_role }"
53
+ lca_sql "grant all privileges on #{lca_table_name}_snapshots_#{id} to #{ lca_role }"
54
+ end
54
55
 
55
56
  end # create_storage
56
57
 
@@ -58,21 +59,24 @@ module Lca
58
59
  # Deletes or detaches the partition and removes the role for this owner
59
60
  def lca_delete_storage
60
61
 
61
- if LCA_OPTIONS[:create_postgrest_roles]
62
+ if LCA_OPTIONS[:create_postgrest_roles]
62
63
  # revoke privs
63
64
  lca_sql "REVOKE ALL PRIVILEGES ON #{lca_table_name}_#{id} FROM #{ lca_role }"
65
+ lca_sql "REVOKE ALL PRIVILEGES ON #{lca_table_name}_snapshots_#{id} FROM #{ lca_role }"
64
66
 
65
67
  # delete role
66
68
  lca_sql "drop role #{ lca_role }"
67
- end
69
+ end
68
70
 
69
- if LCA_OPTIONS[:destroy_partition_on_owner_destroy]
71
+ if LCA_OPTIONS[:destroy_partition_on_owner_destroy]
70
72
  # delete partition
71
73
  lca_sql "drop table if exists #{lca_table_name}_#{id}"
72
- else
73
- # detach and forget about it
74
- lca_sql "alter table #{lca_table_name} detach partition #{ lca_role }"
75
- end
74
+ lca_sql "drop table if exists #{lca_table_name}_snapshots_#{id}"
75
+ else
76
+ # detach and forget about it
77
+ lca_sql "alter table #{lca_table_name} detach partition #{ lca_role }"
78
+ lca_sql "alter table #{lca_table_name}_snapshots detach partition #{ lca_role }"
79
+ end
76
80
  end # delete_storage
77
81
 
78
82
  def lca_sql sql
@@ -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?
@@ -1,6 +1,6 @@
1
1
  class Lca::Cycle < Lca::Model
2
2
 
3
- has_many :stages, class_name: "::Lca::Stage", foreign_key: :parent_id, dependent: :destroy
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}.*")
@@ -1,4 +1,4 @@
1
1
  class Lca::Exchange < Lca::Model
2
- belongs_to :process, class_name: "::Lca::Process", foreign_key: :parent_id
3
- has_many :impacts, class_name: "::Lca::Impact", foreign_key: :parent_id, dependent: :destroy
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
@@ -1,8 +1,23 @@
1
1
  class Lca::Impact < Lca::Model
2
- belongs_to :exchange, class_name: "::Lca::Exchange", foreign_key: :parent_id
3
-
2
+ belongs_to :exchange, class_name: "::Lca::Exchange", foreign_key: :parent_entity_id, required: true
3
+
4
+ has_many :snapshots, class_name: "::Lca::ImpactSnapshot", foreign_key: :impact_id, dependent: :destroy
5
+
4
6
  validates_presence_of :impact_amount
5
7
  validates_presence_of :impact_amount_unit, allow_blank: false
6
8
  validates_presence_of :impact_factor
7
9
  validates_presence_of :impact_precision
10
+
11
+ # lol?
12
+ before_update :snapshot!
13
+
14
+
15
+ def snapshot!
16
+ return ::Lca::ImpactSnapshot.create(
17
+ self.attributes
18
+ .deep_symbolize_keys
19
+ .slice(:impact_amount, :impact_amount_unit, :impact_factor, :impact_precision, :owner_id, :owner_type)
20
+ .merge( impact_id: id )
21
+ )
22
+ end # .snapshot!
8
23
  end
@@ -0,0 +1,44 @@
1
+ class Lca::ImpactSnapshot < ActiveRecord::Base
2
+
3
+ self.primary_key = :id
4
+
5
+ def self.table_name
6
+ return "#{::LCA_OPTIONS[:table_name]}_snapshots" if defined? ::LCA_OPTIONS
7
+ return "lca_models_snapshots"
8
+ end
9
+
10
+
11
+ belongs_to :impact, class_name: "::Lca::Impact", foreign_key: :impact_id, required: true
12
+ belongs_to :owner, polymorphic: true, required: true
13
+
14
+ validates_presence_of :impact_amount
15
+ validates_presence_of :impact_amount_unit, allow_blank: false
16
+ validates_presence_of :impact_factor
17
+ validates_presence_of :impact_precision
18
+
19
+ # pull data from owner's partition
20
+ def self.owned_by(owner_id)
21
+ return self if !owner_id.is_a? Integer
22
+ partition_suffix = "_#{owner_id}"
23
+ table = "#{ self.table_name }#{ partition_suffix }"
24
+
25
+ ApplicationRecord.connection.schema_cache.clear!
26
+ return self if !ApplicationRecord.connection.schema_cache.data_source_exists? table
27
+
28
+ model_class = Class.new self
29
+
30
+ original_class_name = self.name
31
+ class_name = "#{name}#{partition_suffix}"
32
+
33
+ model_class.define_singleton_method(:table_name) do
34
+ table
35
+ end
36
+
37
+ model_class.define_singleton_method(:name) do
38
+ class_name
39
+ end
40
+
41
+ model_class
42
+ end # owned_by
43
+
44
+ end
@@ -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
@@ -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
 
24
+ has_many :metadata, class_name: "::Lca::Metadata", dependent: :destroy, as: :model
25
+
22
26
  before_validation :set_defaults
23
27
  def set_defaults
24
- self.path ||= name.parameterize.gsub("-", ".")
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
@@ -1,10 +1,9 @@
1
1
  class Lca::Process < Lca::Model
2
2
 
3
- has_many :exchanges, class_name: "::Lca::Exchange", foreign_key: :parent_id, dependent: :destroy
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
- def subprocesses
8
- ::Lca::Process.where("path ~ ?", "#{path}.*")
9
- end
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
@@ -1,6 +1,6 @@
1
1
  class Lca::Stage < Lca::Model
2
2
 
3
- belongs_to :cycle, class_name: "::Lca::Cycle", foreign_key: :parent_id
4
- has_many :processes, class_name: "::Lca::Process", foreign_key: :parent_id
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lca
4
- VERSION = "0.2.2"
4
+ VERSION = "0.2.6"
5
5
  end
data/lib/lca.rb CHANGED
@@ -3,15 +3,19 @@ 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"
12
15
  require_relative "lca/models/process"
13
16
  require_relative "lca/models/exchange"
14
17
  require_relative "lca/models/impact"
18
+ require_relative "lca/models/impact_snapshot"
15
19
  require_relative "lca/models/cycle/product"
16
20
  require_relative "lca/models/cycle/service"
17
21
  require_relative "lca/models/cycle/activity"
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.2
4
+ version: 0.2.6
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-25 00:00:00.000000000 Z
11
+ date: 2021-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -118,6 +118,8 @@ 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/impact_snapshot.rb
122
+ - lib/lca/models/metadata.rb
121
123
  - lib/lca/models/model.rb
122
124
  - lib/lca/models/process.rb
123
125
  - lib/lca/models/process/raw_resource.rb