composite_primary_keys 9.0.4 → 9.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.rdoc +20 -0
- data/Rakefile +37 -34
- data/lib/composite_primary_keys.rb +5 -10
- data/lib/composite_primary_keys/arel/in.rb +6 -6
- data/lib/composite_primary_keys/arel/sqlserver.rb +36 -0
- data/lib/composite_primary_keys/associations/association_scope.rb +51 -29
- data/lib/composite_primary_keys/attribute_methods/read.rb +3 -1
- data/lib/composite_primary_keys/connection_adapters/abstract_mysql_adapter.rb +22 -0
- data/lib/composite_primary_keys/relation.rb +30 -0
- data/lib/composite_primary_keys/relation/query_methods.rb +25 -36
- data/lib/composite_primary_keys/sanitization.rb +31 -47
- data/lib/composite_primary_keys/version.rb +1 -1
- data/tasks/databases/mysql.rake +40 -42
- data/tasks/databases/oracle.rake +29 -15
- data/tasks/databases/postgresql.rake +38 -47
- data/tasks/databases/sqlite.rake +25 -0
- data/tasks/databases/sqlserver.rake +32 -16
- data/test/abstract_unit.rb +12 -11
- data/test/connections/connection_spec.rb +27 -18
- data/test/connections/databases.ci.yml +5 -4
- data/test/connections/databases.example.yml +19 -4
- data/test/connections/databases.yml +25 -4
- data/test/fixtures/article.rb +6 -5
- data/test/fixtures/db_definitions/mysql.sql +16 -7
- data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle.sql +25 -15
- data/test/fixtures/db_definitions/postgresql.sql +11 -2
- data/test/fixtures/db_definitions/sqlite.sql +8 -0
- data/test/fixtures/db_definitions/sqlserver.sql +19 -33
- data/test/fixtures/pk_called_id.rb +5 -0
- data/test/fixtures/pk_called_ids.yml +11 -0
- data/test/test_associations.rb +334 -332
- data/test/test_create.rb +9 -1
- data/test/test_delete.rb +17 -39
- data/test/test_ids.rb +113 -109
- data/test/test_preload.rb +94 -0
- data/test/test_suite.rb +1 -1
- data/test/test_update.rb +12 -7
- metadata +14 -24
- data/lib/composite_primary_keys/associations/singular_association.rb +0 -14
- data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb +0 -71
- data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +0 -50
- data/lib/composite_primary_keys/dirty.rb +0 -19
- data/lib/composite_primary_keys/validations/uniqueness.rb +0 -41
- data/tasks/databases/oracle_enhanced.rake +0 -27
- data/tasks/databases/sqlite3.rake +0 -27
- data/test/connections/native_ibm_db/connection.rb +0 -19
- data/test/connections/native_mysql/connection.rb +0 -17
- data/test/connections/native_oracle/connection.rb +0 -11
- data/test/connections/native_oracle_enhanced/connection.rb +0 -16
- data/test/connections/native_postgresql/connection.rb +0 -13
- data/test/connections/native_sqlite3/connection.rb +0 -9
- data/test/connections/native_sqlserver/connection.rb +0 -11
- data/test/fixtures/db_definitions/sqlserver.drop.sql +0 -92
- data/test/test_delete_all.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a7db1ee79736fa3b98274e9577f650d27c239cd
|
4
|
+
data.tar.gz: 4e121d1420ba01fc56073d176888687ca78d2177
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94556da0f6cfb30ed3285635ebcdbff725d5c7ad9098c3de8b63c3920c93ae1739ab27608f2c32113c8514a688ab1fadd5effddfe05b8c67ccaaed39c7f56b69
|
7
|
+
data.tar.gz: df406dbc3ec9c24df294088f033ec760af5602a3ce09891ad23f5f0200bdfbba4658cf4765fc65c5f4df86ca9f749ee9f7740fb3f7c430751d201e649dd7a7c1
|
data/History.rdoc
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
== 9.0.5 (2017-01-02)
|
2
|
+
|
3
|
+
* Don't nest PK twice when looking up id, fixes #319 (Kerey Roper)
|
4
|
+
* Simplify database setup for tests (Charlie Savage)
|
5
|
+
* Revamp gem management (Charlie Savage)
|
6
|
+
* Add support for Relation#update_all when using joins (Charlie Savage)
|
7
|
+
* Add erb support to test database.yml files (Charlie Savage)
|
8
|
+
* Sqlserver fixes for ordering (Charlie Savage)
|
9
|
+
* Sqlserver refresh (Charlie Savage)
|
10
|
+
* Oracle refresh (Charlie Savage)
|
11
|
+
* Fix delete_all for MySql (Charlie Savage)
|
12
|
+
* Added test cases for preloading associations with and without conditions (Martin Körner)
|
13
|
+
* Revamp single association handling to correctly setup SQL binds (Charlie Savage)
|
14
|
+
* Remove references to ActiveModel - #352 (Charlie Savage)
|
15
|
+
* Fixes for #232, #359, #367 and #371 (Charlie Savage)
|
16
|
+
|
1
17
|
== 9.0.4 (2016-08-17)
|
2
18
|
* Do not set associations to readonly. See https://github.com/rails/rails/issues/24093 (Charlie Savage)
|
3
19
|
|
@@ -13,6 +29,10 @@
|
|
13
29
|
== 9.0.0.beta1 (2016-04-16)
|
14
30
|
* Rails 5 beta support (Sammy Larbi)
|
15
31
|
|
32
|
+
== 8.1.5 (2017-01-01)
|
33
|
+
|
34
|
+
* Don't nest PK twice when looking up id, fixes #319 (Kerey Roper)
|
35
|
+
|
16
36
|
== 8.1.4 (2016-07-27)
|
17
37
|
|
18
38
|
* Create OR predicates in a nicely balanced tree fixing #320 (Nathan Samson)
|
data/Rakefile
CHANGED
@@ -1,34 +1,37 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'rake'
|
3
|
-
require 'rake/clean'
|
4
|
-
require 'rake/testtask'
|
5
|
-
require 'rubygems/package_task'
|
6
|
-
|
7
|
-
# Set global variable so other tasks can access them
|
8
|
-
::PROJECT_ROOT = File.expand_path(".")
|
9
|
-
::GEM_NAME = 'composite_primary_keys'
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
Gem::
|
16
|
-
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
Rake::
|
32
|
-
|
33
|
-
|
34
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rubygems/package_task'
|
6
|
+
|
7
|
+
# Set global variable so other tasks can access them
|
8
|
+
::PROJECT_ROOT = File.expand_path(".")
|
9
|
+
::GEM_NAME = 'composite_primary_keys'
|
10
|
+
|
11
|
+
require File.join(PROJECT_ROOT, 'lib', 'composite_primary_keys')
|
12
|
+
require File.join(PROJECT_ROOT, 'test', 'connections', 'connection_spec')
|
13
|
+
|
14
|
+
# Read the spec file
|
15
|
+
spec = Gem::Specification.load("#{GEM_NAME}.gemspec")
|
16
|
+
|
17
|
+
# Setup Rake tasks for managing the gem
|
18
|
+
Gem::PackageTask.new(spec).define
|
19
|
+
|
20
|
+
# Now load in other task files
|
21
|
+
Dir.glob('tasks/**/*.rake').each do |rake_file|
|
22
|
+
load File.join(File.dirname(__FILE__), rake_file)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Set up test tasks for each supported connection adapter
|
26
|
+
%w(mysql sqlite oracle oracle_enhanced postgresql ibm_db sqlserver).each do |adapter|
|
27
|
+
namespace adapter do
|
28
|
+
desc "Run tests using the #{adapter} adapter"
|
29
|
+
task "test" do
|
30
|
+
ENV["ADAPTER"] = adapter
|
31
|
+
Rake::TestTask.new("subtest_#{adapter}") do |t|
|
32
|
+
t.libs << "test"
|
33
|
+
end
|
34
|
+
Rake::Task["subtest_#{adapter}"].invoke
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2006-
|
2
|
+
# Copyright (c) 2006-2016 Nic Williams and Charlie Savage
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -58,6 +58,7 @@ require 'active_record/locking/optimistic'
|
|
58
58
|
require 'active_record/nested_attributes'
|
59
59
|
|
60
60
|
require 'active_record/connection_adapters/abstract_adapter'
|
61
|
+
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
61
62
|
|
62
63
|
require 'active_record/relation/batches'
|
63
64
|
require 'active_record/relation/where_clause'
|
@@ -66,8 +67,6 @@ require 'active_record/relation/finder_methods'
|
|
66
67
|
require 'active_record/relation/predicate_builder'
|
67
68
|
require 'active_record/relation/query_methods'
|
68
69
|
|
69
|
-
require 'active_record/validations/uniqueness' unless ENV["TESTING_CPK"] == "true"
|
70
|
-
|
71
70
|
# CPK files
|
72
71
|
require 'composite_primary_keys/persistence'
|
73
72
|
require 'composite_primary_keys/base'
|
@@ -89,11 +88,8 @@ require 'composite_primary_keys/associations/join_dependency'
|
|
89
88
|
require 'composite_primary_keys/associations/join_dependency/join_association'
|
90
89
|
require 'composite_primary_keys/associations/preloader/association'
|
91
90
|
require 'composite_primary_keys/associations/preloader/belongs_to'
|
92
|
-
require 'composite_primary_keys/associations/singular_association'
|
93
91
|
require 'composite_primary_keys/associations/collection_association'
|
94
92
|
|
95
|
-
require 'composite_primary_keys/dirty'
|
96
|
-
|
97
93
|
require 'composite_primary_keys/attribute_methods/primary_key'
|
98
94
|
require 'composite_primary_keys/attribute_methods/read'
|
99
95
|
require 'composite_primary_keys/attribute_methods/write'
|
@@ -101,7 +97,7 @@ require 'composite_primary_keys/locking/optimistic'
|
|
101
97
|
require 'composite_primary_keys/nested_attributes'
|
102
98
|
|
103
99
|
require 'composite_primary_keys/connection_adapters/abstract_adapter'
|
104
|
-
require 'composite_primary_keys/connection_adapters/
|
100
|
+
require 'composite_primary_keys/connection_adapters/abstract_mysql_adapter'
|
105
101
|
|
106
102
|
require 'composite_primary_keys/relation/batches'
|
107
103
|
require 'composite_primary_keys/relation/where_clause'
|
@@ -110,9 +106,8 @@ require 'composite_primary_keys/relation/finder_methods'
|
|
110
106
|
require 'composite_primary_keys/relation/predicate_builder'
|
111
107
|
require 'composite_primary_keys/relation/query_methods'
|
112
108
|
|
113
|
-
require 'composite_primary_keys/validations/uniqueness'
|
114
|
-
|
115
109
|
require 'composite_primary_keys/composite_relation'
|
116
110
|
|
117
111
|
require 'composite_primary_keys/arel/in'
|
118
|
-
require 'composite_primary_keys/arel/to_sql'
|
112
|
+
require 'composite_primary_keys/arel/to_sql'
|
113
|
+
require 'composite_primary_keys/arel/sqlserver'
|
@@ -1,6 +1,6 @@
|
|
1
|
-
module CompositePrimaryKeys
|
2
|
-
module Nodes
|
3
|
-
class In < ::Arel::Nodes::Equality
|
4
|
-
end
|
5
|
-
end
|
6
|
-
end
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module Nodes
|
3
|
+
class In < ::Arel::Nodes::Equality
|
4
|
+
end
|
5
|
+
end
|
6
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Arel
|
2
|
+
module Visitors
|
3
|
+
class SQLServer
|
4
|
+
def make_Fetch_Possible_And_Deterministic o
|
5
|
+
return if o.limit.nil? && o.offset.nil?
|
6
|
+
t = table_From_Statement o
|
7
|
+
pk = primary_Key_From_Table t
|
8
|
+
return unless pk
|
9
|
+
if o.orders.empty?
|
10
|
+
# Prefer deterministic vs a simple `(SELECT NULL)` expr.
|
11
|
+
# CPK
|
12
|
+
#o.orders = [pk.asc]
|
13
|
+
o.orders = pk.map {|a_pk| a_pk.asc}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def primary_Key_From_Table t
|
18
|
+
return unless t
|
19
|
+
column_name = schema_cache.primary_keys(t.name) || column_cache(t.name).first.second.try(:name)
|
20
|
+
|
21
|
+
# CPK
|
22
|
+
# column_name ? t[column_name] : nil
|
23
|
+
case column_name
|
24
|
+
when Array
|
25
|
+
column_name.map do |name|
|
26
|
+
t[name]
|
27
|
+
end
|
28
|
+
when NilClass
|
29
|
+
[t[column_name]]
|
30
|
+
else
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,44 +1,66 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Associations
|
3
3
|
class AssociationScope
|
4
|
-
silence_warnings do
|
5
|
-
def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
|
6
|
-
join_keys = reflection.join_keys(association_klass)
|
7
|
-
key = join_keys.key
|
8
|
-
foreign_key = join_keys.foreign_key
|
9
|
-
# CPK
|
10
|
-
# constraint = table[key].eq(foreign_table[foreign_key])
|
11
|
-
constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
|
12
4
|
|
5
|
+
def self.get_bind_values(owner, chain)
|
6
|
+
binds = []
|
7
|
+
last_reflection = chain.last
|
8
|
+
|
9
|
+
# CPK
|
10
|
+
# binds << last_reflection.join_id_for(owner)
|
11
|
+
values = last_reflection.join_id_for(owner)
|
12
|
+
binds += Array(values)
|
13
|
+
|
14
|
+
if last_reflection.type
|
15
|
+
binds << owner.class.base_class.name
|
16
|
+
end
|
17
|
+
|
18
|
+
chain.each_cons(2).each do |reflection, next_reflection|
|
13
19
|
if reflection.type
|
14
|
-
|
15
|
-
scope = scope.where(table.name => { reflection.type => value })
|
20
|
+
binds << next_reflection.klass.base_class.name
|
16
21
|
end
|
22
|
+
end
|
23
|
+
binds
|
24
|
+
end
|
17
25
|
|
18
|
-
|
26
|
+
def last_chain_scope(scope, table, reflection, owner, association_klass)
|
27
|
+
join_keys = reflection.join_keys(association_klass)
|
28
|
+
key = join_keys.key
|
29
|
+
foreign_key = join_keys.foreign_key
|
30
|
+
|
31
|
+
# CPK
|
32
|
+
#value = transform_value(owner[foreign_key])
|
33
|
+
#scope = scope.where(table.name => { key => value })
|
34
|
+
mappings = Array(key).zip(Array(foreign_key))
|
35
|
+
joins = mappings.reduce(Hash.new) do |hash, mapping|
|
36
|
+
hash[mapping.first] = transform_value(owner[mapping.last])
|
37
|
+
hash
|
19
38
|
end
|
39
|
+
scope = scope.where(table.name => joins)
|
20
40
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
# CPK
|
27
|
-
if key.kind_of?(Array) || foreign_key.kind_of?(Array)
|
28
|
-
predicate = cpk_join_predicate(table, key, owner, foreign_key)
|
29
|
-
scope = scope.where(predicate)
|
30
|
-
else
|
31
|
-
value = transform_value(owner[foreign_key])
|
32
|
-
scope = scope.where(table.name => { key => value })
|
33
|
-
end
|
41
|
+
if reflection.type
|
42
|
+
polymorphic_type = transform_value(owner.class.base_class.name)
|
43
|
+
scope = scope.where(table.name => { reflection.type => polymorphic_type })
|
44
|
+
end
|
34
45
|
|
35
|
-
|
36
|
-
|
37
|
-
scope = scope.where(table.name => { reflection.type => polymorphic_type })
|
38
|
-
end
|
46
|
+
scope
|
47
|
+
end
|
39
48
|
|
40
|
-
|
49
|
+
def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
|
50
|
+
join_keys = reflection.join_keys(association_klass)
|
51
|
+
key = join_keys.key
|
52
|
+
foreign_key = join_keys.foreign_key
|
53
|
+
|
54
|
+
# CPK
|
55
|
+
# constraint = table[key].eq(foreign_table[foreign_key])
|
56
|
+
constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
|
57
|
+
|
58
|
+
if reflection.type
|
59
|
+
value = transform_value(next_reflection.klass.base_class.name)
|
60
|
+
scope = scope.where(table.name => { reflection.type => value })
|
41
61
|
end
|
62
|
+
|
63
|
+
scope = scope.joins(join(foreign_table, constraint))
|
42
64
|
end
|
43
65
|
end
|
44
66
|
end
|
@@ -8,7 +8,9 @@ module ActiveRecord
|
|
8
8
|
_read_attribute(attr_name, &block)
|
9
9
|
else
|
10
10
|
name = attr_name.to_s
|
11
|
-
|
11
|
+
# CPK
|
12
|
+
#name = self.class.primary_key if name == 'id'.freeze
|
13
|
+
name = self.class.primary_key if name == 'id'.freeze && !composite?
|
12
14
|
_read_attribute(name, &block)
|
13
15
|
end
|
14
16
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class AbstractMysqlAdapter
|
4
|
+
def subquery_for(key, select)
|
5
|
+
subsubselect = select.clone
|
6
|
+
subsubselect.projections = [key]
|
7
|
+
|
8
|
+
# Materialize subquery by adding distinct
|
9
|
+
# to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
|
10
|
+
subsubselect.distinct unless select.limit || select.offset || select.orders.any?
|
11
|
+
|
12
|
+
subselect = Arel::SelectManager.new(select.engine)
|
13
|
+
|
14
|
+
# CPK
|
15
|
+
#subselect.project Arel.sql(key.name)
|
16
|
+
subselect.project Arel.sql(Array(key).map(&:name).join(', '))
|
17
|
+
|
18
|
+
subselect.from subsubselect.as('__active_record_temp')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -47,6 +47,36 @@ module ActiveRecord
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
def update_all(updates)
|
51
|
+
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
52
|
+
|
53
|
+
stmt = Arel::UpdateManager.new
|
54
|
+
|
55
|
+
stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
|
56
|
+
stmt.table(table)
|
57
|
+
|
58
|
+
if joins_values.any?
|
59
|
+
# CPK
|
60
|
+
#@klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
|
61
|
+
if primary_key.kind_of?(Array)
|
62
|
+
attributes = primary_key.map do |key|
|
63
|
+
arel_attribute(key)
|
64
|
+
end
|
65
|
+
@klass.connection.join_to_update(stmt, arel, attributes.to_composite_keys)
|
66
|
+
else
|
67
|
+
@klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
|
68
|
+
end
|
69
|
+
else
|
70
|
+
stmt.key = arel_attribute(primary_key)
|
71
|
+
stmt.take(arel.limit)
|
72
|
+
stmt.order(*arel.orders)
|
73
|
+
stmt.wheres = arel.constraints
|
74
|
+
end
|
75
|
+
|
76
|
+
@klass.connection.update stmt, 'SQL', bound_attributes
|
77
|
+
end
|
78
|
+
|
79
|
+
|
50
80
|
def delete_all(conditions = nil)
|
51
81
|
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
|
52
82
|
if MULTI_VALUE_METHODS.include?(method)
|
@@ -1,41 +1,30 @@
|
|
1
|
-
module CompositePrimaryKeys
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module ActiveRecord
|
3
|
+
module QueryMethods
|
4
|
+
def reverse_sql_order(order_query)
|
5
|
+
# CPK
|
6
|
+
# order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty?
|
2
7
|
|
3
|
-
|
4
|
-
|
5
|
-
|
8
|
+
# break apart CPKs
|
9
|
+
order_query = primary_key.map do |key|
|
10
|
+
"#{quoted_table_name}.#{connection.quote_column_name(key)} ASC"
|
11
|
+
end if order_query.empty?
|
6
12
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
-
else
|
22
|
-
o
|
23
|
-
end
|
24
|
-
end.flatten
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
def order(*args)
|
29
|
-
args.map! do |arg|
|
30
|
-
if arg.is_a?(Arel::Nodes::Ordering) && arg.expr.name.is_a?(Array)
|
31
|
-
arg = arg.expr.name.map do |key|
|
32
|
-
cloned_node = arg.clone
|
33
|
-
cloned_node.expr.name = key
|
34
|
-
cloned_node
|
35
|
-
end
|
13
|
+
order_query.map do |o|
|
14
|
+
case o
|
15
|
+
when Arel::Nodes::Ordering
|
16
|
+
o.reverse
|
17
|
+
when String, Symbol
|
18
|
+
o.to_s.split(',').collect do |s|
|
19
|
+
s.strip!
|
20
|
+
s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
|
21
|
+
end
|
22
|
+
else
|
23
|
+
o
|
24
|
+
end
|
25
|
+
end.flatten
|
36
26
|
end
|
37
|
-
|
38
|
-
end if composite?
|
39
|
-
super(*args)
|
27
|
+
end
|
40
28
|
end
|
41
29
|
end
|
30
|
+
|