ordlite 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6051393488775c98fdee4716e6c49b5cd89c6cd404a45f48024a47dea633acfb
4
- data.tar.gz: d43e1d73f1b49b27ae35e745eaa8e13be394635d2367233bc6c341fd1aa54933
3
+ metadata.gz: 6f1f6f768a785a0badc768db45c1c8ca831958f983b673fe48990846f3d4260e
4
+ data.tar.gz: 234d31cabdc7ed109144487792da9f77c39821f935e3d7d91a151b91e817d511
5
5
  SHA512:
6
- metadata.gz: 05e95871ce3a85dd31557e38a4247d5cd38e25406e2ac535a1254e6952e68b8054e8c1a06378b4620ce8168c67d1e4cb7eac50305da9e7e59e2f10152a4aa971
7
- data.tar.gz: 3fe7780c583d525dd60170f4ec0e996f430722d53899e3edb321d9af67425024c262a253e1cf718ab0b7316f9fbb3ae0a6903b3a82debf3860511a167872a1ab
6
+ metadata.gz: 403e1addf0b974af179de293a26c5f1f47da8d0f665da1ca1a44a89cbcfb025a642a04930f49f6df35681527b2cbcaae855f87de4b7ce09e6cd88b4cffab1472
7
+ data.tar.gz: ab359d39d1dcdf307e8b3239ed61e2f10f8fc6bfc4316c3f9f5554a9fbc2d88b0d1c24f120afcab9b035c675d82d22e0292c6d1202db7219d64f5e8f2c214b54
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.2.0 / 2023-07-28
1
+ ### 0.2.1
2
2
  ### 0.0.1 / 2023-07-01
3
3
 
4
4
  * Everything is new. First release
data/Manifest.txt CHANGED
@@ -5,6 +5,7 @@ Rakefile
5
5
  lib/ordlite.rb
6
6
  lib/ordlite/base.rb
7
7
  lib/ordlite/cache.rb
8
+ lib/ordlite/factory.rb
8
9
  lib/ordlite/importer.rb
9
10
  lib/ordlite/models/blob.rb
10
11
  lib/ordlite/models/collection.rb
data/README.md CHANGED
@@ -13,7 +13,7 @@ ordlite - ordinals inscription (on bitcoin & co) database let's you query via sq
13
13
 
14
14
  ## SQL Database Model
15
15
 
16
- Inscribes • Blobs • Collections • Generatives
16
+ Inscribes • Blobs • Collections • Factories • Generatives
17
17
 
18
18
 
19
19
  Table Inscribes
@@ -63,6 +63,7 @@ puts
63
63
  puts " #{Inscribe.count} inscribe(s)"
64
64
  puts " #{Blob.count} blob(s)"
65
65
  puts " #{Collection.count} collection(s)"
66
+ puts " #{Factory.count} factories"
66
67
  puts " #{Generative.count} generative(s)"
67
68
 
68
69
  #=> 0 inscribe(s)
@@ -74,68 +75,134 @@ puts " #{Generative.count} generative(s)"
74
75
 
75
76
 
76
77
 
77
- ### Example No 1 - Query Ordgen Deploy / Mint Inscriptions
78
+ ### Example No 1 - Auto-Add (Via Ordinals.com) First Thousand Inscriptions (Sub 1k)
78
79
 
79
80
  ``` ruby
80
81
  require 'ordlite'
81
82
 
82
83
 
83
- OrdDb.connect( adapter: 'sqlite3',
84
- database: './ord.db' )
84
+ OrdDb.open( './ord.db' )
85
85
 
86
86
 
87
- ####################
88
- ## query for deploy candidates
89
- ##
90
- ## e.g. sql where clause like
91
- ## content LIKE '%deploy%'
92
- ## AND ( content LIKE '%orc-721%'
93
- ## OR content LIKE '%og%')
94
- ##
87
+ 1000.times do |num| # auto-add inscription 0-999
88
+ OrdDb.import( num )
89
+ end
90
+
91
+ puts
92
+ puts " #{Inscribe.count} inscribe(s)"
93
+ puts " #{Blob.count} blob(s)"
94
+ #=> 1000 inscribe(s)
95
+ #=> 1000 blob(s)
96
+ ```
95
97
 
96
- deploys = Inscribe.deploys
97
- puts " #{deploys.size} deploy candidate(s)"
98
+ Let's query for the ten biggest (by bytes) inscriptions
99
+ (and pretty print the result):
98
100
 
99
- deploys.each_with_index do |rec,i|
100
- puts "==> deploy #{i} - num #{rec.num} - #{rec.bytes} bytes - #{rec.date}"
101
- puts rec.content
101
+ ```ruby
102
+ Inscribe.biggest.limit(10).each do |rec|
103
+ print "#{number_to_human_size(rec.bytes)} (#{rec.bytes} bytes) - "
104
+ print "Inscribe №#{rec.num} (#{rec.content_type}) - "
105
+ print "#{rec.date} - #{rec.fee} fee in sats"
106
+ print "\n"
102
107
  end
108
+ ```
103
109
 
110
+ resulting in:
104
111
 
105
- punks_deploys = Inscribe.deploys_by( slug: 'diypunks')
106
- puts " #{punks_deploys.size} deploy candidate(s)"
112
+ ```
113
+ 3.73 MB (3915537 bytes) - Inscribe №652 (image/jpeg) - 2023-02-01 20:38:33 - 0 fee in sats
114
+ 385 KB (394718 bytes) - Inscribe №978 (application/epub+zip) - 2023-02-02 06:46:04 - 109325 fee in sats
115
+ 385 KB (394479 bytes) - Inscribe №546 (image/gif) - 2023-02-01 10:41:50 - 1489860 fee in sats
116
+ 385 KB (394440 bytes) - Inscribe №833 (image/png) - 2023-02-02 01:13:51 - 99314 fee in sats
117
+ 381 KB (389858 bytes) - Inscribe №388 (image/jpeg) - 2023-01-31 14:01:38 - 981620 fee in sats
118
+ 379 KB (388417 bytes) - Inscribe №291 (image/gif) - 2023-01-30 17:58:54 - 586794 fee in sats
119
+ 378 KB (386858 bytes) - Inscribe №857 (image/png) - 2023-02-02 01:17:54 - 97407 fee in sats
120
+ 374 KB (383322 bytes) - Inscribe №538 (image/jpeg) - 2023-02-01 10:20:28 - 96519 fee in sats
121
+ 367 KB (375414 bytes) - Inscribe №378 (image/gif) - 2023-01-31 09:47:55 - 945300 fee in sats
122
+ 365 KB (373504 bytes) - Inscribe №288 (image/jpeg) - 2023-01-30 16:51:46 - 94050 fee in sats
123
+ ```
107
124
 
108
125
 
126
+ Let's query for all inscriptions grouped by date (day) and dump the results:
109
127
 
110
- #######################
111
- ## query for mint candidates
112
- ##
113
- ## e.g. sql where clause like
114
- ## content LIKE '%mint%'
115
- ## AND ( content LIKE '%orc-721%'
116
- ## OR content LIKE '%og%')
128
+ ```ruby
129
+ pp Inscribe.counts_by_date ## or count_by_day
130
+ ```
117
131
 
118
- mints = Inscribe.mints
119
- puts " #{mints.size} mint candidate(s)"
132
+ resulting in:
120
133
 
121
- ## print last hundred mint candidates
122
- mints[-100,100].each_with_index do |rec,i|
123
- puts "==> mint #{i} - num #{rec.num} - #{rec.bytes} bytes - #{rec.date}"
124
- puts rec.content
125
- end
134
+ ```
135
+ {"2022-12-14" => 1,
136
+ "2022-12-17" => 1,
137
+ "2022-12-19" => 1,
138
+ "2023-01-05" => 1,
139
+ "2023-01-10" => 1,
140
+ "2023-01-12" => 1,
141
+ "2023-01-13" => 2,
142
+ "2023-01-15" => 1,
143
+ "2023-01-16" => 1,
144
+ "2023-01-19" => 5,
145
+ "2023-01-20" => 3,
146
+ "2023-01-21" => 5,
147
+ "2023-01-22" => 34,
148
+ "2023-01-23" => 23,
149
+ "2023-01-24" => 4,
150
+ "2023-01-25" => 9,
151
+ "2023-01-26" => 12,
152
+ "2023-01-27" => 19,
153
+ "2023-01-28" => 16,
154
+ "2023-01-29" => 128,
155
+ "2023-01-30" => 82,
156
+ "2023-01-31" => 98,
157
+ "2023-02-01" => 220,
158
+ "2023-02-02" => 332}
159
+ ```
126
160
 
161
+ Let's query for all inscriptions grouped by month and dump the results:
162
+
163
+ ```ruby
164
+ pp Inscribe.counts_by_month
165
+ ```
166
+
167
+ resulting in:
168
+
169
+ ```
170
+ {"2022-12" => 3,
171
+ "2023-01" => 445,
172
+ "2023-02" => 552}
173
+ ```
127
174
 
128
- phunks_mints = Inscribe.mints_by( slug: 'diyphunks')
129
- puts " #{phunks_mints.size} mint candidate(s)"
130
175
 
176
+ Let's query for all content types and group by count (descending) and dump the results:
131
177
 
132
- puts " #{deploys.size} deploy candidate(s)"
133
- puts " #{mints.size} mint candidate(s)"
134
178
 
135
- #=> 123 deploy candidate(s)
136
- #=> 7453 mint candidate(s)
179
+ ```ruby
180
+ pp Inscribe.counts_by_content_type
137
181
  ```
138
182
 
183
+ resulting in:
184
+
185
+ ```
186
+ {"image/png" => 475,
187
+ "image/jpeg" => 188,
188
+ "image/webp" => 117,
189
+ "text/plain;charset=utf-8" => 112,
190
+ "image/svg+xml" => 62,
191
+ "text/html;charset=utf-8" => 18,
192
+ "image/gif" => 11,
193
+ "audio/mpeg" => 6,
194
+ "application/pdf" => 2,
195
+ "image/avif" => 2,
196
+ "video/webm" => 2,
197
+ "application/epub+zip" => 1,
198
+ "application/pgp-signature" => 1,
199
+ "audio/midi" => 1,
200
+ "audio/mod" => 1,
201
+ "video/mp4" => 1}
202
+ ```
203
+
204
+ and so on.
205
+
139
206
 
140
207
 
141
208
 
@@ -150,13 +217,10 @@ into an (sql) database e.g. `ord.db`:
150
217
  ``` ruby
151
218
  require 'ordlite'
152
219
 
153
- OrdDb.connect( adapter: 'sqlite3',
154
- database: './ord.db' )
155
-
156
- OrdDb.create_all # build table schema
220
+ OrdDb.open( './ord.db' )
157
221
 
158
222
  cache_dir = './ordinals.cache/inscription'
159
- cache = OrdDb::Cache.new( cache_dir )
223
+ cache = Ordinals::Cache.new( cache_dir )
160
224
  cache.import_all
161
225
 
162
226
 
data/Rakefile CHANGED
@@ -27,6 +27,7 @@ Hoe.spec 'ordlite' do
27
27
  ['props'],
28
28
  ['props-activerecord'],
29
29
  ['sqlite3'],
30
+ ['pixelart'], ## required for factory (ordgen/orc-721) support for now
30
31
  ]
31
32
 
32
33
  self.licenses = ['Public Domain']
data/lib/ordlite/base.rb CHANGED
@@ -134,5 +134,13 @@ module OrdDb
134
134
  end # module OrdDb
135
135
 
136
136
 
137
+
138
+ ####
139
+ # add factory (ordgen/orc-721) support here for now - why? why not?
140
+ require 'pixelart'
141
+ require_relative 'factory'
142
+
143
+
144
+
137
145
  # say hello
138
146
  puts Ordlite.banner ## if defined?($RUBYCOCOS_DEBUG) && $RUBCOCOS_DEBUG
@@ -0,0 +1,132 @@
1
+
2
+
3
+ class FactorySpritesheet ## check - rename to catalog or atlas NOT spritesheet - why? why not?
4
+ def self.read_inscribes( *inscribes, width:,
5
+ height: )
6
+ ## map inscribes to images
7
+ images = inscribes.map {|inscribe| Pixelart::Image.blob( inscribe.content ) }
8
+ ## puts " #{images.size} image(s)"
9
+
10
+ new( *images, width: width,
11
+ height: height)
12
+ end
13
+
14
+ def initialize( *images, width:,
15
+ height: )
16
+ @tile_width = width
17
+ @tile_height = height
18
+ @tiles = []
19
+ images.each {|img| add(img) }
20
+ end
21
+
22
+ def count() @tiles.size; end
23
+ alias_method :size, :count
24
+ alias_method :tile_count, :count ## add tile_count - why? why not?
25
+ def tile_width() @tile_width; end ## use width - why? why not?
26
+ def tile_height() @tile_height; end ## use height - why? why not?
27
+
28
+ def tile( index ) @tiles[ index ]; end
29
+ alias_method :[], :tile
30
+
31
+ def add_inscribe( inscribe ) _add( Pixelart::Image.blob( inscribe.content )); end
32
+ def add( img )
33
+ ## 1:1 tile; use as is
34
+ if img.width == @tile_width && img.height == @tile_height
35
+ @tiles << img
36
+ else ## assume spritesheet??
37
+ ## wrap into composite image
38
+ composite = Pixelart::ImageComposite.new( img.image, width: @tile_width,
39
+ height: @tile_height )
40
+ cols = img.width / composite.tile_width
41
+ rows = img.height / composite.tile_height
42
+ puts " #{composite.count} tile(s) in #{cols}x#{rows} grid"
43
+ composite.each {|tile| @tiles << tile }
44
+ end
45
+ end
46
+ alias_method :<<, :add
47
+ end ## class Spritesheet
48
+
49
+
50
+ class FactoryGenerator
51
+ ###################
52
+ ## convenience setup helper(s)
53
+ def self.read_inscribes( *inscribes, width:,
54
+ height: )
55
+ new( FactorySpritesheet.read_inscribes( *inscribes,
56
+ width: width,
57
+ height: height ))
58
+ end
59
+
60
+ def initialize( spritesheet )
61
+ @spritesheet = spritesheet
62
+ end
63
+
64
+ def _parse( spec )
65
+ ## for delimiter allow for now: - why? why not?
66
+ ## (multiple) space ( )
67
+ ## command or semicolon
68
+ spec.strip.split( %r{[ ,;/_-]+} ).map {|v| v.to_i(10) }
69
+ end
70
+
71
+ def parse( spec )
72
+ ## convenience helper
73
+ ## parses g spec in various (delimited) formats
74
+ g = _parse( spec )
75
+ generate( *g )
76
+ end
77
+
78
+ def generate( *attributes )
79
+ img = Pixelart::Image.new( width, height )
80
+ attributes.each do |num|
81
+ img.compose!( @spritesheet[ num ] )
82
+ end
83
+ img
84
+ end
85
+ alias_method :g, :generate
86
+
87
+ def width() @spritesheet.tile_width; end
88
+ def height() @spritesheet.tile_height; end
89
+ def count() @spritesheet.count; end
90
+ end # class FactoryGenerator
91
+
92
+
93
+
94
+ module OrdDb
95
+ module Model
96
+
97
+ class Factory
98
+
99
+ ## use id/slug to cache generators / spritesheets - why? why not?
100
+ def self.generators
101
+ @generators ||= {}
102
+ end
103
+
104
+ def generator
105
+ generators = self.class.generators
106
+ if generators.has_key?( id )
107
+ generators[ id ]
108
+ else
109
+ ## auto-add generator on first-time/hit/demand
110
+ width, height = _parse_dimension( dim )
111
+ inscribes = layers.to_a ## get layer inscribe records
112
+ generator = FactoryGenerator.read_inscribes( *inscribes,
113
+ width: width,
114
+ height: height )
115
+ generators[ id ] = generator
116
+ generator
117
+ end
118
+ end
119
+
120
+ def generate( *attributes ) ## add g shortcut alias - why? why not?
121
+ generator.generate( *attributes )
122
+ end
123
+
124
+
125
+ ## e.g. convert dimension (width x height) "24x24" or "24 x 24" to [24,24]
126
+ def _parse_dimension( str )
127
+ str.split( /x/i ).map { |str| str.strip.to_i(10) }
128
+ end
129
+
130
+ end # class Factory
131
+ end # module Model
132
+ end # module OrdDb
@@ -1,8 +1,82 @@
1
+ module OrdDb
1
2
 
3
+ class Importer
4
+ Inscribe = Model::Inscribe
5
+ Blob = Model::Blob
6
+ Collection = Model::Collection
2
7
 
3
- module OrdDb
4
8
 
5
- def self.import_collection( path, content: true )
9
+
10
+ def import_collection_csv( path,
11
+ name:,
12
+ content: true )
13
+ ## or use
14
+ ## import_collection( format: 'csv') - why? why not?
15
+ recs = read_csv( path )
16
+ puts " #{recs.size} inscribe id(s)"
17
+
18
+ col = Collection.find_by( name: name )
19
+ if col && col.items.count > 0
20
+ puts "!! WARN - collection already in db; delete first to reimport"
21
+ return
22
+ elsif col
23
+ ## do nothing; (re)use collection record; add items
24
+ else
25
+ col = Collection.create(
26
+ name: name
27
+ ## max: recs.size ## auto-add max - why? why not?
28
+ )
29
+ end
30
+
31
+ recs.each_with_index do |rec,i|
32
+ id = rec['id']
33
+ name = rec['name'] || rec['title']
34
+ puts "==> #{i+1}/#{recs.size} >#{name}< @ #{id}..."
35
+
36
+ col.items.create( pos: i,
37
+ inscribe_id: id,
38
+ name: name )
39
+
40
+ _import( id, content: content )
41
+ end
42
+ end
43
+
44
+
45
+ def import_collection_inscriptions( path,
46
+ name:,
47
+ content: true )
48
+ recs = read_json( path )
49
+ puts " #{recs.size} inscribe id(s)"
50
+
51
+ col = Collection.find_by( name: name )
52
+ if col && col.items.count > 0
53
+ puts "!! WARN - collection already in db; delete first to reimport"
54
+ return
55
+ elsif col
56
+ ## do nothing; (re)use collection record; add items
57
+ else
58
+ col = Model::Collection.create(
59
+ name: name
60
+ ## max: recs.size ## auto-add max - why? why not?
61
+ )
62
+ end
63
+
64
+ recs.each_with_index do |rec,i|
65
+ id = rec['id']
66
+ meta = rec['meta']
67
+ name = meta['name']
68
+ puts "==> #{i+1}/#{recs.size} >#{name}< @ #{id}..."
69
+
70
+ col.items.create( pos: i,
71
+ inscribe_id: id,
72
+ name: name )
73
+
74
+ _import( id, content: content )
75
+ end
76
+ end
77
+
78
+
79
+ def import_collection( path, content: true )
6
80
  data = read_json( path )
7
81
 
8
82
  meta = data['collection']
@@ -10,13 +84,13 @@ def self.import_collection( path, content: true )
10
84
 
11
85
  name = meta['name']
12
86
 
13
- col = Model::Collection.find_by( name: name )
87
+ col = Collection.find_by( name: name )
14
88
  if col
15
89
  puts "!! WARN - collection already in db; delete first to reimport"
16
90
  return
17
91
  end
18
92
 
19
- col = Model::Collection.create(
93
+ col = Collection.create(
20
94
  name: name,
21
95
  desc: meta['description'],
22
96
  max: meta['max_supply']
@@ -33,35 +107,12 @@ def self.import_collection( path, content: true )
33
107
  inscribe_id: id,
34
108
  name: name )
35
109
 
36
- ## check if inscription / inscribe is already in db?
37
- inscribe = Model::Inscribe.find_by( id: id )
38
- if inscribe ## already in db; dump record
39
- ## pp inscribe
40
- else ## fetch via ordinals.com api and update db
41
- data = Ordinals.inscription( id )
42
- pp data
43
- Model::Inscribe.create_from_api( data )
44
- sleep( 1 ) ## delay in seconds (before next request)
45
- end
46
-
47
- if content
48
- ## check if (content) blob is already in db?
49
- blob = Model::Blob.find_by( id: id )
50
- if blob ## already in db; do nothing
51
- else ## fetch via ordinals.com api and update db
52
- content = Ordinals.content( id )
53
- puts " content-type: #{content.type}"
54
- puts " content-length: #{content.length}"
55
-
56
- Model::Blob.create( id: id, content: content.data )
57
- sleep( 1 ) ## delay in seconds (before next request)
58
- end
59
- end
110
+ _import( id, content: content )
60
111
  end
61
112
  end
62
113
 
63
114
 
64
- def self.import_csv( path, content: true )
115
+ def import_csv( path, content: true )
65
116
  recs = read_csv( path )
66
117
  puts " #{recs.size} inscribe id(s)"
67
118
  #=> 1000 inscribe id(s)
@@ -70,30 +121,98 @@ def self.import_csv( path, content: true )
70
121
  id = rec['id']
71
122
  puts "==> #{i+1}/#{rec.size} @ #{id}..."
72
123
 
73
- ## check if inscription / inscribe is already in db?
74
- inscribe = Model::Inscribe.find_by( id: id )
75
- if inscribe ## already in db; dump record
76
- ## pp inscribe
77
- else ## fetch via ordinals.com api and update db
78
- data = Ordinals.inscription( id )
79
- pp data
80
- Model::Inscribe.create_from_api( data )
81
- sleep( 1 ) ## delay in seconds (before next request)
82
- end
124
+ _import( id, content: content )
125
+ end
126
+ end # method import_csv
83
127
 
84
- if content
85
- ## check if (content) blob is already in db?
86
- blob = Model::Blob.find_by( id: id )
87
- if blob ## already in db; do nothing
88
- else ## fetch via ordinals.com api and update db
89
- content = Ordinals.content( id )
90
- puts " content-type: #{content.type}"
91
- puts " content-length: #{content.length}"
92
-
93
- Model::Blob.create( id: id, content: content.data )
94
- sleep( 1 ) ## delay in seconds (before next request)
95
- end
128
+ def import( id_or_ids, content: true )
129
+ if id_or_ids.is_a?( String )
130
+ id = id_or_ids
131
+ _import( id, content: content )
132
+ else ## assume array
133
+ ids = id_or_ids
134
+ ids.each do |id|
135
+ _import( id, content: content )
96
136
  end
97
- end
98
- end # method self.import_csv
137
+ end
138
+ end
139
+
140
+ def _import( id, content: true )
141
+ ## check if inscription / inscribe is already in db?
142
+ inscribe = Inscribe.find_by( id: id )
143
+ if inscribe ## already in db; dump record
144
+ ## pp inscribe
145
+ else ## fetch via ordinals.com api and update db
146
+ data = Ordinals.inscription( id )
147
+
148
+ pp data
149
+ Inscribe.create_from_api( data )
150
+ end
151
+
152
+ if content
153
+ ## check if (content) blob is already in db?
154
+ blob = Blob.find_by( id: id )
155
+ if blob ## already in db; do nothing
156
+ else ## fetch via ordinals.com api and update db
157
+ content = Ordinals.content( id )
158
+
159
+ puts " content-type: #{content.type}"
160
+ puts " content-length: #{content.length}"
161
+
162
+ Blob.create( id: id, content: content.data )
163
+ end
164
+ end
165
+ end
166
+
167
+ end # class Importer
168
+
169
+
170
+
171
+ ###
172
+ ## convenience helpers
173
+
174
+ def self.importer ## "default" importer
175
+ @importer ||= Importer.new
176
+ end
177
+
178
+ def self.import( id_or_ids, content: true )
179
+ importer.import( id_or_ids, content: content )
180
+ end
181
+
182
+
183
+ def self.import_csv( path, content: true )
184
+ importer.import_csv( path, content: content )
185
+ end
186
+
187
+
188
+ def self.import_collection( path, content: true )
189
+ importer.import_collection( path, content: content )
190
+ end
191
+
192
+ def self.import_collection_inscriptions( path,
193
+ name:,
194
+ content: true )
195
+ importer.import_collection_inscriptions( path,
196
+ name: name,
197
+ content: content )
198
+ end
199
+
200
+ def self.import_collection_csv( path,
201
+ name:,
202
+ content: true )
203
+ importer.import_collection_csv( path,
204
+ name: name,
205
+ content: content )
206
+ end
207
+
208
+
209
+ module Model
210
+ class Inscribe
211
+ def self.import( id_or_ids, content: true )
212
+ OrdDb.importer.import( id_or_ids, content: content )
213
+ end
214
+ end # class Inscribe
215
+ end # module Model
216
+
217
+
99
218
  end # module OrdDb
@@ -2,7 +2,11 @@ module OrdDb
2
2
  module Model
3
3
 
4
4
  class Collection < ActiveRecord::Base
5
- has_many :items, -> { order('pos') }
5
+ has_many :items
6
+ ## -> { order('pos') }
7
+ ## note: default_scope (order)
8
+ ## will break all count queries and more
9
+ ## thus - no "magic" - always sort if pos order required!!!
6
10
  has_many :inscribes, :through => :items
7
11
  end # class Collection
8
12
 
@@ -7,7 +7,12 @@ module OrdDb
7
7
 
8
8
  belongs_to :inscribe
9
9
 
10
- has_many :inscriberefs, -> { order('pos') } ## join table (use habtm - why? why not?)
10
+ has_many :inscriberefs ## join table (use habtm - why? why not?)
11
+ ## -> { order('pos') }
12
+ ## note: default_scope (order)
13
+ ## will break all count queries and more
14
+ ## thus - no "magic" - always sort if pos order required!!!
15
+
11
16
  has_many :layers, :through => :inscriberefs,
12
17
  :source => :inscribe
13
18
 
@@ -66,29 +66,40 @@ SQL
66
66
  def self.sub20k() where( 'num < 20000' ); end
67
67
  def self.sub100k() where( 'num < 100000' ); end
68
68
  def self.sub1m() where( 'num < 1000000' ); end
69
+ def self.sub2m() where( 'num < 2000000' ); end
70
+ def self.sub10m() where( 'num < 10000000' ); end
71
+ def self.sub20m() where( 'num < 20000000' ); end
72
+ def self.sub21m() where( 'num < 21000000' ); end
69
73
 
70
74
 
71
75
  def self.largest
72
76
  order( 'bytes DESC' )
73
77
  end
74
78
 
79
+ def self.address_counts
80
+ group( 'address' )
81
+ .order( Arel.sql( 'COUNT(*) DESC')).count
82
+ end
83
+
75
84
  def self.block_counts
76
- group( 'block' ).count
85
+ group( 'block' )
86
+ .order( 'block').count
77
87
  end
78
88
 
79
89
  def self.block_with_timestamp_counts
80
- group( Arel.sql( "block || ' @ ' || date" )).count
90
+ group( Arel.sql( "block || ' @ ' || date" ))
91
+ .order( Arel.sql( "block || ' @ ' || date" ) ).count
81
92
  end
82
93
 
83
94
  def self.content_type_counts
84
- group( 'content_type' )
95
+ group( 'content_type' )
85
96
  .order( Arel.sql( 'COUNT(*) DESC, content_type')).count
86
97
  end
87
98
 
88
99
 
89
100
  def self.date_counts
90
101
  ## note: strftime is SQLite specific/only!!!
91
- group( Arel.sql("strftime('%Y-%m-%d', date)"))
102
+ group( Arel.sql("strftime('%Y-%m-%d', date)"))
92
103
  .order( Arel.sql("strftime('%Y-%m-%d', date)")).count
93
104
  end
94
105
 
@@ -100,13 +111,14 @@ SQL
100
111
 
101
112
  def self.hour_counts
102
113
  ## note: strftime is SQLite specific/only!!!
103
- group( Arel.sql("strftime('%Y-%m-%d %Hh', date)"))
114
+ group( Arel.sql("strftime('%Y-%m-%d %Hh', date)"))
104
115
  .order( Arel.sql("strftime('%Y-%m-%d %Hh', date)")).count
105
116
  end
106
117
 
107
118
 
108
119
  class << self
109
120
  alias_method :biggest, :largest
121
+ alias_method :counts_by_address, :address_counts
110
122
  alias_method :counts_by_content_type, :content_type_counts
111
123
  alias_method :counts_by_date, :date_counts
112
124
  alias_method :counts_by_day, :date_counts
@@ -4,7 +4,7 @@ module Ordlite
4
4
  # sync version w/ sport.db n friends - why? why not?
5
5
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
6
6
  MINOR = 2
7
- PATCH = 0
7
+ PATCH = 1
8
8
  VERSION = [MAJOR,MINOR,PATCH].join('.')
9
9
 
10
10
  def self.version
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ordlite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-28 00:00:00.000000000 Z
11
+ date: 2023-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ordinals
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pixelart
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: rdoc
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -173,6 +187,7 @@ files:
173
187
  - lib/ordlite.rb
174
188
  - lib/ordlite/base.rb
175
189
  - lib/ordlite/cache.rb
190
+ - lib/ordlite/factory.rb
176
191
  - lib/ordlite/importer.rb
177
192
  - lib/ordlite/models/blob.rb
178
193
  - lib/ordlite/models/collection.rb