date_queries 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8d1a94a3f288918fe037fcbad546f0c09a3080ce98b17c5b95624a98b82ce17d
4
+ data.tar.gz: 423559d7377ec1218978c8d93af207e5164f721da8894e038c8c02f7da4cdf63
5
+ SHA512:
6
+ metadata.gz: 10357288f3acaa11e2f2d8f99ff7ab50e5c1c4c71594b24625257b086f050662467f22ad383ec2d66d9dd2110e63a0f19af3738a97589f346cb7f5e228d1a606
7
+ data.tar.gz: 6ac8a49474439f4754cc69be44c05a1dec2a710d881b4db33f02273d5d2491b640ba947db35c3cce1d0e7c070e4c3154a739059793b65854f630ef168ea66432
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.0
6
+ before_install: gem install bundler -v 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in date_queries.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "rspec", "~> 3.0"
@@ -0,0 +1,97 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ date_queries (0.0.1)
5
+ rails (~> 4.0.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actionmailer (4.0.3)
11
+ actionpack (= 4.0.3)
12
+ mail (~> 2.5.4)
13
+ actionpack (4.0.3)
14
+ activesupport (= 4.0.3)
15
+ builder (~> 3.1.0)
16
+ erubis (~> 2.7.0)
17
+ rack (~> 1.5.2)
18
+ rack-test (~> 0.6.2)
19
+ activemodel (4.0.3)
20
+ activesupport (= 4.0.3)
21
+ builder (~> 3.1.0)
22
+ activerecord (4.0.3)
23
+ activemodel (= 4.0.3)
24
+ activerecord-deprecated_finders (~> 1.0.2)
25
+ activesupport (= 4.0.3)
26
+ arel (~> 4.0.0)
27
+ activerecord-deprecated_finders (1.0.3)
28
+ activesupport (4.0.3)
29
+ i18n (~> 0.6, >= 0.6.4)
30
+ minitest (~> 4.2)
31
+ multi_json (~> 1.3)
32
+ thread_safe (~> 0.1)
33
+ tzinfo (~> 0.3.37)
34
+ arel (4.0.2)
35
+ atomic (1.1.14)
36
+ builder (3.1.4)
37
+ diff-lcs (1.2.5)
38
+ erubis (2.7.0)
39
+ hike (1.2.3)
40
+ i18n (0.6.9)
41
+ mail (2.5.4)
42
+ mime-types (~> 1.16)
43
+ treetop (~> 1.4.8)
44
+ mime-types (1.25.1)
45
+ minitest (4.7.5)
46
+ multi_json (1.8.4)
47
+ polyglot (0.3.4)
48
+ rack (1.5.2)
49
+ rack-test (0.6.2)
50
+ rack (>= 1.0)
51
+ rails (4.0.3)
52
+ actionmailer (= 4.0.3)
53
+ actionpack (= 4.0.3)
54
+ activerecord (= 4.0.3)
55
+ activesupport (= 4.0.3)
56
+ bundler (>= 1.3.0, < 2.0)
57
+ railties (= 4.0.3)
58
+ sprockets-rails (~> 2.0.0)
59
+ railties (4.0.3)
60
+ actionpack (= 4.0.3)
61
+ activesupport (= 4.0.3)
62
+ rake (>= 0.8.7)
63
+ thor (>= 0.18.1, < 2.0)
64
+ rake (10.1.1)
65
+ rspec (2.14.1)
66
+ rspec-core (~> 2.14.0)
67
+ rspec-expectations (~> 2.14.0)
68
+ rspec-mocks (~> 2.14.0)
69
+ rspec-core (2.14.7)
70
+ rspec-expectations (2.14.5)
71
+ diff-lcs (>= 1.1.3, < 2.0)
72
+ rspec-mocks (2.14.6)
73
+ sprockets (2.11.0)
74
+ hike (~> 1.2)
75
+ multi_json (~> 1.0)
76
+ rack (~> 1.0)
77
+ tilt (~> 1.1, != 1.3.0)
78
+ sprockets-rails (2.0.1)
79
+ actionpack (>= 3.0)
80
+ activesupport (>= 3.0)
81
+ sprockets (~> 2.8)
82
+ thor (0.18.1)
83
+ thread_safe (0.1.3)
84
+ atomic
85
+ tilt (1.4.1)
86
+ treetop (1.4.15)
87
+ polyglot
88
+ polyglot (>= 0.3.1)
89
+ tzinfo (0.3.38)
90
+
91
+ PLATFORMS
92
+ ruby
93
+
94
+ DEPENDENCIES
95
+ date_queries!
96
+ rake
97
+ rspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Ravi Ture
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,133 @@
1
+ # DateQueries
2
+ Package to provide date related scopes for Active Record Models. This gem allows you to have scopes like records with the field in a particular month or year or on a specific day. The gem actually ammends adapters to provide the queries on database level an not just on rails level sopes.
3
+
4
+ ## Installation
5
+
6
+ Add this line to your application's Gemfile:
7
+
8
+ ```ruby
9
+ gem 'date_queries'
10
+ ```
11
+
12
+ And then execute:
13
+
14
+ $ bundle install
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install date_queries
19
+
20
+ ## Usage
21
+
22
+ This gem has two class methods defined
23
+
24
+ ### acts_as_birthday(:field1, :field2, ...)
25
+
26
+ This will give you two methods as followed:
27
+
28
+ ```ruby
29
+
30
+ model User < ActiveRecord::Base
31
+ acts_as_birthday :birth_date
32
+ end
33
+
34
+ user = User.last # => #<User id: 1, name: "Test User", birth_date: "1991-11-11", created_at: "2021-02-01 11:35:48.713098000 +1100", updated_at: "2021-02-01 11:35:48.713098000 +1100">
35
+ user.birth_date_age # => 29
36
+ user.birth_date_today? # => false
37
+
38
+ ```
39
+
40
+ ### date_queries_for(:field1, :field2, ...)
41
+
42
+ This is method provides variety of methods as followed:
43
+
44
+ ```ruby
45
+
46
+ model User < ActiveRecord::Base
47
+ date_queries_for :birth_date
48
+ end
49
+ ```
50
+ In the example above following methods will be created:
51
+
52
+ #### User.birth_dates_passed
53
+
54
+ Scope for user model to find out if the field's date has passed in this year or not.
55
+
56
+ NOTE: This method checks the date in the format of dd/mm and not year.
57
+
58
+ #### User.birth_dates_in_future
59
+
60
+ Scope for user model to find out the records with birth date value has not yet passed for this year.
61
+
62
+ #### User.birth_dates_in(start_date, end_date)
63
+
64
+ Scope to find out records with birth date lies in the given range
65
+
66
+ #### User.birth_dates_in_this_year
67
+
68
+ Finds user records with date field is in this year.
69
+
70
+ #### User.birth_dates_in_this_month
71
+
72
+ Finds Users whoes birth date is in this month
73
+
74
+ #### User.birth_date_is_today
75
+
76
+ Users with the birth date is today
77
+
78
+ #### User.birth_dates_after(date)
79
+
80
+ Users with birth date after given date
81
+
82
+ #### User.birth_dates_before(date)
83
+
84
+ Users with birthdate is before given date
85
+
86
+ #### User.birth_dates_in_range(start_date, end_date, *skip_args)
87
+
88
+ This is a spacial method providing full power of comparing dates while skipping month or year or date of a date field.
89
+
90
+ There can be few examples of this method
91
+ 1. if you want to find out the users with birth day between 11 - 20 in any month and any year
92
+
93
+ ```ruby
94
+ User.birth_dates_in_rage('11-01-2020', '15-01-2020', :month, :year)
95
+ ```
96
+
97
+ 2. If you want to find users with birth_dates in the months of Jan, Feb and March
98
+
99
+ ```ruby
100
+ User.birth_dates_in_rage('11-01-2020', '15-03-2020', :date, :year)
101
+ ```
102
+
103
+ 3. If you want to find birth_dates in this the year 1991 to 2003
104
+
105
+ ```ruby
106
+ User.birth_dates_in_rage('11-01-1991', '15-01-2003', :month, :date)
107
+ ```
108
+
109
+ 4. If you want to users with birth dates in feb to march month of 1992
110
+
111
+ ```ruby
112
+ User.birth_dates_in_rage('11-02-1992', '15-03-1992', :date)
113
+ ```
114
+
115
+
116
+
117
+ These scopes are not neccessarily to be used with only for date type fields, its also compatible with date time fields.
118
+
119
+ Note: This gem is inspired from [Birthday gem](https://github.com/railslove/birthday)
120
+
121
+
122
+ ## TODO:
123
+
124
+ Write Specs
125
+
126
+ ## Contributing
127
+
128
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/date_queries.
129
+
130
+
131
+ ## License
132
+
133
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "date_queries"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,26 @@
1
+ require_relative 'lib/date_queries/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "date_queries"
5
+ spec.version = DateQueries::VERSION
6
+ spec.authors = ["Ravi Ture"]
7
+ spec.email = ["raviture@gmail.com"]
8
+
9
+ spec.summary = %q{A gem for date related database queries}
10
+ spec.description = %q{Provides scopes for date related database queries, such as records between dates with year/month skipped.}
11
+ spec.homepage = "https://github.com/ravi-ture/date_queries"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = "https://github.com/ravi-ture/date_queries"
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+ end
@@ -0,0 +1,50 @@
1
+ require "date_queries/version"
2
+
3
+ module DateQueries
4
+
5
+ autoload :ScopeDefiner, 'date_queries/definers/scope_definer'
6
+ autoload :Adapter, 'date_queries/adapter'
7
+
8
+ def self.included(base)
9
+ base.extend ClassMethods
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ def date_queries_for(*query_fields)
15
+
16
+ # setting the scope types according to ActiveRecord version
17
+ query_fields.each do |field|
18
+ raise ArgumentError, "Column '#{field}' does not exist in '#{self.name}' model." unless self.column_names.include?(field.to_s)
19
+ ScopeDefiner.define_scopes_for(field, self)
20
+ end
21
+ end
22
+
23
+ def acts_as_birthday(*fields)
24
+ # fields to be treated as birthdays
25
+ fields.each do |field|
26
+ raise ArgumentError, "Column '#{field}' does not exist in '#{self.name}' model." unless self.column_names.include?(field.to_s)
27
+ ScopeDefiner.define_birthday_scopes_for(field, self)
28
+
29
+ class_eval %{
30
+ def #{field}_age
31
+ return nil unless self.#{field}?
32
+ today = Date.today.in_time_zone
33
+ age = today.year - #{field}.year
34
+ age -= 1 if today.month < #{field}.month || (today.month == #{field}.month && today.mday < #{field}.mday)
35
+ age
36
+ end
37
+
38
+ def #{field}_today?
39
+ return nil unless self.#{field}?
40
+ Date.today.strftime('%m%d') == #{field}.strftime('%m%d')
41
+ end
42
+ }
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+
50
+ ActiveRecord::Base.send :include, DateQueries
@@ -0,0 +1,13 @@
1
+ module DateQueries
2
+ module Adapter
3
+ autoload :MysqlAdapter, 'date_queries/adapters/mysql_adapter'
4
+ autoload :Mysql2Adapter, 'date_queries/adapters/mysql2_adapter'
5
+ autoload :PostgreSQLAdapter, 'date_queries/adapters/postgresql_adapter'
6
+ autoload :OracleEnhancedAdapter, 'date_queries/adapters/oracle_enanced_adapter'
7
+ autoload :SQLite3Adapter, 'date_queries/adapters/sqlite3_adapter'
8
+
9
+ def self.adapter_for(connection)
10
+ "DateQueries::Adapter::#{connection.class.name.demodulize}".constantize
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module DateQueries
2
+ module Adapter
3
+ class Mysql2Adapter < MysqlAdapter
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,120 @@
1
+ module DateQueries
2
+ module Adapter
3
+ class MysqlAdapter
4
+
5
+ def self.condition_string_for_range(field, start_date, end_date, *skip_args)
6
+ # Mysql related conditions string with skipped arguments
7
+
8
+ if skip_args.present?
9
+ if skip_args.include?(:year)
10
+ if skip_args.include?(:month)
11
+ # condition with month and year skipped
12
+ if start_date.strftime('%d') > end_date.strftime('%d')
13
+ <<-QUERY
14
+ (DATE_FORMAT(`#{field}`, '%d') BETWEEN '#{start_date.in_time_zone.strftime('%d')}' AND '31')
15
+ OR (DATE_FORMAT(`#{field}`, '%d') BETWEEN '01' AND '#{end_date.in_time_zone.strftime('%d')}')
16
+ QUERY
17
+ else
18
+ <<-QUERY
19
+ DATE_FORMAT(`#{field}`, '%d') BETWEEN
20
+ '#{start_date.in_time_zone.strftime('%d')}' AND '#{end_date.in_time_zone.strftime('%d')}'
21
+ QUERY
22
+ end
23
+ elsif skip_args.include?(:date)
24
+ # condition with year and date skipped
25
+ if start_date.strftime('%m') > end_date.strftime('%m')
26
+ <<-QUERY
27
+ (DATE_FORMAT(`#{field}`, '%m') BETWEEN '#{start_date.in_time_zone.strftime('%m')}' AND '12')
28
+ OR (DATE_FORMAT(`#{field}`, '%m') BETWEEN '01' AND '#{end_date.in_time_zone.strftime('%m')}')
29
+ QUERY
30
+ else
31
+ <<-QUERY
32
+ DATE_FORMAT(`#{field}`, '%m') BETWEEN
33
+ '#{start_date.in_time_zone.strftime('%m')}' AND '#{end_date.in_time_zone.strftime('%m')}'
34
+ QUERY
35
+ end
36
+ else
37
+ # condition with only year skipped
38
+ if start_date.strftime('%m%d') > end_date.strftime('%m%d')
39
+ <<-QUERY
40
+ (DATE_FORMAT(`#{field}`, '%m%d') BETWEEN '#{start_date.in_time_zone.strftime('%m%d')}' AND '1231')
41
+ OR (DATE_FORMAT(`#{field}`, '%m%d') BETWEEN '0101' AND '#{end_date.in_time_zone.strftime('%m%d')}')
42
+ QUERY
43
+ else
44
+ <<-QUERY
45
+ DATE_FORMAT(`#{field}`, '%m%d') BETWEEN
46
+ '#{start_date.in_time_zone.strftime('%m%d')}' AND '#{end_date.in_time_zone.strftime('%m%d')}'
47
+ QUERY
48
+ end
49
+ end
50
+ elsif skip_args.include?(:month)
51
+ if skip_args.include?(:date)
52
+ # condition with month and date skipped
53
+ <<-QUERY
54
+ DATE_FORMAT(`#{field}`, '%Y') BETWEEN
55
+ '#{start_date.in_time_zone.strftime('%Y')}' AND '#{end_date.in_time_zone.strftime('%Y')}'
56
+ QUERY
57
+ else
58
+ # condition with only month skipped
59
+ <<-QUERY
60
+ DATE_FORMAT(`#{field}`, '%Y%d') BETWEEN
61
+ '#{start_date.in_time_zone.strftime('%Y%d')}' AND '#{end_date.in_time_zone.strftime('%Y%d')}'
62
+ QUERY
63
+ end
64
+ elsif skip_args.include?(:date)
65
+ # condition with only date skipped
66
+ <<-QUERY
67
+ DATE_FORMAT(`#{field}`, '%Y%m') BETWEEN
68
+ '#{start_date.in_time_zone.strftime('%Y%m')}' AND '#{end_date.in_time_zone.strftime('%Y%m')}'
69
+ QUERY
70
+ end
71
+ end
72
+ end
73
+
74
+ def self.condition_string_for_current_time(field, date, *skip_args)
75
+
76
+ if skip_args.include?(:year)
77
+ if skip_args.include?(:month)
78
+ # condition for date only
79
+ <<-QUERY
80
+ DATE_FORMAT(`#{field}`, '%d') = '#{date.in_time_zone.strftime('%d')}'
81
+ QUERY
82
+ elsif skip_args.include?(:date)
83
+ # condition for month only
84
+ <<-QUERY
85
+ DATE_FORMAT(`#{field}`, '%m') = '#{date.in_time_zone.strftime('%m')}'
86
+ QUERY
87
+ else
88
+ # condition for month and day only
89
+ <<-QUERY
90
+ DATE_FORMAT(`#{field}`, '%m%d') = '#{date.in_time_zone.strftime('%m%d')}'
91
+ QUERY
92
+ end
93
+ elsif skip_args.include?(:month)
94
+ if skip_args.include?(:date)
95
+ # condition for year only
96
+ <<-QUERY
97
+ DATE_FORMAT(`#{field}`, '%Y') = '#{date.in_time_zone.strftime('%Y')}'
98
+ QUERY
99
+ else
100
+ <<-QUERY
101
+ DATE_FORMAT(`#{field}`, '%Y%d') = '#{date.in_time_zone.strftime('%Y%d')}'
102
+ QUERY
103
+ end
104
+ elsif skip_args.include?(:date)
105
+ # condition for month and year only
106
+ <<-QUERY
107
+ DATE_FORMAT(`#{field}`, '%Y%m') = '#{date.in_time_zone.strftime('%Y%m')}'
108
+ QUERY
109
+ else
110
+ # condition for date without time
111
+ <<-QUERY
112
+ DATE_FORMAT(`#{field}`, '%Y%m%d') = '#{date.in_time_zone.strftime('%Y%m%d')}'
113
+ QUERY
114
+ end
115
+
116
+ end
117
+
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,121 @@
1
+ module DateQueries
2
+ module Adapter
3
+ class OracleEnhancedAdapter
4
+
5
+ def self.condition_string_for_range(field, start_date, end_date, *skip_args)
6
+ # Oracle related conditions string with skipped arguments
7
+
8
+ if skip_args.present?
9
+ if skip_args.include?(:year)
10
+ if skip_args.include?(:month)
11
+ # condition with month and year skipped
12
+ if start_date.strftime('%d') > end_date.strftime('%d')
13
+ <<-QUERY
14
+ to_char(#{field}, 'DD') BETWEEN ('#{start_date.in_time_zone.strftime('%d')}' AND '31')
15
+ OR to_char(#{field}, 'DD') BETWEEN ('01' AND '#{end_date.in_time_zone.strftime('%d')}')
16
+ QUERY
17
+ else
18
+ <<-QUERY
19
+ to_char(#{field}, 'DD') BETWEEN
20
+ '#{start_date.in_time_zone.strftime('%d')}' AND '#{end_date.in_time_zone.strftime('%d')}'
21
+ QUERY
22
+ end
23
+ elsif skip_args.include?(:date)
24
+ # condition with year and date skipped
25
+ if start_date.strftime('%m') > end_date.strftime('%m')
26
+ <<-QUERY
27
+ to_char(#{field}, 'MM') BETWEEN ('#{start_date.in_time_zone.strftime('%m')}' AND '12')
28
+ OR to_char(#{field}, 'MM') BETWEEN ('01' AND '#{end_date.in_time_zone.strftime('%m')}')
29
+ QUERY
30
+ else
31
+ <<-QUERY
32
+ to_char(#{field}, 'MM') BETWEEN
33
+ '#{start_date.in_time_zone.strftime('%m')}' AND '#{end_date.in_time_zone.strftime('%m')}'
34
+ QUERY
35
+ end
36
+ else
37
+ # condition with only year skipped
38
+ if start_date.strftime('%m%d') > end_date.strftime('%m%d')
39
+ <<-QUERY
40
+ to_char(#{field}, 'MMDD') BETWEEN ('#{start_date.in_time_zone.strftime('%m%d')}' AND '1231')
41
+ OR to_char(#{field}, 'MMDD') BETWEEN ('0101' AND '#{end_date.in_time_zone.strftime('%m%d')}')
42
+ QUERY
43
+ else
44
+ <<-QUERY
45
+ to_char(#{field}, 'MMDD') BETWEEN
46
+ '#{start_date.in_time_zone.strftime('%m%d')}' AND '#{end_date.in_time_zone.strftime('%m%d')}'
47
+ QUERY
48
+ end
49
+ end
50
+ elsif skip_args.include?(:month)
51
+ if skip_args.include?(:date)
52
+ # condition with month and date skipped
53
+ <<-QUERY
54
+ to_char(#{field}, 'YYYY') BETWEEN
55
+ '#{start_date.in_time_zone.strftime('%Y')}' AND '#{end_date.in_time_zone.strftime('%Y')}'
56
+ QUERY
57
+ else
58
+ # condition with only month skipped
59
+ <<-QUERY
60
+ to_char(#{field}, 'YYYYDD') BETWEEN
61
+ '#{start_date.in_time_zone.strftime('%Y%d')}' AND '#{end_date.in_time_zone.strftime('%Y%d')}'
62
+ QUERY
63
+ end
64
+ elsif skip_args.include?(:date)
65
+ # condition with only date skipped
66
+ <<-QUERY
67
+ to_char(#{field}, 'YYYYMM') BETWEEN
68
+ '#{start_date.in_time_zone.strftime('%Y%m')}' AND '#{end_date.in_time_zone.strftime('%Y%m')}'
69
+ QUERY
70
+ end
71
+ end
72
+ end
73
+
74
+ def self.condition_string_for_current_time(field, date, *skip_args)
75
+
76
+ if skip_args.include?(:year)
77
+ if skip_args.include?(:month)
78
+ # condition for date only
79
+ <<-QUERY
80
+ to_char(#{field}, 'DD') = '#{date.in_time_zone.strftime('%d')}'
81
+ QUERY
82
+ elsif skip_args.include?(:date)
83
+ # condition for month only
84
+ <<-QUERY
85
+ to_char(#{field}, 'MM') = '#{date.in_time_zone.strftime('%m')}'
86
+ QUERY
87
+ else
88
+ # condition for month and day only
89
+ <<-QUERY
90
+ to_char(#{field}, 'MMDD') = '#{date.in_time_zone.strftime('%m%d')}'
91
+ QUERY
92
+ end
93
+ elsif skip_args.include?(:month)
94
+ if skip_args.include?(:date)
95
+ # condition for year only
96
+ <<-QUERY
97
+ to_char(#{field}, 'YYYY') = '#{date.in_time_zone.strftime('%Y')}'
98
+ QUERY
99
+ else
100
+ # condition for year and date only
101
+ <<-QUERY
102
+ to_char(#{field}, 'YYYYDD') = '#{date.in_time_zone.strftime('%Y%d')}'
103
+ QUERY
104
+ end
105
+ elsif skip_args.include?(:date)
106
+ # condition for month and year only.
107
+ <<-QUERY
108
+ to_char(#{field}, 'YYYYMM') = '#{date.in_time_zone.strftime('%Y%m')}'
109
+ QUERY
110
+ else
111
+ # condition for checking current date without time
112
+ <<-QUERY
113
+ to_char(#{field}, 'YYYYMMDD') = '#{date.in_time_zone.strftime('%Y%m%d')}'
114
+ QUERY
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,121 @@
1
+ module DateQueries
2
+ module Adapter
3
+ class PostgreSQLAdapter
4
+
5
+ def self.condition_string_for_range(field, start_date, end_date, *skip_args)
6
+ # PostgreSql related conditions string with skipped arguments
7
+
8
+ if skip_args.present?
9
+ if skip_args.include?(:year)
10
+ if skip_args.include?(:month)
11
+ # condition with month and year skipped
12
+ if start_date.strftime('%d') > end_date.strftime('%d')
13
+ <<-QUERY
14
+ (to_char(\"#{field}\", 'DD') BETWEEN '#{start_date.in_time_zone.strftime('%d')}' AND '31')
15
+ OR (to_char(\"#{field}\", 'DD') BETWEEN '01' AND '#{end_date.in_time_zone.strftime('%d')}')
16
+ QUERY
17
+ else
18
+ <<-QUERY
19
+ to_char(\"#{field}\", 'DD') BETWEEN
20
+ '#{start_date.in_time_zone.strftime('%d')}' AND '#{end_date.in_time_zone.strftime('%d')}'
21
+ QUERY
22
+ end
23
+ elsif skip_args.include?(:date)
24
+ # condition with year and date skipped
25
+ if start_date.strftime('%m') > end_date.strftime('%m')
26
+ <<-QUERY
27
+ (to_char(\"#{field}\", 'MM') BETWEEN '#{start_date.in_time_zone.strftime('%m')}' AND '12')
28
+ OR (to_char(\"#{field}\", 'MM') BETWEEN '01' AND '#{end_date.in_time_zone.strftime('%m')}')
29
+ QUERY
30
+ else
31
+ <<-QUERY
32
+ to_char(\"#{field}\", 'MM') BETWEEN
33
+ '#{start_date.in_time_zone.strftime('%m')}' AND '#{end_date.in_time_zone.strftime('%m')}'
34
+ QUERY
35
+ end
36
+ else
37
+ # condition with only year skipped
38
+ if start_date.strftime('%m%d') > end_date.strftime('%m%d')
39
+ <<-QUERY
40
+ (to_char(\"#{field}\", 'MMDD') BETWEEN '#{start_date.in_time_zone.strftime('%m%d')}' AND '1231')
41
+ OR (to_char(\"#{field}\", 'MMDD') BETWEEN '0101' AND '#{end_date.in_time_zone.strftime('%m%d')}')
42
+ QUERY
43
+ else
44
+ <<-QUERY
45
+ to_char(\"#{field}\", 'MMDD') BETWEEN
46
+ '#{start_date.in_time_zone.strftime('%m%d')}' AND '#{end_date.in_time_zone.strftime('%m%d')}'
47
+ QUERY
48
+ end
49
+ end
50
+ elsif skip_args.include?(:month)
51
+ if skip_args.include?(:date)
52
+ # condition with month and date skipped
53
+ <<-QUERY
54
+ to_char(\"#{field}\", 'YYYY') BETWEEN
55
+ '#{start_date.in_time_zone.strftime('%Y')}' AND '#{end_date.in_time_zone.strftime('%Y')}'
56
+ QUERY
57
+ else
58
+ # condition with only month skipped
59
+ <<-QUERY
60
+ to_char(\"#{field}\", 'YYYYDD') BETWEEN
61
+ '#{start_date.in_time_zone.strftime('%Y%d')}' AND '#{end_date.in_time_zone.strftime('%Y%d')}'
62
+ QUERY
63
+ end
64
+ elsif skip_args.include?(:date)
65
+ # condition with only date skipped
66
+ <<-QUERY
67
+ to_char(\"#{field}\", 'YYYYMM') BETWEEN
68
+ '#{start_date.in_time_zone.strftime('%Y%m')}' AND '#{end_date.in_time_zone.strftime('%Y%m')}'
69
+ QUERY
70
+ end
71
+ end
72
+ end
73
+
74
+ def self.condition_string_for_current_time(field, date, *skip_args)
75
+
76
+ if skip_args.include?(:year)
77
+ if skip_args.include?(:month)
78
+ # condition for date only
79
+ <<-QUERY
80
+ to_char(\"#{field}\", 'DD') = '#{date.in_time_zone.strftime('%d')}'
81
+ QUERY
82
+ elsif skip_args.include?(:date)
83
+ # condition for month only
84
+ <<-QUERY
85
+ to_char(\"#{field}\", 'MM') = '#{date.in_time_zone.strftime('%m')}'
86
+ QUERY
87
+ else
88
+ # condition for month and day only
89
+ <<-QUERY
90
+ to_char(\"#{field}\", 'MMDD') = '#{date.in_time_zone.strftime('%m%d')}'
91
+ QUERY
92
+ end
93
+ elsif skip_args.include?(:month)
94
+ if skip_args.include?(:date)
95
+ # condition for year only
96
+ <<-QUERY
97
+ to_char(\"#{field}\", 'YYYY') = '#{date.in_time_zone.strftime('%Y')}'
98
+ QUERY
99
+ else
100
+ # condition for year and date only
101
+ <<-QUERY
102
+ to_char(\"#{field}\", 'YYYYDD') = '#{date.in_time_zone.strftime('%Y%d')}'
103
+ QUERY
104
+ end
105
+ elsif skip_args.include?(:date)
106
+ # condition for month and year only.
107
+ <<-QUERY
108
+ to_char(\"#{field}\", 'YYYYMM') = '#{date.in_time_zone.strftime('%Y%m')}'
109
+ QUERY
110
+ else
111
+ # condition for checking current date without time
112
+ <<-QUERY
113
+ to_char(\"#{field}\", 'YYYYMMDD') = '#{date.in_time_zone.strftime('%Y%m%d')}'
114
+ QUERY
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,121 @@
1
+ module DateQueries
2
+ module Adapter
3
+ class SQLite3Adapter
4
+
5
+ def self.condition_string_for_range(field, start_date, end_date, *skip_args)
6
+ # SQLite3Adapter related conditions string with skipped arguments
7
+
8
+ if skip_args.present?
9
+ if skip_args.include?(:year)
10
+ if skip_args.include?(:month)
11
+ # condition with month and year skipped
12
+ if start_date.strftime('%d') > end_date.strftime('%d')
13
+ <<-QUERY
14
+ (strftime('%d', #{field}) BETWEEN '#{start_date.in_time_zone.strftime('%d')}' AND '31')
15
+ OR (strftime('%d', #{field}) BETWEEN '01' AND '#{end_date.in_time_zone.strftime('%d')}')
16
+ QUERY
17
+ else
18
+ <<-QUERY
19
+ strftime('%d', #{field}) BETWEEN
20
+ '#{start_date.in_time_zone.strftime('%d')}' AND '#{end_date.in_time_zone.strftime('%d')}'
21
+ QUERY
22
+ end
23
+ elsif skip_args.include?(:date)
24
+ # condition with year and date skipped
25
+ if start_date.strftime('%m') > end_date.strftime('%m')
26
+ <<-QUERY
27
+ (strftime('%m', #{field}) BETWEEN '#{start_date.in_time_zone.strftime('%m')}' AND '12')
28
+ OR (strftime('%m', #{field}) BETWEEN '01' AND '#{end_date.in_time_zone.strftime('%m')}')
29
+ QUERY
30
+ else
31
+ <<-QUERY
32
+ strftime('%m', #{field}) BETWEEN
33
+ '#{start_date.in_time_zone.strftime('%m')}' AND '#{end_date.in_time_zone.strftime('%m')}'
34
+ QUERY
35
+ end
36
+ else
37
+ # condition with only year skipped
38
+ if start_date.strftime('%m%d') > end_date.strftime('%m%d')
39
+ <<-QUERY
40
+ (strftime('%m%d', #{field}) BETWEEN '#{start_date.in_time_zone.strftime('%m%d')}' AND '1231')
41
+ OR (strftime('%m%d', #{field}) BETWEEN '0101' AND '#{end_date.in_time_zone.strftime('%m%d')}')
42
+ QUERY
43
+ else
44
+ <<-QUERY
45
+ strftime('%m%d', #{field}) BETWEEN
46
+ '#{start_date.in_time_zone.strftime('%m%d')}' AND '#{end_date.in_time_zone.strftime('%m%d')}'
47
+ QUERY
48
+ end
49
+ end
50
+ elsif skip_args.include?(:month)
51
+ if skip_args.include?(:date)
52
+ # condition with month and date skipped
53
+ <<-QUERY
54
+ strftime('%Y', #{field}) BETWEEN
55
+ '#{start_date.in_time_zone.strftime('%Y')}' AND '#{end_date.in_time_zone.strftime('%Y')}'
56
+ QUERY
57
+ else
58
+ # condition with only month skipped
59
+ <<-QUERY
60
+ strftime('%Y%d', #{field}) BETWEEN
61
+ '#{start_date.in_time_zone.strftime('%Y%d')}' AND '#{end_date.in_time_zone.strftime('%Y%d')}'
62
+ QUERY
63
+ end
64
+ elsif skip_args.include?(:date)
65
+ # condition with only date skipped
66
+ <<-QUERY
67
+ strftime('%Y%m', #{field}) BETWEEN
68
+ '#{start_date.in_time_zone.strftime('%Y%m')}' AND '#{end_date.in_time_zone.strftime('%Y%m')}'
69
+ QUERY
70
+ end
71
+ end
72
+ end
73
+
74
+ def self.condition_string_for_current_time(field, date, *skip_args)
75
+
76
+ if skip_args.include?(:year)
77
+ if skip_args.include?(:month)
78
+ # condition for date only
79
+ <<-QUERY
80
+ strftime('%d', #{field}) = '#{date.in_time_zone.strftime('%d')}'
81
+ QUERY
82
+ elsif skip_args.include?(:date)
83
+ # condition for month only
84
+ <<-QUERY
85
+ strftime('%m', #{field}) = '#{date.in_time_zone.strftime('%m')}'
86
+ QUERY
87
+ else
88
+ # condition for month and day only
89
+ <<-QUERY
90
+ strftime('%m%d', #{field}) = '#{date.in_time_zone.strftime('%m%d')}'
91
+ QUERY
92
+ end
93
+ elsif skip_args.include?(:month)
94
+ if skip_args.include?(:date)
95
+ # condition for year only
96
+ <<-QUERY
97
+ strftime('%Y', #{field}) = '#{date.in_time_zone.strftime('%Y')}'
98
+ QUERY
99
+ else
100
+ # condition for year and date only
101
+ <<-QUERY
102
+ strftime('%Y%d', #{field}) = '#{date.in_time_zone.strftime('%Y%d')}'
103
+ QUERY
104
+ end
105
+ elsif skip_args.include?(:date)
106
+ # condition for month and year only.
107
+ <<-QUERY
108
+ strftime('%Y%m', #{field}) = '#{date.in_time_zone.strftime('%Y%m')}'
109
+ QUERY
110
+ else
111
+ # condition for checking current date without time
112
+ <<-QUERY
113
+ strftime('%Y%m%d', #{field}) = '#{date.in_time_zone.strftime('%Y%m%d')}'
114
+ QUERY
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,137 @@
1
+ module DateQueries
2
+ module ScopeDefiner
3
+ def self.define_scopes_for(field, klass)
4
+ define_scopes_without_arguments(field, klass)
5
+ define_scopes_with_arguments(field, klass)
6
+ end
7
+
8
+ def self.define_birthday_scopes_for(field, klass)
9
+ define_scopes_without_arguments(field, klass)
10
+ klass.send('scope', :"#{field.to_s.pluralize}_passed", klass.class_eval(
11
+ <<-LAMBDA
12
+ lambda {
13
+ where ::DateQueries::Adapter.adapter_for(self.connection).condition_string_for_range(
14
+ field,
15
+ DateTime.new(Date.today.year, 1, 1),
16
+ DateTime.now - 1.day,
17
+ :year
18
+ )
19
+ }
20
+ LAMBDA
21
+ ))
22
+
23
+ klass.send('scope', :"#{field.to_s.pluralize}_in_future", klass.class_eval(
24
+ <<-LAMBDA
25
+ lambda {
26
+ where ::DateQueries::Adapter.adapter_for(self.connection).condition_string_for_range(
27
+ field,
28
+ DateTime.now,
29
+ DateTime.new(Date.today.year, 12, 31),
30
+ :year
31
+ )
32
+ }
33
+ LAMBDA
34
+ ))
35
+
36
+ klass.send('scope', :"#{field.to_s.pluralize}_in", klass.class_eval(
37
+ <<-PROC
38
+ lambda {|start_date, end_date|
39
+ where ::DateQueries::Adapter.adapter_for(self.connection).condition_string_for_range(
40
+ field,
41
+ start_date,
42
+ end_date,
43
+ :year
44
+ )
45
+ }
46
+ PROC
47
+ ))
48
+ end
49
+
50
+ def self.define_scopes_without_arguments(field, klass)
51
+ # #{field}_in_this_year
52
+ klass.send('scope', :"#{field.to_s.pluralize}_in_this_year", klass.class_eval(
53
+ <<-LAMBDA
54
+ lambda {
55
+ where ::DateQueries::Adapter.adapter_for(self.connection).condition_string_for_current_time(
56
+ field,
57
+ Date.today,
58
+ :date, :month
59
+ )
60
+ }
61
+ LAMBDA
62
+ ))
63
+
64
+ # #{field}_in_this_month
65
+ klass.send('scope', :"#{field.to_s.pluralize}_in_this_month", klass.class_eval(
66
+ <<-LAMBDA
67
+ lambda {
68
+ where ::DateQueries::Adapter.adapter_for(self.connection).condition_string_for_current_time(
69
+ field,
70
+ Date.today,
71
+ :date, :year
72
+ )
73
+ }
74
+ LAMBDA
75
+ ))
76
+
77
+ # #{field}_is_today
78
+ klass.send('scope', :"#{field.to_s}_is_today", klass.class_eval(
79
+ <<-LAMBDA
80
+ lambda {
81
+ where ::DateQueries::Adapter.adapter_for(self.connection).condition_string_for_current_time(
82
+ field,
83
+ Date.today
84
+ )
85
+ }
86
+ LAMBDA
87
+ ))
88
+ end
89
+
90
+ def self.define_scopes_with_arguments(field, klass)
91
+
92
+ # #{field}_before(dateTime)
93
+ klass.send('scope', :"#{field.to_s.pluralize}_after", klass.class_eval(
94
+ <<-LAMBDA
95
+ lambda {|end_date|
96
+ where("#{field} < ?", end_date)
97
+ }
98
+ LAMBDA
99
+ ))
100
+
101
+ # #{field}_after(dateTime)
102
+ klass.send('scope', :"#{field.to_s.pluralize}_after", klass.class_eval(
103
+ <<-LAMBDA
104
+ lambda {|start_date|
105
+ where("#{field} > ?", start_date)
106
+ }
107
+ LAMBDA
108
+ ))
109
+
110
+ # #{field}_in_range(start_date, end_date, *skip_args)
111
+ klass.send('scope', :"#{field.to_s.pluralize}_in_range", klass.class_eval(
112
+ <<-PROC
113
+ proc { |start_date, end_date, *skip_args|
114
+ # creating the scope like
115
+ raise ArgumentError, 'Provide at-least one date.' unless start_date.present?
116
+ raise ArgumentError, 'Invalid arguments in dates, end date is not greater than start date.' if end_date.present? and end_date < start_date
117
+ raise ArgumentError, "can not skip all date, month and year" if ([:year, :month, :date] - skip_args).blank?
118
+
119
+ if end_date
120
+ if skip_args.blank?
121
+ # condition without skipping parameters
122
+ where("#{field} BETWEEN :start_date AND :end_date", :start_date => start_date, :end_date => end_date)
123
+ else
124
+ # conditions with skipped parameters
125
+ where ::DateQueries::Adapter.adapter_for(self.connection).condition_string_for_range(field, start_date, end_date, *skip_args)
126
+ end
127
+ else
128
+ # conditions with single date
129
+ where("#{field} = ?", start_date)
130
+ end
131
+ }
132
+ PROC
133
+ )
134
+ )
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,3 @@
1
+ module DateQueries
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: date_queries
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ravi Ture
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-02-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Provides scopes for date related database queries, such as records between
14
+ dates with year/month skipped.
15
+ email:
16
+ - raviture@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".gitignore"
22
+ - ".rspec"
23
+ - ".travis.yml"
24
+ - Gemfile
25
+ - Gemfile.lock
26
+ - LICENSE.txt
27
+ - README.md
28
+ - Rakefile
29
+ - bin/console
30
+ - bin/setup
31
+ - date_queries.gemspec
32
+ - lib/date_queries.rb
33
+ - lib/date_queries/adapter.rb
34
+ - lib/date_queries/adapters/mysql2_adapter.rb
35
+ - lib/date_queries/adapters/mysql_adapter.rb
36
+ - lib/date_queries/adapters/oracle_enhanced_adapter.rb
37
+ - lib/date_queries/adapters/postgresql_adapter.rb
38
+ - lib/date_queries/adapters/sqlite3_adapter.rb
39
+ - lib/date_queries/definers/scope_definer.rb
40
+ - lib/date_queries/version.rb
41
+ homepage: https://github.com/ravi-ture/date_queries
42
+ licenses:
43
+ - MIT
44
+ metadata:
45
+ homepage_uri: https://github.com/ravi-ture/date_queries
46
+ source_code_uri: https://github.com/ravi-ture/date_queries
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: 2.3.0
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubygems_version: 3.1.2
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: A gem for date related database queries
66
+ test_files: []