date_queries 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []