static-record 1.1.0 → 1.2.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 +4 -4
- data/README.rdoc +74 -14
- data/lib/static_record.rb +2 -0
- data/lib/static_record/concerns/getters_setters_concern.rb +43 -0
- data/lib/static_record/concerns/query_building_concern.rb +28 -4
- data/lib/static_record/concerns/request_execution_concern.rb +57 -0
- data/lib/static_record/concerns/sqlite_storing_concern.rb +10 -3
- data/lib/static_record/models/base.rb +14 -26
- data/lib/static_record/models/query_interface/search_modifiers.rb +6 -0
- data/lib/static_record/models/querying.rb +15 -4
- data/lib/static_record/models/relation.rb +11 -46
- data/lib/static_record/version.rb +1 -1
- data/spec/models/relation_spec.rb +15 -6
- data/spec/models/static_record_reference_spec.rb +10 -0
- data/spec/test_app/app/models/article.rb +6 -1
- data/spec/test_app/app/models/articles/article_one.rb +2 -0
- data/spec/test_app/app/models/categories/category_one.rb +4 -0
- data/spec/test_app/app/models/categories/category_two.rb +4 -0
- data/spec/test_app/app/models/category.rb +7 -0
- metadata +12 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 54e3e66a230098bdc375ec07c84e7a7d266872df
         | 
| 4 | 
            +
              data.tar.gz: 461d0be8afac337dc13b5cd68fa62729bf2c3842
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 835d40e2bf9e440641cf082d2ba9b9ba33ffbc9bca037e92714fffeaef83ff718c661cf26f74a5d14ca02fc2c43eb69cb35fd051a6000bc4c6bc70a7a72f961b
         | 
| 7 | 
            +
              data.tar.gz: 5c6e71af8b1698e0bd03fceb0d9705f3d88815d9a143eac21586fdaa8e37ed78be71ac61cc820956b3d382fda5aab904437b8afc55d8e2b2ba9cb50ab9d15f03
         | 
    
        data/README.rdoc
    CHANGED
    
    | @@ -26,7 +26,7 @@ The 'require' part is important so that Rails autoloads the library correctly. | |
| 26 26 | 
             
            Create your base class inheriting from StaticRecord::Base.
         | 
| 27 27 |  | 
| 28 28 | 
             
              class Article < StaticRecord::Base
         | 
| 29 | 
            -
                # Declare in which  | 
| 29 | 
            +
                # Declare in which table Articles will be store (always in file db/static_records.sqlite3)
         | 
| 30 30 | 
             
                table       :articles
         | 
| 31 31 |  | 
| 32 32 | 
             
                # Declare at which path "article" files can be found
         | 
| @@ -37,23 +37,24 @@ Create your base class inheriting from StaticRecord::Base. | |
| 37 37 | 
             
                primary_key :name
         | 
| 38 38 |  | 
| 39 39 | 
             
                # You can specify default values for each column of your static records
         | 
| 40 | 
            -
                # Just create a method with name: default_<attribute_name>
         | 
| 41 | 
            -
                def default_author
         | 
| 40 | 
            +
                # Just create a class method with name: default_<attribute_name>
         | 
| 41 | 
            +
                def self.default_author
         | 
| 42 42 | 
             
                  'Default author'
         | 
| 43 43 | 
             
                end
         | 
| 44 44 |  | 
| 45 45 | 
             
                # You can override any attribute value
         | 
| 46 | 
            -
                # Just create a method with name: override_<attribute_name>
         | 
| 47 | 
            -
                def override_cover(cover)
         | 
| 46 | 
            +
                # Just create a class method with name: override_<attribute_name>
         | 
| 47 | 
            +
                def self.override_cover(cover)
         | 
| 48 48 | 
             
                  return cover if cover.to_s.include?('/')
         | 
| 49 49 | 
             
                  Rails.root.join('public', 'default_cover_path', cover)
         | 
| 50 50 | 
             
                end
         | 
| 51 51 |  | 
| 52 52 | 
             
                # Specify which "article" attributes can be queried over with their types
         | 
| 53 | 
            -
                columns     name: | 
| 54 | 
            -
                            author: | 
| 55 | 
            -
                            rank: | 
| 56 | 
            -
                            cover: | 
| 53 | 
            +
                columns     name:     :string,
         | 
| 54 | 
            +
                            author:   :string,
         | 
| 55 | 
            +
                            rank:     :integer,
         | 
| 56 | 
            +
                            cover:    :string,
         | 
| 57 | 
            +
                            category  :static_record
         | 
| 57 58 | 
             
              end
         | 
| 58 59 |  | 
| 59 60 | 
             
            At each application startup, an SQLite3 database will be created to store this class' children.
         | 
| @@ -63,6 +64,7 @@ Available column types are | |
| 63 64 | 
             
            - :integer
         | 
| 64 65 | 
             
            - :boolean
         | 
| 65 66 | 
             
            - :float
         | 
| 67 | 
            +
            - :static_record
         | 
| 66 68 |  | 
| 67 69 | 
             
            === Child class
         | 
| 68 70 |  | 
| @@ -75,6 +77,10 @@ Create has many child class as you want. | |
| 75 77 | 
             
                attribute :rank, 2
         | 
| 76 78 | 
             
                attribute :cover, Rails.root.join('public', 'articles', 'one.jpg')
         | 
| 77 79 |  | 
| 80 | 
            +
                # Define the references to other StaticRecords
         | 
| 81 | 
            +
                # These ones can be queried over after a jointure
         | 
| 82 | 
            +
                reference :category, Category.find('Category One')
         | 
| 83 | 
            +
             | 
| 78 84 | 
             
                # Your class can be used as any other Ruby class
         | 
| 79 85 | 
             
                def initialize
         | 
| 80 86 | 
             
                  @an_instance_variable
         | 
| @@ -94,25 +100,51 @@ In your code, you can perform queries like this one: | |
| 94 100 |  | 
| 95 101 | 
             
            Article.where(name: 'Article Two').or.where('rank >= 2').limit(2).offset(3)
         | 
| 96 102 |  | 
| 97 | 
            -
            I tried to implement as  | 
| 103 | 
            +
            I tried to implement as much of ActiveRecord's query interface as I could.
         | 
| 98 104 |  | 
| 99 | 
            -
            There is still a lot of work before everything is available, but I chose to release the  | 
| 105 | 
            +
            There is still a lot of work before everything is available, but I chose to release the gem nevertheless.
         | 
| 100 106 |  | 
| 101 107 | 
             
            Here is a full list:
         | 
| 102 108 | 
             
            * where
         | 
| 103 | 
            -
              *  | 
| 104 | 
            -
              *  | 
| 109 | 
            +
              * Article.where(name: 'Article One', author: 'The author')
         | 
| 110 | 
            +
              * Article.where(name: ['Article One', 'Article Two'])
         | 
| 111 | 
            +
              * Article.where(name: 'Article One').where(author: 'The author')
         | 
| 112 | 
            +
              * Article.where("name = 'Article One'")
         | 
| 113 | 
            +
              * Article.where("name = ?", 'Article One')
         | 
| 114 | 
            +
              * Article.where("name = :name", name: 'Article One')
         | 
| 105 115 | 
             
            * find (only if a primary key has been set)
         | 
| 116 | 
            +
              * Article.find('Article One')
         | 
| 106 117 | 
             
            * find_by
         | 
| 118 | 
            +
              * Article.find_by(author: 'The author')
         | 
| 119 | 
            +
            * joins
         | 
| 120 | 
            +
              * Article.joins(:categories).where("categories.name = 'Category One'")
         | 
| 107 121 | 
             
            * not
         | 
| 122 | 
            +
              * Article.where.not(author: 'The author')
         | 
| 108 123 | 
             
            * or
         | 
| 124 | 
            +
              * Article.where(author: 'The author').or.where(author: 'Another author')
         | 
| 125 | 
            +
              * Article.where.not(name: 'Article One').or.where.not(author: 'The author')
         | 
| 109 126 | 
             
            * all
         | 
| 127 | 
            +
              * Article.where(author: 'The author').all
         | 
| 128 | 
            +
              * Article.all
         | 
| 110 129 | 
             
            * take
         | 
| 130 | 
            +
              * Article.take
         | 
| 131 | 
            +
              * Article.take(3)
         | 
| 111 132 | 
             
            * first
         | 
| 133 | 
            +
              * Article.first
         | 
| 134 | 
            +
              * Article.first(3)
         | 
| 112 135 | 
             
            * last
         | 
| 136 | 
            +
              * Article.last
         | 
| 137 | 
            +
              * Article.last(3)
         | 
| 113 138 | 
             
            * limit
         | 
| 139 | 
            +
              * Article.limit(5)
         | 
| 114 140 | 
             
            * offset
         | 
| 141 | 
            +
              * Article.limit(3).offset(2)
         | 
| 115 142 | 
             
            * order
         | 
| 143 | 
            +
              * Article.order(:rank) # Use ASC ordering
         | 
| 144 | 
            +
              * Article.order([:rank, :name]) # Use ASC ordering for both columns
         | 
| 145 | 
            +
              * Article.order(rank: :asc)
         | 
| 146 | 
            +
              * Article.order(rank: :desc, name: :asc)
         | 
| 147 | 
            +
              * Article.order("rank DESC")
         | 
| 116 148 |  | 
| 117 149 | 
             
            == IDs
         | 
| 118 150 |  | 
| @@ -122,6 +154,8 @@ As the database is recreated at each application startup and IDs depend on the i | |
| 122 154 |  | 
| 123 155 | 
             
            == References
         | 
| 124 156 |  | 
| 157 | 
            +
            === ActiveRecord
         | 
| 158 | 
            +
             | 
| 125 159 | 
             
            A migration helper allows your ActiveRecord models to reference a StaticRecord.
         | 
| 126 160 |  | 
| 127 161 | 
             
            In a migration, use:
         | 
| @@ -153,6 +187,32 @@ If you don't want to name your column with the same name than your StaticRecord | |
| 153 187 | 
             
              # In the model
         | 
| 154 188 | 
             
              has_static_record :any_column_name, class_name: 'Article'
         | 
| 155 189 |  | 
| 190 | 
            +
            === StaticRecord
         | 
| 191 | 
            +
             | 
| 192 | 
            +
            You can also use 'reference' instead of 'attribute' to have your StaticRecords reference other ones.
         | 
| 193 | 
            +
             | 
| 194 | 
            +
            You must use type :static_record when declaring your column!
         | 
| 195 | 
            +
             | 
| 196 | 
            +
              class Article < StaticRecord::Base
         | 
| 197 | 
            +
                table       :articles
         | 
| 198 | 
            +
                path        Rails.root.join('app', 'models', 'articles', '**', '*.rb')
         | 
| 199 | 
            +
                primary_key :name
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                columns     name:     :string,
         | 
| 202 | 
            +
                            category  :static_record
         | 
| 203 | 
            +
              end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
              class ArticleOne < Article
         | 
| 206 | 
            +
                attribute   :name, 'Article one'
         | 
| 207 | 
            +
                reference   :category, Category.find('Category One')
         | 
| 208 | 
            +
              end
         | 
| 209 | 
            +
             | 
| 210 | 
            +
            You can query them like this
         | 
| 211 | 
            +
             | 
| 212 | 
            +
              Article.where(category: Category.find('Category One'))
         | 
| 213 | 
            +
              Article.joins(Category).where("categories.name = 'Category One'")
         | 
| 214 | 
            +
              Article.joins("categories").where("categories.name = 'Category One'")
         | 
| 215 | 
            +
             | 
| 156 216 | 
             
            == Questions?
         | 
| 157 217 |  | 
| 158 218 | 
             
            If you have any question or doubt regarding StaticRecord which you cannot find the solution to in the documentation, you can send me an email. I'll try to answer in less than 24 hours.
         | 
| @@ -165,4 +225,4 @@ If you find a bug please add an issue on GitHub or fork the project and send a p | |
| 165 225 |  | 
| 166 226 | 
             
            - Better documentation
         | 
| 167 227 | 
             
            - Generators
         | 
| 168 | 
            -
            -  | 
| 228 | 
            +
            - Improve jointures
         | 
    
        data/lib/static_record.rb
    CHANGED
    
    | @@ -1,8 +1,10 @@ | |
| 1 1 | 
             
            require 'static_record/engine'
         | 
| 2 2 | 
             
            require 'static_record/exceptions'
         | 
| 3 3 |  | 
| 4 | 
            +
            require 'static_record/concerns/getters_setters_concern'
         | 
| 4 5 | 
             
            require 'static_record/concerns/query_building_concern'
         | 
| 5 6 | 
             
            require 'static_record/concerns/sqlite_storing_concern'
         | 
| 7 | 
            +
            require 'static_record/concerns/request_execution_concern'
         | 
| 6 8 |  | 
| 7 9 | 
             
            require 'static_record/models/query_interface/conditioners'
         | 
| 8 10 | 
             
            require 'static_record/models/query_interface/retrievers'
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            module StaticRecord
         | 
| 2 | 
            +
              # Contains StaticRecord::Base getters and setters
         | 
| 3 | 
            +
              module GettersSettersConcern
         | 
| 4 | 
            +
                extend ActiveSupport::Concern
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                module ClassMethods # :nodoc:
         | 
| 7 | 
            +
                  def primary_key(name)
         | 
| 8 | 
            +
                    err = StaticRecord::Base::RESERVED_ATTRIBUTES.include?("@@#{name}".to_sym)
         | 
| 9 | 
            +
                    raise StaticRecord::ReservedAttributeName, "#{name} is a reserved name" if err
         | 
| 10 | 
            +
                    class_variable_set('@@_primary_key', name)
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def pkey
         | 
| 14 | 
            +
                    class_variable_defined?(:@@_primary_key) ? class_variable_get('@@_primary_key') : nil
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def bound_static_tables
         | 
| 18 | 
            +
                    return {} unless class_variable_defined?(:@@_bound_static_tables)
         | 
| 19 | 
            +
                    class_variable_get('@@_bound_static_tables')
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def bound_static_tables=(value)
         | 
| 23 | 
            +
                    class_variable_set('@@_bound_static_tables', value)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def table(store)
         | 
| 27 | 
            +
                    class_variable_set('@@_store', store.to_s)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def store
         | 
| 31 | 
            +
                    class_variable_get('@@_store')
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def path(path)
         | 
| 35 | 
            +
                    class_variable_set('@@_path_pattern', path)
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def path_pattern
         | 
| 39 | 
            +
                    class_variable_get('@@_path_pattern')
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| @@ -5,6 +5,7 @@ module StaticRecord | |
| 5 5 |  | 
| 6 6 | 
             
                def build_query
         | 
| 7 7 | 
             
                  sql = sql_select_from
         | 
| 8 | 
            +
                  sql += sql_joins unless @joins_clauses.empty?
         | 
| 8 9 | 
             
                  sql += sql_where unless @where_clauses.empty?
         | 
| 9 10 | 
             
                  sql += sql_order unless @order_by.empty?
         | 
| 10 11 | 
             
                  sql += sql_limit_offset if @sql_limit
         | 
| @@ -17,6 +18,13 @@ module StaticRecord | |
| 17 18 | 
             
                  "SELECT #{@columns} FROM #{@table}"
         | 
| 18 19 | 
             
                end
         | 
| 19 20 |  | 
| 21 | 
            +
                def sql_joins
         | 
| 22 | 
            +
                  @joins_clauses.map do |joint|
         | 
| 23 | 
            +
                    " INNER JOIN #{joint} ON "\
         | 
| 24 | 
            +
                    "#{@store}.#{get_column_for_static_table(joint)} = #{joint}.klass"
         | 
| 25 | 
            +
                  end.join
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 20 28 | 
             
                def sql_where
         | 
| 21 29 | 
             
                  " WHERE #{where_clause_builder}"
         | 
| 22 30 | 
             
                end
         | 
| @@ -70,14 +78,14 @@ module StaticRecord | |
| 70 78 | 
             
                    if value.is_a?(Array)
         | 
| 71 79 | 
             
                      # ex: where(name: ['John', 'Jack'])
         | 
| 72 80 | 
             
                      # use IN operator
         | 
| 73 | 
            -
                      value.map! { |v| v  | 
| 81 | 
            +
                      value.map! { |v| cast(v) }
         | 
| 74 82 | 
             
                      inverse = 'NOT ' if clause[:operator] == :not_eq
         | 
| 75 83 | 
             
                      "#{key} #{inverse}IN (#{value.join(',')})"
         | 
| 76 84 | 
             
                    else
         | 
| 77 85 | 
             
                      # ex: where(name: 'John')
         | 
| 78 86 | 
             
                      # use = operator
         | 
| 79 87 | 
             
                      inverse = '!' if clause[:operator] == :not_eq
         | 
| 80 | 
            -
                      "#{key} #{inverse}=  | 
| 88 | 
            +
                      "#{key} #{inverse}= #{cast(value)}"
         | 
| 81 89 | 
             
                    end
         | 
| 82 90 | 
             
                  end
         | 
| 83 91 | 
             
                  parts.join(' AND ')
         | 
| @@ -89,16 +97,32 @@ module StaticRecord | |
| 89 97 | 
             
                    # Anon parameters
         | 
| 90 98 | 
             
                    # ex: where("name = ? OR name = ?", 'John', 'Jack')
         | 
| 91 99 | 
             
                    clause[:parameters].each do |param|
         | 
| 92 | 
            -
                      final_string.sub!(/\?/,  | 
| 100 | 
            +
                      final_string.sub!(/\?/, cast(param))
         | 
| 93 101 | 
             
                    end
         | 
| 94 102 | 
             
                  elsif clause[:parameters].is_a?(Hash)
         | 
| 95 103 | 
             
                    # Named parameters (placeholder condition)
         | 
| 96 104 | 
             
                    # ex: where("name = :one OR name = :two", one: 'John', two: 'Smith')
         | 
| 97 105 | 
             
                    clause[:parameters].each do |key, value|
         | 
| 98 | 
            -
                      final_string.sub!(":#{key}",  | 
| 106 | 
            +
                      final_string.sub!(":#{key}", cast(value))
         | 
| 99 107 | 
             
                    end
         | 
| 100 108 | 
             
                  end
         | 
| 101 109 | 
             
                  final_string
         | 
| 102 110 | 
             
                end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                def cast(value)
         | 
| 113 | 
            +
                  return escape(value.class.name) if value.class < StaticRecord::Base
         | 
| 114 | 
            +
                  return value.to_s if value =~ /^[+|-]?\d+\.?\d*$/
         | 
| 115 | 
            +
                  escape(value)
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                def escape(value)
         | 
| 119 | 
            +
                  return "'#{value}'" unless value.include?('\'')
         | 
| 120 | 
            +
                  "\"#{value}\""
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                def get_column_for_static_table(table)
         | 
| 124 | 
            +
                  klass = @klass.constantize
         | 
| 125 | 
            +
                  klass.bound_static_tables[table.to_sym]
         | 
| 126 | 
            +
                end
         | 
| 103 127 | 
             
              end
         | 
| 104 128 | 
             
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            module StaticRecord
         | 
| 2 | 
            +
              module RequestExecutionConcern # :nodoc:
         | 
| 3 | 
            +
                extend ActiveSupport::Concern
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                private
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def exec_request(expectancy = :result_set)
         | 
| 8 | 
            +
                  return build_query if @only_sql
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  dbname = Rails.root.join('db', 'static_records.sqlite3').to_s
         | 
| 11 | 
            +
                  result = get_expected_result_from_database(dbname, expectancy)
         | 
| 12 | 
            +
                  cast_result(expectancy, result)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def get_expected_result_from_database(dbname, expectancy)
         | 
| 16 | 
            +
                  result = nil
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  begin
         | 
| 19 | 
            +
                    db = SQLite3::Database.open(dbname)
         | 
| 20 | 
            +
                    query = build_query
         | 
| 21 | 
            +
                    if expectancy == :integer
         | 
| 22 | 
            +
                      result = db.get_first_value(query)
         | 
| 23 | 
            +
                    else
         | 
| 24 | 
            +
                      statement = db.prepare(query)
         | 
| 25 | 
            +
                      result_set = statement.execute
         | 
| 26 | 
            +
                      result = result_set.map { |row| row[1].constantize.new }
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  rescue SQLite3::Exception => e
         | 
| 29 | 
            +
                    error, msg = handle_error(e, query)
         | 
| 30 | 
            +
                  ensure
         | 
| 31 | 
            +
                    statement.close if statement
         | 
| 32 | 
            +
                    db.close if db
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                  raise error, msg if error
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  result
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def handle_error(error, query)
         | 
| 40 | 
            +
                  msg = query ? "#{error} in #{query}" : error
         | 
| 41 | 
            +
                  [error, msg]
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def cast_result(expectancy, result)
         | 
| 45 | 
            +
                  if expectancy == :result_set
         | 
| 46 | 
            +
                    case @result_type
         | 
| 47 | 
            +
                    when :array
         | 
| 48 | 
            +
                      result = [] if result.nil?
         | 
| 49 | 
            +
                    when :record
         | 
| 50 | 
            +
                      result = result.empty? ? nil : result.first
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  result
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -8,7 +8,7 @@ module StaticRecord | |
| 8 8 | 
             
                  def create_store
         | 
| 9 9 | 
             
                    cols = class_variable_get(:@@_columns)
         | 
| 10 10 | 
             
                    begin
         | 
| 11 | 
            -
                      dbname = Rails.root.join('db',  | 
| 11 | 
            +
                      dbname = Rails.root.join('db', 'static_records.sqlite3').to_s
         | 
| 12 12 | 
             
                      SQLite3::Database.new(dbname)
         | 
| 13 13 | 
             
                      db = SQLite3::Database.open(dbname)
         | 
| 14 14 | 
             
                      db.execute("DROP TABLE IF EXISTS #{store}")
         | 
| @@ -37,7 +37,7 @@ module StaticRecord | |
| 37 37 |  | 
| 38 38 | 
             
                  def column_type_to_sql(ctype)
         | 
| 39 39 | 
             
                    case ctype.to_s
         | 
| 40 | 
            -
                    when 'string'
         | 
| 40 | 
            +
                    when 'string', 'static_record'
         | 
| 41 41 | 
             
                      ' TEXT'
         | 
| 42 42 | 
             
                    else
         | 
| 43 43 | 
             
                      " #{ctype.to_s.upcase}"
         | 
| @@ -54,7 +54,14 @@ module StaticRecord | |
| 54 54 | 
             
                    sqlized = [index.to_s, "'#{record}'"]
         | 
| 55 55 | 
             
                    # model's attributes
         | 
| 56 56 | 
             
                    sqlized += cols.map do |name, ctype|
         | 
| 57 | 
            -
                      ctype | 
| 57 | 
            +
                      case ctype
         | 
| 58 | 
            +
                      when :integer
         | 
| 59 | 
            +
                        attrs[name].to_s
         | 
| 60 | 
            +
                      when :static_record
         | 
| 61 | 
            +
                        "'#{attrs[name].class.name}'"
         | 
| 62 | 
            +
                      else
         | 
| 63 | 
            +
                        "'#{attrs[name]}'"
         | 
| 64 | 
            +
                      end
         | 
| 58 65 | 
             
                    end
         | 
| 59 66 |  | 
| 60 67 | 
             
                    db.execute("INSERT INTO #{store} VALUES(#{sqlized.join(', ')})")
         | 
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            module StaticRecord
         | 
| 2 2 | 
             
              # Class that immutable model instances can inherit from
         | 
| 3 3 | 
             
              class Base
         | 
| 4 | 
            +
                include StaticRecord::GettersSettersConcern
         | 
| 4 5 | 
             
                include StaticRecord::Querying
         | 
| 5 6 | 
             
                include StaticRecord::SqliteStoringConcern
         | 
| 6 7 |  | 
| @@ -8,14 +9,16 @@ module StaticRecord | |
| 8 9 | 
             
                  :@@_columns,
         | 
| 9 10 | 
             
                  :@@_primary_key,
         | 
| 10 11 | 
             
                  :@@_path_pattern,
         | 
| 11 | 
            -
                  :@@_store
         | 
| 12 | 
            +
                  :@@_store,
         | 
| 13 | 
            +
                  :@@_bound_static_tables
         | 
| 12 14 | 
             
                ].freeze
         | 
| 13 15 |  | 
| 14 16 | 
             
                KNOWN_TYPES = [
         | 
| 15 17 | 
             
                  :string,
         | 
| 16 18 | 
             
                  :boolean,
         | 
| 17 19 | 
             
                  :integer,
         | 
| 18 | 
            -
                  :float
         | 
| 20 | 
            +
                  :float,
         | 
| 21 | 
            +
                  :static_record
         | 
| 19 22 | 
             
                ].freeze
         | 
| 20 23 |  | 
| 21 24 | 
             
                def initialize
         | 
| @@ -34,30 +37,15 @@ module StaticRecord | |
| 34 37 | 
             
                  class_variable_set("@@#{name}", value)
         | 
| 35 38 | 
             
                end
         | 
| 36 39 |  | 
| 37 | 
            -
                def self. | 
| 38 | 
            -
                   | 
| 39 | 
            -
                   | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
                   | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
                def self.table(store)
         | 
| 48 | 
            -
                  class_variable_set('@@_store', store.to_s)
         | 
| 49 | 
            -
                end
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                def self.store
         | 
| 52 | 
            -
                  class_variable_get('@@_store')
         | 
| 53 | 
            -
                end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                def self.path(path)
         | 
| 56 | 
            -
                  class_variable_set('@@_path_pattern', path)
         | 
| 57 | 
            -
                end
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                def self.path_pattern
         | 
| 60 | 
            -
                  class_variable_get('@@_path_pattern')
         | 
| 40 | 
            +
                def self.reference(name, value)
         | 
| 41 | 
            +
                  attribute(name, value)
         | 
| 42 | 
            +
                  unless value.class < StaticRecord::Base
         | 
| 43 | 
            +
                    err = 'Reference only accepts StaticRecords'
         | 
| 44 | 
            +
                    raise StaticRecord::ClassError, err
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                  tables = superclass.bound_static_tables
         | 
| 47 | 
            +
                  tables[value.class.store.to_sym] = name
         | 
| 48 | 
            +
                  superclass.bound_static_tables = tables
         | 
| 61 49 | 
             
                end
         | 
| 62 50 |  | 
| 63 51 | 
             
                def attributes
         | 
| @@ -6,15 +6,16 @@ module StaticRecord | |
| 6 6 |  | 
| 7 7 | 
             
                module ClassMethods # :nodoc:
         | 
| 8 8 | 
             
                  def method_missing(method_sym, *arguments, &block)
         | 
| 9 | 
            -
                     | 
| 10 | 
            -
             | 
| 9 | 
            +
                    params = relation_params
         | 
| 10 | 
            +
                    if Relation.new(nil, params).respond_to?(method_sym, true)
         | 
| 11 | 
            +
                      Relation.new(nil, params).send(method_sym, *arguments, &block)
         | 
| 11 12 | 
             
                    else
         | 
| 12 13 | 
             
                      super
         | 
| 13 14 | 
             
                    end
         | 
| 14 15 | 
             
                  end
         | 
| 15 16 |  | 
| 16 17 | 
             
                  def respond_to?(method_sym, include_private = false)
         | 
| 17 | 
            -
                    if Relation.new(nil,  | 
| 18 | 
            +
                    if Relation.new(nil, relation_params).respond_to?(method_sym, true)
         | 
| 18 19 | 
             
                      true
         | 
| 19 20 | 
             
                    else
         | 
| 20 21 | 
             
                      super
         | 
| @@ -22,12 +23,22 @@ module StaticRecord | |
| 22 23 | 
             
                  end
         | 
| 23 24 |  | 
| 24 25 | 
             
                  def respond_to_missing?(method_sym, include_private = false)
         | 
| 25 | 
            -
                    if Relation.new(nil,  | 
| 26 | 
            +
                    if Relation.new(nil, relation_params).respond_to_missing?(method_sym, true)
         | 
| 26 27 | 
             
                      true
         | 
| 27 28 | 
             
                    else
         | 
| 28 29 | 
             
                      super
         | 
| 29 30 | 
             
                    end
         | 
| 30 31 | 
             
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  private
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def relation_params
         | 
| 36 | 
            +
                    {
         | 
| 37 | 
            +
                      klass: name,
         | 
| 38 | 
            +
                      store: store,
         | 
| 39 | 
            +
                      primary_key: pkey
         | 
| 40 | 
            +
                    }
         | 
| 41 | 
            +
                  end
         | 
| 31 42 | 
             
                end
         | 
| 32 43 | 
             
              end
         | 
| 33 44 | 
             
            end
         | 
| @@ -4,6 +4,7 @@ module StaticRecord | |
| 4 4 | 
             
                            :sql_limit,
         | 
| 5 5 | 
             
                            :sql_offset,
         | 
| 6 6 | 
             
                            :where_clauses,
         | 
| 7 | 
            +
                            :joins_clauses,
         | 
| 7 8 | 
             
                            :chain,
         | 
| 8 9 | 
             
                            :result_type,
         | 
| 9 10 | 
             
                            :order_by,
         | 
| @@ -11,16 +12,19 @@ module StaticRecord | |
| 11 12 |  | 
| 12 13 | 
             
                include StaticRecord::QueryInterface::Interface
         | 
| 13 14 | 
             
                include StaticRecord::QueryBuildingConcern
         | 
| 15 | 
            +
                include StaticRecord::RequestExecutionConcern
         | 
| 14 16 |  | 
| 15 17 | 
             
                def initialize(previous_node, params)
         | 
| 16 18 | 
             
                  @store = params[:store]
         | 
| 17 19 | 
             
                  @table = params[:store]
         | 
| 20 | 
            +
                  @klass = params[:klass]
         | 
| 18 21 | 
             
                  @primary_key = params[:primary_key]
         | 
| 19 22 |  | 
| 20 23 | 
             
                  @columns = '*'
         | 
| 21 24 | 
             
                  @sql_limit = nil
         | 
| 22 25 | 
             
                  @sql_offset = nil
         | 
| 23 26 | 
             
                  @where_clauses = []
         | 
| 27 | 
            +
                  @joins_clauses = []
         | 
| 24 28 | 
             
                  @chain = :and
         | 
| 25 29 | 
             
                  @result_type = :array
         | 
| 26 30 | 
             
                  @order_by = []
         | 
| @@ -31,7 +35,12 @@ module StaticRecord | |
| 31 35 |  | 
| 32 36 | 
             
                def method_missing(method_sym, *arguments, &block)
         | 
| 33 37 | 
             
                  if respond_to?(method_sym, true)
         | 
| 34 | 
            -
                     | 
| 38 | 
            +
                    params = {
         | 
| 39 | 
            +
                      klass: @klass,
         | 
| 40 | 
            +
                      store: @store,
         | 
| 41 | 
            +
                      primary_key: @primary_key
         | 
| 42 | 
            +
                    }
         | 
| 43 | 
            +
                    Relation.new(self, params).send(method_sym, *arguments, &block)
         | 
| 35 44 | 
             
                  elsif [].respond_to?(method_sym)
         | 
| 36 45 | 
             
                    to_a.send(method_sym)
         | 
| 37 46 | 
             
                  else
         | 
| @@ -58,6 +67,7 @@ module StaticRecord | |
| 58 67 | 
             
                  @sql_limit = relation.sql_limit
         | 
| 59 68 | 
             
                  @sql_offset = relation.sql_offset
         | 
| 60 69 | 
             
                  @where_clauses = relation.where_clauses.deep_dup
         | 
| 70 | 
            +
                  @joins_clauses = relation.joins_clauses.deep_dup
         | 
| 61 71 | 
             
                  @chain = relation.chain
         | 
| 62 72 | 
             
                  @result_type = relation.result_type
         | 
| 63 73 | 
             
                  @order_by = relation.order_by.deep_dup
         | 
| @@ -74,50 +84,5 @@ module StaticRecord | |
| 74 84 | 
             
                  @where_clauses << clause
         | 
| 75 85 | 
             
                  @chain = :and
         | 
| 76 86 | 
             
                end
         | 
| 77 | 
            -
             | 
| 78 | 
            -
                def exec_request(expectancy = :result_set)
         | 
| 79 | 
            -
                  return build_query if @only_sql
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                  dbname = Rails.root.join('db', "static_#{@store}.sqlite3").to_s
         | 
| 82 | 
            -
                  result = get_expected_result_from_database(dbname, expectancy)
         | 
| 83 | 
            -
                  cast_result(expectancy, result)
         | 
| 84 | 
            -
                end
         | 
| 85 | 
            -
             | 
| 86 | 
            -
                def get_expected_result_from_database(dbname, expectancy)
         | 
| 87 | 
            -
                  result = nil
         | 
| 88 | 
            -
             | 
| 89 | 
            -
                  begin
         | 
| 90 | 
            -
                    db = SQLite3::Database.open(dbname)
         | 
| 91 | 
            -
                    if expectancy == :integer
         | 
| 92 | 
            -
                      result = db.get_first_value(build_query)
         | 
| 93 | 
            -
                    else
         | 
| 94 | 
            -
                      statement = db.prepare(build_query)
         | 
| 95 | 
            -
                      result_set = statement.execute
         | 
| 96 | 
            -
                      result = result_set.map { |row| row[1].constantize.new }
         | 
| 97 | 
            -
                    end
         | 
| 98 | 
            -
                  rescue SQLite3::Exception => e
         | 
| 99 | 
            -
                    error = e
         | 
| 100 | 
            -
                  ensure
         | 
| 101 | 
            -
                    statement.close if statement
         | 
| 102 | 
            -
                    db.close if db
         | 
| 103 | 
            -
                  end
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                  raise error if error
         | 
| 106 | 
            -
             | 
| 107 | 
            -
                  result
         | 
| 108 | 
            -
                end
         | 
| 109 | 
            -
             | 
| 110 | 
            -
                def cast_result(expectancy, result)
         | 
| 111 | 
            -
                  if expectancy == :result_set
         | 
| 112 | 
            -
                    case @result_type
         | 
| 113 | 
            -
                    when :array
         | 
| 114 | 
            -
                      result = [] if result.nil?
         | 
| 115 | 
            -
                    when :record
         | 
| 116 | 
            -
                      result = result.empty? ? nil : result.first
         | 
| 117 | 
            -
                    end
         | 
| 118 | 
            -
                  end
         | 
| 119 | 
            -
             | 
| 120 | 
            -
                  result
         | 
| 121 | 
            -
                end
         | 
| 122 87 | 
             
              end
         | 
| 123 88 | 
             
            end
         | 
| @@ -141,7 +141,7 @@ RSpec.describe StaticRecord::Relation, :type => :model do | |
| 141 141 |  | 
| 142 142 | 
             
                it 'accepts array of values' do
         | 
| 143 143 | 
             
                  expect(Article.where(name: ['Article One', 'Article Two']).to_a.size).to eql(2)
         | 
| 144 | 
            -
                  expect(Article.where(name: ['Article One', 'Article Two']).to_sql).to eql("SELECT * FROM articles WHERE name IN ( | 
| 144 | 
            +
                  expect(Article.where(name: ['Article One', 'Article Two']).to_sql).to eql("SELECT * FROM articles WHERE name IN ('Article One','Article Two')")
         | 
| 145 145 | 
             
                end
         | 
| 146 146 |  | 
| 147 147 | 
             
                it 'accepts strings' do
         | 
| @@ -151,17 +151,17 @@ RSpec.describe StaticRecord::Relation, :type => :model do | |
| 151 151 |  | 
| 152 152 | 
             
                it 'accepts strings followed by an anonymous parameters' do
         | 
| 153 153 | 
             
                  expect(Article.where("name = ?", 'Article Two').first.class).to eql(ArticleTwo)
         | 
| 154 | 
            -
                  expect(Article.where("name = ?", 'Article Two').to_sql).to eql("SELECT * FROM articles WHERE name =  | 
| 154 | 
            +
                  expect(Article.where("name = ?", 'Article Two').to_sql).to eql("SELECT * FROM articles WHERE name = 'Article Two'")
         | 
| 155 155 | 
             
                end
         | 
| 156 156 |  | 
| 157 157 | 
             
                it 'accepts strings followed by several anonymous parameters' do
         | 
| 158 158 | 
             
                  expect(Article.where("name = ? AND author = ?", 'Article Two', 'The author').first.class).to eql(ArticleTwo)
         | 
| 159 | 
            -
                  expect(Article.where("name = ? AND author = ?", 'Article Two', 'The author').to_sql).to eql("SELECT * FROM articles WHERE name =  | 
| 159 | 
            +
                  expect(Article.where("name = ? AND author = ?", 'Article Two', 'The author').to_sql).to eql("SELECT * FROM articles WHERE name = 'Article Two' AND author = 'The author'")
         | 
| 160 160 | 
             
                end
         | 
| 161 161 |  | 
| 162 162 | 
             
                it 'accepts strings followed by a hash of named parameters' do
         | 
| 163 163 | 
             
                  expect(Article.where("name = :name AND author = :author", {name: 'Article Two', author: 'The author'}).first.class).to eql(ArticleTwo)
         | 
| 164 | 
            -
                  expect(Article.where("name = :name AND author = :author", {name: 'Article Two', author: 'The author'}).to_sql).to eql("SELECT * FROM articles WHERE name =  | 
| 164 | 
            +
                  expect(Article.where("name = :name AND author = :author", {name: 'Article Two', author: 'The author'}).to_sql).to eql("SELECT * FROM articles WHERE name = 'Article Two' AND author = 'The author'")
         | 
| 165 165 | 
             
                end
         | 
| 166 166 | 
             
              end
         | 
| 167 167 |  | 
| @@ -178,7 +178,7 @@ RSpec.describe StaticRecord::Relation, :type => :model do | |
| 178 178 | 
             
                it 'is possible to chain where.not and where.not clauses' do
         | 
| 179 179 | 
             
                  request = Article.where.not(author: ['The author', 'Me']).where.not(name: 'Article Two')
         | 
| 180 180 | 
             
                  expect(request.last.class.name).to eql(ArticleThree.name)
         | 
| 181 | 
            -
                  expect(request.to_sql).to eql("SELECT * FROM articles WHERE author NOT IN ( | 
| 181 | 
            +
                  expect(request.to_sql).to eql("SELECT * FROM articles WHERE author NOT IN ('The author','Me') AND name != 'Article Two'")
         | 
| 182 182 | 
             
                end
         | 
| 183 183 | 
             
              end
         | 
| 184 184 |  | 
| @@ -207,7 +207,7 @@ RSpec.describe StaticRecord::Relation, :type => :model do | |
| 207 207 |  | 
| 208 208 | 
             
                it 'accepts array of values' do
         | 
| 209 209 | 
             
                  expect(Article.find(['Article One', 'Article Two']).to_a.size).to eql(2)
         | 
| 210 | 
            -
                  expect(Article.see_sql_of.find(['Article One', 'Article Two'])).to eql("SELECT * FROM articles WHERE name IN ( | 
| 210 | 
            +
                  expect(Article.see_sql_of.find(['Article One', 'Article Two'])).to eql("SELECT * FROM articles WHERE name IN ('Article One','Article Two')")
         | 
| 211 211 | 
             
                end
         | 
| 212 212 |  | 
| 213 213 | 
             
                context 'one value' do
         | 
| @@ -249,4 +249,13 @@ RSpec.describe StaticRecord::Relation, :type => :model do | |
| 249 249 | 
             
                  expect(Article.where(author: 'Inexisting author').or.where(author: 'The author').to_sql).to eql("SELECT * FROM articles WHERE author = 'Inexisting author' OR author = 'The author'")
         | 
| 250 250 | 
             
                end
         | 
| 251 251 | 
             
              end
         | 
| 252 | 
            +
             | 
| 253 | 
            +
              context '.joins' do
         | 
| 254 | 
            +
                it 'allows to use the SQL JOIN clause' do
         | 
| 255 | 
            +
                  expect(Article.joins(:categories).where("categories.name = 'Category One'").first.class).to eql(ArticleOne)
         | 
| 256 | 
            +
                  expected_sql = "SELECT * FROM articles INNER JOIN categories ON articles.category = categories.klass"
         | 
| 257 | 
            +
                  expect(Article.joins(:categories).to_sql).to eql(expected_sql)
         | 
| 258 | 
            +
                  expect(Article.joins(Category).to_sql).to eql(expected_sql)
         | 
| 259 | 
            +
                end
         | 
| 260 | 
            +
              end
         | 
| 252 261 | 
             
            end
         | 
| @@ -0,0 +1,10 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'rails_helper'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            RSpec.describe StaticRecord::Base, :type => :module do
         | 
| 5 | 
            +
              it 'can query over a static record reference' do
         | 
| 6 | 
            +
                category = Category.find('Category One')
         | 
| 7 | 
            +
                article = Article.where(category: category)
         | 
| 8 | 
            +
                expect(article.first.category.class).to eql(category.class)
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
            end
         | 
| @@ -11,6 +11,10 @@ class Article < StaticRecord::Base | |
| 11 11 | 
             
                3
         | 
| 12 12 | 
             
              end
         | 
| 13 13 |  | 
| 14 | 
            +
              def self.default_category
         | 
| 15 | 
            +
                Category.find('Category Two')
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 14 18 | 
             
              def self.override_cover(cover)
         | 
| 15 19 | 
             
                unless cover.to_s.include?('/')
         | 
| 16 20 | 
             
                  folder = Rails.root.join('public', 'articles', 'cover').itself
         | 
| @@ -23,5 +27,6 @@ class Article < StaticRecord::Base | |
| 23 27 | 
             
                          author:     :string,
         | 
| 24 28 | 
             
                          rank:       :integer,
         | 
| 25 29 | 
             
                          important:  :boolean,
         | 
| 26 | 
            -
                          cover:      :string
         | 
| 30 | 
            +
                          cover:      :string,
         | 
| 31 | 
            +
                          category:   :static_record
         | 
| 27 32 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: static-record
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Hugo Chevalier
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2016-01- | 
| 11 | 
            +
            date: 2016-01-08 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rails
         | 
| @@ -144,7 +144,9 @@ files: | |
| 144 144 | 
             
            - app/views/layouts/static_record/application.html.erb
         | 
| 145 145 | 
             
            - config/routes.rb
         | 
| 146 146 | 
             
            - lib/static_record.rb
         | 
| 147 | 
            +
            - lib/static_record/concerns/getters_setters_concern.rb
         | 
| 147 148 | 
             
            - lib/static_record/concerns/query_building_concern.rb
         | 
| 149 | 
            +
            - lib/static_record/concerns/request_execution_concern.rb
         | 
| 148 150 | 
             
            - lib/static_record/concerns/sqlite_storing_concern.rb
         | 
| 149 151 | 
             
            - lib/static_record/engine.rb
         | 
| 150 152 | 
             
            - lib/static_record/exceptions.rb
         | 
| @@ -167,6 +169,7 @@ files: | |
| 167 169 | 
             
            - spec/models/default_value_spec.rb
         | 
| 168 170 | 
             
            - spec/models/querying_spec.rb
         | 
| 169 171 | 
             
            - spec/models/relation_spec.rb
         | 
| 172 | 
            +
            - spec/models/static_record_reference_spec.rb
         | 
| 170 173 | 
             
            - spec/rails_helper.rb
         | 
| 171 174 | 
             
            - spec/spec_helper.rb
         | 
| 172 175 | 
             
            - spec/test_app/app/controllers/application_controller.rb
         | 
| @@ -179,6 +182,9 @@ files: | |
| 179 182 | 
             
            - spec/test_app/app/models/articles/article_two.rb
         | 
| 180 183 | 
             
            - spec/test_app/app/models/badge.rb
         | 
| 181 184 | 
             
            - spec/test_app/app/models/badges/badge_one.rb
         | 
| 185 | 
            +
            - spec/test_app/app/models/categories/category_one.rb
         | 
| 186 | 
            +
            - spec/test_app/app/models/categories/category_two.rb
         | 
| 187 | 
            +
            - spec/test_app/app/models/category.rb
         | 
| 182 188 | 
             
            - spec/test_app/app/models/role.rb
         | 
| 183 189 | 
             
            - spec/test_app/app/models/roles/role_one.rb
         | 
| 184 190 | 
             
            - spec/test_app/app/models/roles/role_two.rb
         | 
| @@ -234,6 +240,7 @@ test_files: | |
| 234 240 | 
             
            - spec/models/default_value_spec.rb
         | 
| 235 241 | 
             
            - spec/models/querying_spec.rb
         | 
| 236 242 | 
             
            - spec/models/relation_spec.rb
         | 
| 243 | 
            +
            - spec/models/static_record_reference_spec.rb
         | 
| 237 244 | 
             
            - spec/rails_helper.rb
         | 
| 238 245 | 
             
            - spec/spec_helper.rb
         | 
| 239 246 | 
             
            - spec/test_app/app/controllers/application_controller.rb
         | 
| @@ -246,6 +253,9 @@ test_files: | |
| 246 253 | 
             
            - spec/test_app/app/models/articles/article_two.rb
         | 
| 247 254 | 
             
            - spec/test_app/app/models/badge.rb
         | 
| 248 255 | 
             
            - spec/test_app/app/models/badges/badge_one.rb
         | 
| 256 | 
            +
            - spec/test_app/app/models/categories/category_one.rb
         | 
| 257 | 
            +
            - spec/test_app/app/models/categories/category_two.rb
         | 
| 258 | 
            +
            - spec/test_app/app/models/category.rb
         | 
| 249 259 | 
             
            - spec/test_app/app/models/role.rb
         | 
| 250 260 | 
             
            - spec/test_app/app/models/roles/role_one.rb
         | 
| 251 261 | 
             
            - spec/test_app/app/models/roles/role_two.rb
         |