sportdb-readers 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40a0db453b48c9bed47b6370c44249d5c8197df2fddc90a911653f2ddd145357
4
- data.tar.gz: 8792558c03345ba1662249e5239f5b6122324740f353be4143c420f482486742
3
+ metadata.gz: cdad0e950d6144fe9de65be3f4a87057b05e1f03e168237c44c5f0c9f2d3f0b3
4
+ data.tar.gz: 541e0de0a923297dc7b1b7349319e77bcaa31ac5405bb3f2cdd111f522230985
5
5
  SHA512:
6
- metadata.gz: 342de18d45ec3be01a528be68e2e77d18866911cef7fbad17424179c648eda816170e77ea39987bfa66b48af9627284080535eab292c0e9798e3ca25ad09118a
7
- data.tar.gz: 5861f675107c90fdd10f865396df5b43f30df1df63ff3e437f409612853b393d575f96df0b59a86d23c2773791a2a63d57db1df9949ebb4e0845768b088a9654
6
+ metadata.gz: d36e0affcfc3fbdd5fbb50fabcbaebce34935f48a257c7ab7e918cf2cf1a96bdf3b7d2737f05adf75f9094ade927c88806d1fef5ce9d792feaac852534125e86
7
+ data.tar.gz: 797fd4250e078bf2255e38830358cedeea761ea85236e7084f08fd04ba71b2831890267c7a2268cc92312556149dda33a7ef893d0a5878ce9474be221ba50d9b
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 1.2.0
1
+ ### 2.0.0
2
2
 
3
3
  ### 0.0.1 / 2019-10-29
4
4
 
data/Manifest.txt CHANGED
@@ -7,4 +7,11 @@ lib/sportdb/readers.rb
7
7
  lib/sportdb/readers/conf_reader.rb
8
8
  lib/sportdb/readers/match_reader.rb
9
9
  lib/sportdb/readers/package.rb
10
+ lib/sportdb/readers/sync/club.rb
11
+ lib/sportdb/readers/sync/country.rb
12
+ lib/sportdb/readers/sync/event.rb
13
+ lib/sportdb/readers/sync/league.rb
14
+ lib/sportdb/readers/sync/match.rb
15
+ lib/sportdb/readers/sync/more.rb
16
+ lib/sportdb/readers/sync/season.rb
10
17
  lib/sportdb/readers/version.rb
data/README.md CHANGED
@@ -50,15 +50,14 @@ Matchday 1
50
50
  ...
51
51
  ```
52
52
 
53
- (Source: [england/2015-16/1-premierleague-i.txt](https://github.com/openfootball/england/blob/master/2015-16/1-premierleague-i.txt))
53
+ (Source: [england/2015-16/1-premierleague.txt](https://github.com/openfootball/england/blob/master/2015-16/1-premierleague.txt))
54
54
 
55
55
  and let's try:
56
56
 
57
57
  ``` ruby
58
58
  ## assumes football.db datasets for England in ./england directory
59
59
  ## see github.com/openfootball/england
60
- SportDb.read( './england/2015-16/1-premierleague-i.txt' )
61
- SportDb.read( './england/2015-16/1-premierleague-ii.txt' )
60
+ SportDb.read( './england/2015-16/1-premierleague.txt' )
62
61
 
63
62
  ## let's try another season
64
63
  SportDb.read( './england/2019-20/1-premierleague.txt' )
@@ -136,7 +135,7 @@ Round, Date, Team 1, FT, HT, Team 2
136
135
  ```
137
136
  (Source: [england/2019-20/eng.1.csv](https://github.com/footballcsv/england/blob/master/2010s/2019-20/eng.1.csv))
138
137
 
139
- Yes, you can. See the [sportdb-importers library / gem »](https://github.com/sportdb/sport.db/tree/master/sportdb-importers)
138
+ Yes, you can. See the [sportdb-importers library / gem »](https://github.com/sportdb/sport.db/tree/master/sportdb-importers)
140
139
 
141
140
 
142
141
 
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require './lib/sportdb/readers/version.rb'
3
3
 
4
4
  Hoe.spec 'sportdb-readers' do
5
5
 
6
- self.version = SportDb::Readers::VERSION
6
+ self.version = SportDb::Module::Readers::VERSION
7
7
 
8
8
  self.summary = "sportdb-readers - sport.db readers for leagues, seasons, clubs, match schedules and results, and more"
9
9
  self.description = summary
@@ -20,11 +20,13 @@ Hoe.spec 'sportdb-readers' do
20
20
  self.licenses = ['Public Domain']
21
21
 
22
22
  self.extra_deps = [
23
- ['sportdb-sync', '>= 1.2.0'],
23
+ ['sportdb-formats', '>= 2.0.0'],
24
+ ['sportdb-catalogs', '>= 1.2.1'],
25
+ ['sportdb-models', '>= 2.1.0'],
24
26
  ]
25
27
 
26
28
  self.spec_extras = {
27
- required_ruby_version: '>= 2.2.2'
29
+ required_ruby_version: '>= 3.1.0'
28
30
  }
29
31
 
30
32
  end
@@ -1,8 +1,18 @@
1
1
 
2
2
  module SportDb
3
-
4
3
  class MatchReader ## todo/check: rename to MatchReaderV2 (use plural?) why? why not?
5
4
 
5
+
6
+ ### fix - remove catalog reference!!!
7
+ ## use classes with "augmented" static methods
8
+ ## e.g. Club.match_by etc.
9
+ def catalog
10
+ puts "[deprecated] do NOT use catalog reference; use classes with enhanced search static methods!"
11
+ Import.catalog
12
+ end
13
+
14
+
15
+
6
16
  def self.read( path, season: nil ) ## use - rename to read_file or from_file etc. - why? why not?
7
17
  txt = File.open( path, 'r:utf-8' ) {|f| f.read }
8
18
  parse( txt, season: season )
@@ -23,43 +33,22 @@ class MatchReader ## todo/check: rename to MatchReaderV2 (use plural?) why? w
23
33
  secs = LeagueOutlineReader.parse( @txt, season: season )
24
34
  pp secs
25
35
 
26
-
27
- ###
28
- ## todo/check/fix: move to LeagueOutlineReader for (re)use - why? why not?
29
- ## use sec[:lang] or something?
30
- langs = { ## map country keys to lang codes
31
- 'de' => 'de', ## de - Deutsch (German)
32
- 'at' => 'de',
33
- 'ch' => 'de',
34
- 'fr' => 'fr', ## fr - French
35
- 'it' => 'it', ## it - Italian
36
- 'es' => 'es', ## es - Español (Spanish)
37
- 'mx' => 'es',
38
- 'ar' => 'es', ## Argentina
39
- 'pt' => 'pt', ## pt - Português (Portuguese)
40
- 'br' => 'pt',
41
- }
42
-
43
36
  secs.each do |sec| ## sec(tion)s
44
37
  season = sec[:season]
45
38
  league = sec[:league]
46
39
  stage = sec[:stage]
47
40
  lines = sec[:lines]
48
41
 
49
- ## hack for now: switch lang
50
- ## todo/fix: set lang for now depending on league country!!!
51
- if league.intl? ## todo/fix: add intl? to ActiveRecord league!!!
52
- Import.config.lang = 'en'
53
- else ## assume national/domestic
54
- Import.config.lang = langs[ league.country.key ] || 'en'
55
- end
56
-
57
42
  ### check if event info availabe - use start_date;
58
43
  ## otherwise we have to guess (use a "synthetic" start_date)
59
44
  event_info = catalog.events.find_by( season: season,
60
45
  league: league )
61
46
 
62
47
  start = if event_info && event_info.start_date
48
+ puts "event info found:"
49
+ puts " using start date from event: "
50
+ pp event_info
51
+ pp event_info.start_date
63
52
  event_info.start_date
64
53
  else
65
54
  if season.year?
@@ -70,61 +59,101 @@ class MatchReader ## todo/check: rename to MatchReaderV2 (use plural?) why? w
70
59
  end
71
60
 
72
61
 
73
- ### todo/check: make sure team include teams from group def too!!!!!
74
- ###
75
- ### note - only use teams and grounds for now
76
- auto_conf_teams,
77
- _rounds, _groups, _round_defs, _group_defs,
78
- auto_conf_grounds,
79
- _ = AutoConfParser.parse( lines, start: start )
80
-
81
-
62
+ parser = MatchParser.new( lines,
63
+ start ) ## note: keep season start_at date for now (no need for more specific stage date need for now)
64
+
65
+ auto_conf_teams, matches, rounds, groups = parser.parse
66
+
67
+ puts ">>> #{auto_conf_teams.size} teams:"
68
+ pp auto_conf_teams
69
+ puts ">>> #{matches.size} matches:"
70
+ ## pp matches
71
+ puts ">>> #{rounds.size} rounds:"
72
+ pp rounds
73
+ puts ">>> #{groups.size} groups:"
74
+ pp groups
75
+
76
+
77
+
82
78
  ## step 1: map/find teams
83
79
 
84
80
  ## note: loop over keys (holding the names); values hold the usage counter!! e.g. 'Arsenal' => 2, etc.
85
81
  mods = nil
86
82
  if league.clubs? && league.intl? ## todo/fix: add intl? to ActiveRecord league!!!
83
+
84
+ ## quick hack - use "dynamic" keys for keys
85
+ uefa_el_q = Import::League.match_by( code: 'uefa.el.quali' )[0]
86
+ uefa_cl_q = Import::League.match_by( code: 'uefa.cl.quali' )[0]
87
+ uefa_cl = Import::League.match_by( code: 'uefa.cl' )[0]
88
+ uefa_el = Import::League.match_by( code: 'uefa.el' )[0]
89
+
90
+ pp [uefa_el_q, uefa_cl_q, uefa_cl, uefa_el]
91
+
87
92
  ### quick hack mods for popular/known ambigious club names
88
93
  ## todo/fix: make more generic / reuseable!!!!
89
94
  mods = {}
90
95
  ## europa league uses same mods as champions league
91
- mods[ 'uefa.el.quali' ] =
92
- mods[ 'uefa.cl.quali' ] =
93
- mods[ 'uefa.el' ] =
94
- mods[ 'uefa.cl' ] = catalog.clubs.build_mods(
96
+ mods[ uefa_el_q.key ] =
97
+ mods[ uefa_cl_q.key ] =
98
+ mods[ uefa_el.key ] =
99
+ mods[ uefa_cl.key ] = catalog.clubs.build_mods(
95
100
  { 'Liverpool | Liverpool FC' => 'Liverpool FC, ENG',
96
101
  'Arsenal | Arsenal FC' => 'Arsenal FC, ENG',
97
102
  'Barcelona' => 'FC Barcelona, ESP',
98
- 'Valencia' => 'Valencia CF, ESP' })
103
+ 'Valencia' => 'Valencia CF, ESP',
104
+ 'Rangers FC' => 'Rangers FC, SCO',
105
+ })
99
106
  end
100
107
 
101
108
  # puts " [debug] auto_conf_teams:"
102
109
  # pp auto_conf_teams
103
110
 
104
111
 
105
- teams = catalog.teams.find_by!( name: auto_conf_teams.keys,
112
+ ## todo/fix
113
+ ## ** !!! ERROR - too many matches (2) for club >Barcelona<:
114
+ ## [<Club: FC Barcelona (ESP)>, <Club: Barcelona Guayaquil (ECU)>]
115
+
116
+ puts "league:"
117
+ pp league
118
+
119
+ teams = catalog.teams.find_by!( name: auto_conf_teams,
106
120
  league: league,
107
121
  mods: mods )
108
122
 
109
- # puts " [debug] teams:"
110
- # pp teams
123
+ puts " [debug] teams:"
124
+ pp teams
125
+
111
126
 
112
127
  ## build mapping - name => team struct record
113
- team_mapping = auto_conf_teams.keys.zip( teams ).to_h
128
+ team_mapping = auto_conf_teams.zip( teams ).to_h
114
129
 
115
- # puts " [debug] team_mapping:"
116
- # pp team_mapping
130
+ puts " [debug] team_mapping:"
131
+ pp team_mapping
117
132
 
118
-
119
133
 
120
- parser = MatchParser.new( lines,
121
- team_mapping,
122
- start ) ## note: keep season start_at date for now (no need for more specific stage date need for now)
134
+ ## quick (and dirty) hack
135
+ ## update all team strings with mapped records
136
+ matches.each do |match|
137
+ match.update( team1: team_mapping[ match.team1 ] )
138
+ match.update( team2: team_mapping[ match.team2 ] )
139
+ end
123
140
 
124
- matches, rounds, groups = parser.parse
141
+ ## quick hack cont.
142
+ ## rebuild groups with all team strings with mapped records
143
+ groups = groups.map do |old_group|
144
+ group = Import::Group.new(
145
+ name: old_group.name,
146
+ teams: old_group.teams.map {|team| team_mapping[team] }
147
+ )
148
+ group
149
+ end
150
+ puts "groups:"
151
+ pp groups
125
152
 
126
- pp rounds
127
- pp groups
153
+ ## fix
154
+ ## !! ERROR - no (cached) team rec found for team in group >Group A<
155
+ ## for >#<Sports::Club:0x000002c7e1686040><
156
+ ### update sync group to check for records (use .name) !!!
128
157
 
129
158
 
130
159
  ######################################################
@@ -166,10 +195,10 @@ class MatchReader ## todo/check: rename to MatchReaderV2 (use plural?) why? w
166
195
  ## e.g. group.teams assumes an array of team names e.g.
167
196
  ## ["Spain", "Czech Republic", "Turkey", "Croatia"]
168
197
  group_team_ids = []
169
- group.teams.each do |team_name|
170
- team_rec = cache_team_recs[ team_name ]
198
+ group.teams.each do |team|
199
+ team_rec = cache_team_recs[ team.name ]
171
200
  if team_rec.nil? ## assume team MUST always be present/known in mapping (via autoconfig parser)
172
- puts "!! ERROR - no (cached) team rec found for team in group >#{group.name}< for >#{team_name}<"
201
+ puts "!! ERROR - no (cached) team rec found for team in group >#{group.name}< for >#{team}<"
173
202
  exit 1
174
203
  end
175
204
  group_team_ids << team_rec.id
@@ -182,6 +211,7 @@ class MatchReader ## todo/check: rename to MatchReaderV2 (use plural?) why? w
182
211
  round_rec = Sync::Round.find_or_create( round, event: event_rec ) ## check: use/rename to EventRound why? why not?
183
212
  end
184
213
 
214
+
185
215
  matches.each do |match|
186
216
  ## note: pass along stage (if present): stage - optional from heading!!!!
187
217
  match = match.update( stage: stage ) if stage
@@ -193,10 +223,5 @@ class MatchReader ## todo/check: rename to MatchReaderV2 (use plural?) why? w
193
223
  end # method parse
194
224
 
195
225
 
196
- ######################
197
- # (convenience) helpers
198
-
199
- def catalog() Import.catalog; end
200
-
201
226
  end # class MatchReader
202
227
  end # module SportDb
@@ -0,0 +1,47 @@
1
+ module SportDb
2
+ module Sync
3
+ class Club
4
+
5
+ ## auto-cache all clubs by find_or_create for later mapping / lookup
6
+ def self.cache() @cache ||= {}; end
7
+
8
+
9
+ ##################################
10
+ # finders
11
+
12
+ def self.find_or_create( club )
13
+ ## note: assume "canonical unique" names for now for clubs
14
+ rec = Model::Team.find_by( name: club.name )
15
+ if rec.nil?
16
+
17
+ ## todo/fix: move auto-key gen to structs for re(use)!!!!!!
18
+ ## check if key is present otherwise generate e.g. remove all non-ascii a-z chars
19
+ key = club.key || club.name.downcase.gsub( /[^a-z]/, '' )
20
+ puts "add club: #{key}, #{club.name}, #{club.country.name} (#{club.country.key})"
21
+
22
+ attribs = {
23
+ key: key,
24
+ name: club.name,
25
+ country_id: Sync::Country.find_or_create( club.country ).id,
26
+ club: true,
27
+ national: false ## check -is default anyway - use - why? why not?
28
+ ## todo/fix: add city if present - why? why not?
29
+ }
30
+
31
+ attribs[:code] = club.code if club.code ## add code (abbreviation) if present
32
+
33
+ if club.alt_names.empty? == false
34
+ attribs[:alt_names] = club.alt_names.join('|')
35
+ end
36
+
37
+ rec = Model::Team.create!( attribs )
38
+ end
39
+ ## auto-add to cache
40
+ cache[club.name] = rec
41
+
42
+ rec
43
+ end
44
+
45
+ end # class Club
46
+ end # module Sync
47
+ end # module SportDb
@@ -0,0 +1,39 @@
1
+ module SportDb
2
+ module Sync
3
+ class Country
4
+
5
+ #############################
6
+ # finders
7
+
8
+ def self.find( country )
9
+ WorldDb::Model::Country.find_by( key: country.key )
10
+ end
11
+
12
+ def self.find!( country )
13
+ rec = find( country )
14
+ if rec.nil?
15
+ puts "** !!! ERROR !!! - country for key >#{country.key}< not found; sorry - add to COUNTRIES table"
16
+ exit 1
17
+ end
18
+ rec
19
+ end
20
+
21
+ def self.find_or_create( country )
22
+ rec = find( country )
23
+ if rec.nil?
24
+ attribs = {
25
+ key: country.key,
26
+ name: country.name,
27
+ code: country.code, ## fix: uses fifa code now (should be iso-alpha3 if available)
28
+ ## fifa: country.fifa,
29
+ area: 1,
30
+ pop: 1
31
+ }
32
+ rec = WorldDb::Model::Country.create!( attribs )
33
+ end
34
+ rec
35
+ end
36
+ end # class Country
37
+
38
+ end # module Sync
39
+ end # module SportDb
@@ -0,0 +1,72 @@
1
+ module SportDb
2
+ module Sync
3
+
4
+ class Event
5
+
6
+ ##################################################
7
+ # finders
8
+ def self.find_by( league:, season: )
9
+ ## note: allow passing in of activerecord db records too - why? why not?
10
+ ## fix - change ArgumentError to TypeError !! (if TypeError exists)
11
+ raise ArgumentError, "league struct record expected; got #{league.class.name}" unless league.is_a?( Import::League )
12
+ raise ArgumentError, "season struct record expected; got #{season.class.name}" unless season.is_a?( Import::Season )
13
+
14
+ ## auto-create league and season (db) records if missing? - why? why not?
15
+ season_rec = Season.find( season )
16
+ league_rec = League.find( league )
17
+
18
+ rec = nil
19
+ rec = Model::Event.find_by( league_id: league_rec.id,
20
+ season_id: season_rec.id ) if season_rec && league_rec
21
+ rec
22
+ end
23
+
24
+ def self.find_by!( league:, season: )
25
+ rec = find_by( league: league, season: season )
26
+ if rec.nil?
27
+ puts "** !!!ERROR!!! db sync - no event match found for:"
28
+ pp league
29
+ pp season
30
+ exit 1
31
+ end
32
+ rec
33
+ end
34
+
35
+ def self.find_or_create_by( league:, season: )
36
+ ## note: allow passing in of activerecord db records too - why? why not?
37
+ raise ArgumentError, "league struct record expected; got #{league.class.name}" unless league.is_a?( Import::League )
38
+ raise ArgumentError, "season struct record expected; got #{season.class.name}" unless season.is_a?( Import::Season )
39
+
40
+ ## note: auto-creates league and season (db) records if missing - why? why not?
41
+ season_rec = Season.find_or_create( season )
42
+ league_rec = League.find_or_create( league )
43
+
44
+ rec = Model::Event.find_by( league_id: league_rec.id,
45
+ season_id: season_rec.id )
46
+ if rec.nil?
47
+ attribs = {
48
+ league_id: league_rec.id,
49
+ season_id: season_rec.id,
50
+ }
51
+
52
+ ## quick hack/change later !!
53
+ ## todo/fix: check season - if is length 4 (single year) use 2017, 1, 1
54
+ ## otherwise use 2017, 7, 1
55
+ ## start_at use year and 7,1 e.g. Date.new( 2017, 7, 1 )
56
+ ## hack: fix/todo1!!
57
+ ## add "fake" start_date for now
58
+ attribs[:start_date] = if season.year? ## e.g. assume 2018 etc.
59
+ Date.new( season.start_year, 1, 1 )
60
+ else ## assume 2014/15 etc.
61
+ Date.new( season.start_year, 7, 1 )
62
+ end
63
+
64
+ rec = Model::Event.create!( attribs )
65
+ end
66
+ rec
67
+ end
68
+ end # class Event
69
+
70
+ end # module Sync
71
+ end # module SportDb
72
+
@@ -0,0 +1,40 @@
1
+ module SportDb
2
+ module Sync
3
+ class League
4
+
5
+ ###################################
6
+ # finders
7
+
8
+ def self.find( league )
9
+ Model::League.find_by( key: league.key )
10
+ end
11
+
12
+ def self.find!( league )
13
+ rec = find( league )
14
+ if rec.nil?
15
+ puts "** !!!ERROR!!! db sync - no league match found for:"
16
+ pp league
17
+ exit 1
18
+ end
19
+ rec
20
+ end
21
+
22
+ def self.find_or_create( league )
23
+ rec = find( league )
24
+ if rec.nil?
25
+ attribs = { key: league.key,
26
+ name: league.name }
27
+
28
+ if league.country
29
+ attribs[ :country_id ] = Sync::Country.find_or_create( league.country ).id
30
+ end
31
+
32
+ rec = Model::League.create!( attribs )
33
+ end
34
+ rec
35
+ end
36
+
37
+ end # class League
38
+ end # module Sync
39
+ end # module SportDb
40
+
@@ -0,0 +1,147 @@
1
+ module SportDb
2
+ module Sync
3
+
4
+ class Match
5
+ ### todo/fix: rename to create!! (add update support later) !!!!
6
+ ## use update_by_round or update_by_date or update_by_teams or such
7
+ ## NO easy (unique always auto-id match) possible!!!!!!
8
+ def self.create_or_update( match, event: )
9
+ ## note: MUST find round, thus, use bang (!)
10
+
11
+ ## todo/check: allow strings too - why? why not?
12
+
13
+
14
+ ## todo/check:
15
+ ## how to model "same" rounds in different stages
16
+ ## e.g. Belgium
17
+ ## in regular season (stage) - round 1, round 2, etc.
18
+ ## in playoff (stage) - round 1, round 2, etc.
19
+ ## reference same round or create a new one for each stage!!???
20
+ ## and lookup by name AND stage??
21
+
22
+
23
+ round_rec = if match.round
24
+ ## query for round - allow string or round rec
25
+ round_name = match.round.is_a?( String ) ? match.round : match.round.name
26
+ Model::Round.find_by!( event_id: event.id,
27
+ name: round_name )
28
+ else # note: allow matches WITHOUT rounds too (e.g. England Football League 1888 and others)
29
+ nil
30
+ end
31
+
32
+ ## todo/check: allow fallback with db lookup if NOT found in cache - why? why not?
33
+ ## or better use Sync::Team.find_or_create( team ) !!!!!!! to auto-create on first hit!
34
+ ## || Team.find_or_create( team1 ) -- note: does NOT work for string (only recs) - what to do?
35
+ ## || Model::Team.find_by!( name: team1_name )
36
+ team1_name = match.team1.is_a?( String ) ? match.team1 : match.team1.name
37
+ team1_rec = Team.cache[ team1_name ]
38
+ team2_name = match.team2.is_a?( String ) ? match.team2 : match.team2.name
39
+ team2_rec = Team.cache[ team2_name ]
40
+
41
+ ## check optional group (e.g. Group A, etc.)
42
+ group_rec = if match.group
43
+ group_name = match.group.is_a?( String ) ? match.group : match.group.name
44
+ Model::Group.find_by!( event_id: event.id,
45
+ name: group_name )
46
+ else
47
+ nil
48
+ end
49
+
50
+ ## check optional stage (e.g. Regular, Play Off, Relegation, etc. )
51
+ stage_rec = if match.stage
52
+ stage_name = match.stage.is_a?( String ) ? match.stage : match.stage.name
53
+ Model::Stage.find_by!( event_id: event.id,
54
+ name: stage_name )
55
+ else
56
+ nil
57
+ end
58
+
59
+ ### todo/check: what happens if there's more than one match? exception raised??
60
+ rec = if ['N. N.'].include?( team1_name ) && ## some special cases - always assume new record for now (to avoid ambigious update conflict)
61
+ ['N. N.'].include?( team2_name )
62
+ ## always assume new record for now
63
+ ## check for date or such - why? why not?
64
+ nil
65
+ elsif round_rec
66
+ ## add match status too? allows [abandoned] and [replay] in same round
67
+ find_attributes = { round_id: round_rec.id,
68
+ team1_id: team1_rec.id,
69
+ team2_id: team2_rec.id }
70
+
71
+ ## add stage if present to query
72
+ find_attributes[ :stage_id] = stage_rec.id if stage_rec
73
+
74
+ Model::Match.find_by( find_attributes )
75
+ else
76
+ ## always assume new record for now
77
+ ## check for date or such - why? why not?
78
+ nil
79
+ end
80
+
81
+ if rec.nil?
82
+ ## find last pos - check if it can be nil? yes, is nil if no records found
83
+ max_pos = Model::Match.where( event_id: event.id ).maximum( 'pos' )
84
+ max_pos = max_pos ? max_pos+1 : 1
85
+
86
+ attribs = { event_id: event.id, ## todo/fix: change to data struct too?
87
+ team1_id: team1_rec.id,
88
+ team2_id: team2_rec.id,
89
+ pos: max_pos,
90
+ num: match.num, ## note - might be nil (not nil for euro, world cup, etc.)
91
+ # date: match.date.to_date, ## todo/fix: split and add date & time!!!!
92
+ date: match.date, # assume iso format as string e.g. 2021-07-10 !!!
93
+ time: match.time, # assume iso format as string e.g. 21:00 !!!
94
+ score1: match.score1,
95
+ score2: match.score2,
96
+ score1i: match.score1i,
97
+ score2i: match.score2i,
98
+ score1et: match.score1et,
99
+ score2et: match.score2et,
100
+ score1p: match.score1p,
101
+ score2p: match.score2p,
102
+ status: match.status }
103
+
104
+ attribs[ :round_id ] = round_rec.id if round_rec
105
+ attribs[ :group_id ] = group_rec.id if group_rec
106
+ attribs[ :stage_id ] = stage_rec.id if stage_rec
107
+
108
+ rec = Model::Match.create!( attribs )
109
+
110
+
111
+ #############################################
112
+ ### try to update goals
113
+ #### quick & dirty v0 - redo !!!!
114
+ goals = match.goals
115
+ if goals && goals.size > 0
116
+ goals.each do |goal|
117
+ person_rec = Model::Person.find_by(
118
+ name: goal.player )
119
+ if person_rec.nil?
120
+ person_rec = Model::Person.create!(
121
+ key: goal.player.downcase.gsub( /[^a-z]/, '' ),
122
+ name: goal.player
123
+ )
124
+ end
125
+ Model::Goal.create!(
126
+ match_id: rec.id,
127
+ person_id: person_rec.id,
128
+ team_id: goal.team == 1 ? rec.team1.id
129
+ : rec.team2.id,
130
+ minute: goal.minute,
131
+ offset: goal.offset || 0,
132
+ penalty: goal.penalty,
133
+ owngoal: goal.owngoal,
134
+ )
135
+ end
136
+ end
137
+ else
138
+ # update - todo
139
+ puts "!! ERROR - match updates not yet supported (only inserts); sorry"
140
+ exit 1
141
+ end
142
+ rec
143
+ end
144
+ end # class Match
145
+
146
+ end # module Sync
147
+ end # module SportDb
@@ -0,0 +1,136 @@
1
+
2
+ module SportDb
3
+ module Sync
4
+
5
+
6
+ class NationalTeam
7
+ def self.find_or_create( team )
8
+ rec = Model::Team.find_by( name: team.name )
9
+ if rec.nil?
10
+ puts "add national team: #{team.key}, #{team.name}, #{team.country.name} (#{team.country.key})"
11
+
12
+ ### note: key expected three or more lowercase letters a-z /\A[a-z]{3,}\z/
13
+ attribs = {
14
+ key: team.key, ## note: always use downcase fifa code for now!!!
15
+ name: team.name,
16
+ code: team.code,
17
+ country_id: Sync::Country.find_or_create( team.country ).id,
18
+ club: false,
19
+ national: true ## check -is default anyway - use - why? why not?
20
+ }
21
+
22
+ if team.alt_names.empty? == false
23
+ attribs[:alt_names] = team.alt_names.join('|')
24
+ end
25
+
26
+ rec = Model::Team.create!( attribs )
27
+ end
28
+ rec
29
+ end
30
+ end # class NationalTeam
31
+
32
+
33
+ class Team
34
+ ## auto-cache all clubs by find_or_create for later mapping / lookup
35
+ def self.cache() @cache ||= {}; end
36
+
37
+ def self.find_or_create( team_or_teams )
38
+ if team_or_teams.is_a?( Array )
39
+ recs = []
40
+ teams = team_or_teams
41
+ teams.each do |team|
42
+ recs << __find_or_create( team )
43
+ end
44
+ recs
45
+ else # assome single rec
46
+ team = team_or_teams
47
+ __find_or_create( team )
48
+ end
49
+ end
50
+
51
+ def self.__find_or_create( team ) ## todo/check: use find_or_create_worker instead of _find - why? why not?
52
+ rec = if team.is_a?( Import::NationalTeam )
53
+ NationalTeam.find_or_create( team )
54
+ else ## assume Club
55
+ Club.find_or_create( team )
56
+ end
57
+ cache[ team.name ] = rec ## note: assume "canonical" unique team name
58
+ rec
59
+ end
60
+ end # class Team
61
+
62
+
63
+
64
+ class Round
65
+ def self.find_or_create( round, event: )
66
+ rec = Model::Round.find_by( name: round.name, event_id: event.id )
67
+ if rec.nil?
68
+ ## find last pos - check if it can be nil?
69
+ max_pos = Model::Round.where( event_id: event.id ).maximum( 'pos' )
70
+ max_pos = max_pos ? max_pos+1 : 1
71
+
72
+ attribs = { event_id: event.id,
73
+ name: round.name,
74
+ pos: max_pos
75
+ }
76
+
77
+ ## todo/fix: check if round has (optional) start or end date and add!!!
78
+ ## attribs[ :start_date] = round.start_date.to_date
79
+
80
+ rec = Model::Round.create!( attribs )
81
+ end
82
+ rec
83
+ end
84
+ end # class Round
85
+
86
+
87
+ class Group
88
+ def self.find_or_create( group, event: )
89
+ rec = Model::Group.find_by( name: group.name, event_id: event.id )
90
+ if rec.nil?
91
+ ## find last pos - check if it can be nil?
92
+ max_pos = Model::Group.where( event_id: event.id ).maximum( 'pos' )
93
+ max_pos = max_pos ? max_pos+1 : 1
94
+
95
+ attribs = { event_id: event.id,
96
+ name: group.name,
97
+ pos: max_pos
98
+ }
99
+
100
+ ## todo/fix: check/add optional group key (was: pos before)!!!!
101
+ rec = Model::Group.create!( attribs )
102
+ end
103
+ ## todo/fix: add/update teams in group too!!!!!
104
+ rec
105
+ end
106
+ end # class Group
107
+
108
+
109
+ class Stage
110
+ def self.find( name, event: )
111
+ Model::Stage.find_by( name: name, event_id: event.id )
112
+ end
113
+ def self.find!( name, event: )
114
+ rec = find( name, event: event )
115
+ if rec.nil?
116
+ puts "** !!!ERROR!!! db sync - no stage match found for:"
117
+ pp name
118
+ pp event
119
+ exit 1
120
+ end
121
+ rec
122
+ end
123
+
124
+ def self.find_or_create( name, event: )
125
+ rec = find( name, event: event )
126
+ if rec.nil?
127
+ attribs = { event_id: event.id,
128
+ name: name,
129
+ }
130
+ rec = Model::Stage.create!( attribs )
131
+ end
132
+ rec
133
+ end
134
+ end # class Stage
135
+ end # module Sync
136
+ end # module SportDb
@@ -0,0 +1,36 @@
1
+ module SportDb
2
+ module Sync
3
+ class Season
4
+
5
+ ################
6
+ # finders
7
+
8
+ def self.find( season )
9
+ season = Season( season ) ## auto-convert for now (for old compat) - why? why not?
10
+ Model::Season.find_by( key: season.key )
11
+ end
12
+
13
+ def self.find!( season )
14
+ season = Season( season ) ## auto-convert for now (for old compat) - why? why not?
15
+ rec = find( season )
16
+ if rec.nil?
17
+ puts "** !!!ERROR!!! db sync - no season match found for >#{season.key}<:"
18
+ exit 1
19
+ end
20
+ rec
21
+ end
22
+
23
+ def self.find_or_create( season )
24
+ season = Season( season ) ## auto-convert for now (for old compat) - why? why not?
25
+ rec = find( season )
26
+ if rec.nil?
27
+ attribs = { key: season.key,
28
+ name: season.name }
29
+ rec = Model::Season.create!( attribs )
30
+ end
31
+ rec
32
+ end
33
+ end # class Season
34
+ end # module Sync
35
+ end # module SportDb
36
+
@@ -1,10 +1,11 @@
1
1
 
2
2
 
3
3
  module SportDb
4
+ module Module
4
5
  module Readers
5
6
 
6
- MAJOR = 1 ## todo: namespace inside version or something - why? why not??
7
- MINOR = 2
7
+ MAJOR = 2 ## todo: namespace inside version or something - why? why not??
8
+ MINOR = 0
8
9
  PATCH = 0
9
10
  VERSION = [MAJOR,MINOR,PATCH].join('.')
10
11
 
@@ -21,4 +22,5 @@ module Readers
21
22
  end
22
23
 
23
24
  end # module Readers
25
+ end # module Module
24
26
  end # module SportDb
@@ -1,10 +1,22 @@
1
-
2
- require 'sportdb/sync'
1
+ require 'sportdb/formats'
2
+ require 'sportdb/catalogs'
3
+ require 'sportdb/models'
3
4
 
4
5
 
5
6
  ###
6
7
  # our own code
7
8
  require_relative 'readers/version' # let version always go first
9
+
10
+ ## add sync stuff
11
+ require_relative 'readers/sync/country'
12
+ require_relative 'readers/sync/league'
13
+ require_relative 'readers/sync/season'
14
+ require_relative 'readers/sync/event'
15
+ require_relative 'readers/sync/club'
16
+ require_relative 'readers/sync/more'
17
+ require_relative 'readers/sync/match' ## note - let match sync go last
18
+
19
+ ## add readers & friends
8
20
  require_relative 'readers/conf_reader'
9
21
  require_relative 'readers/match_reader'
10
22
  require_relative 'readers/package'
@@ -12,7 +24,6 @@ require_relative 'readers/package'
12
24
 
13
25
 
14
26
 
15
-
16
27
  ##
17
28
  ## add convenience shortcut helpers
18
29
  module SportDb
@@ -57,4 +68,4 @@ end # module SportDb
57
68
 
58
69
 
59
70
 
60
- puts SportDb::Readers.banner # say hello
71
+ puts SportDb::Module::Readers.banner # say hello
metadata CHANGED
@@ -1,29 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sportdb-readers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-23 00:00:00.000000000 Z
11
+ date: 2024-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: sportdb-sync
14
+ name: sportdb-formats
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 1.2.0
19
+ version: 2.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 1.2.0
26
+ version: 2.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: sportdb-catalogs
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.2.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: sportdb-models
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 2.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.1.0
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rdoc
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -78,6 +106,13 @@ files:
78
106
  - lib/sportdb/readers/conf_reader.rb
79
107
  - lib/sportdb/readers/match_reader.rb
80
108
  - lib/sportdb/readers/package.rb
109
+ - lib/sportdb/readers/sync/club.rb
110
+ - lib/sportdb/readers/sync/country.rb
111
+ - lib/sportdb/readers/sync/event.rb
112
+ - lib/sportdb/readers/sync/league.rb
113
+ - lib/sportdb/readers/sync/match.rb
114
+ - lib/sportdb/readers/sync/more.rb
115
+ - lib/sportdb/readers/sync/season.rb
81
116
  - lib/sportdb/readers/version.rb
82
117
  homepage: https://github.com/sportdb/sport.db
83
118
  licenses:
@@ -93,7 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
128
  requirements:
94
129
  - - ">="
95
130
  - !ruby/object:Gem::Version
96
- version: 2.2.2
131
+ version: 3.1.0
97
132
  required_rubygems_version: !ruby/object:Gem::Requirement
98
133
  requirements:
99
134
  - - ">="