ordlite 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -1
- data/Manifest.txt +4 -0
- data/README.md +159 -7
- data/Rakefile +2 -1
- data/lib/ordlite/base.rb +37 -5
- data/lib/ordlite/cache.rb +46 -105
- data/lib/ordlite/importer.rb +99 -0
- data/lib/ordlite/models/blob.rb +4 -0
- data/lib/ordlite/models/collection.rb +10 -0
- data/lib/ordlite/models/factory.rb +20 -0
- data/lib/ordlite/models/forward.rb +22 -3
- data/lib/ordlite/models/generative.rb +12 -0
- data/lib/ordlite/models/inscribe.rb +265 -0
- data/lib/ordlite/schema.rb +105 -2
- data/lib/ordlite/version.rb +2 -2
- data/lib/ordlite.rb +12 -2
- metadata +21 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6051393488775c98fdee4716e6c49b5cd89c6cd404a45f48024a47dea633acfb
|
|
4
|
+
data.tar.gz: d43e1d73f1b49b27ae35e745eaa8e13be394635d2367233bc6c341fd1aa54933
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 05e95871ce3a85dd31557e38a4247d5cd38e25406e2ac535a1254e6952e68b8054e8c1a06378b4620ce8168c67d1e4cb7eac50305da9e7e59e2f10152a4aa971
|
|
7
|
+
data.tar.gz: 3fe7780c583d525dd60170f4ec0e996f430722d53899e3edb321d9af67425024c262a253e1cf718ab0b7316f9fbb3ae0a6903b3a82debf3860511a167872a1ab
|
data/CHANGELOG.md
CHANGED
data/Manifest.txt
CHANGED
|
@@ -5,8 +5,12 @@ Rakefile
|
|
|
5
5
|
lib/ordlite.rb
|
|
6
6
|
lib/ordlite/base.rb
|
|
7
7
|
lib/ordlite/cache.rb
|
|
8
|
+
lib/ordlite/importer.rb
|
|
8
9
|
lib/ordlite/models/blob.rb
|
|
10
|
+
lib/ordlite/models/collection.rb
|
|
11
|
+
lib/ordlite/models/factory.rb
|
|
9
12
|
lib/ordlite/models/forward.rb
|
|
13
|
+
lib/ordlite/models/generative.rb
|
|
10
14
|
lib/ordlite/models/inscribe.rb
|
|
11
15
|
lib/ordlite/schema.rb
|
|
12
16
|
lib/ordlite/version.rb
|
data/README.md
CHANGED
|
@@ -4,21 +4,170 @@
|
|
|
4
4
|
ordlite - ordinals inscription (on bitcoin & co) database let's you query via sql and more
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
* home :: [github.com/ordbase/
|
|
8
|
-
* bugs :: [github.com/ordbase/
|
|
7
|
+
* home :: [github.com/ordbase/ordbase](https://github.com/ordbase/ordbase)
|
|
8
|
+
* bugs :: [github.com/ordbase/ordbase/issues](https://github.com/ordbase/ordbase/issues)
|
|
9
9
|
* gem :: [rubygems.org/gems/ordlite](https://rubygems.org/gems/ordlite)
|
|
10
10
|
* rdoc :: [rubydoc.info/gems/ordlite](http://rubydoc.info/gems/ordlite)
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
## SQL Database Model
|
|
15
|
+
|
|
16
|
+
Inscribes • Blobs • Collections • Generatives
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
Table Inscribes
|
|
20
|
+
|
|
21
|
+
``` sql
|
|
22
|
+
CREATE TABLE "inscribes" (
|
|
23
|
+
"id" varchar NOT NULL PRIMARY KEY,
|
|
24
|
+
"num" integer NOT NULL,
|
|
25
|
+
"bytes" integer NOT NULL,
|
|
26
|
+
"content_type" varchar NOT NULL,
|
|
27
|
+
"date" datetime(6) NOT NULL,
|
|
28
|
+
"sat" integer NOT NULL,
|
|
29
|
+
"block" integer NOT NULL,
|
|
30
|
+
"fee" integer NOT NULL,
|
|
31
|
+
"tx" varchar NOT NULL,
|
|
32
|
+
"offset" integer NOT NULL,
|
|
33
|
+
"address" varchar NOT NULL,
|
|
34
|
+
"output" varchar NOT NULL,
|
|
35
|
+
"value" integer NOT NULL,
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Table Blobs
|
|
40
|
+
|
|
41
|
+
``` sql
|
|
42
|
+
CREATE TABLE "blobs" (
|
|
43
|
+
"id" varchar NOT NULL PRIMARY KEY,
|
|
44
|
+
"content" blob NOT NULL,
|
|
45
|
+
)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
|
|
14
49
|
## Usage
|
|
15
50
|
|
|
16
|
-
|
|
51
|
+
|
|
52
|
+
### Step 0: Setup Databae
|
|
53
|
+
|
|
54
|
+
``` ruby
|
|
55
|
+
require 'ordlite'
|
|
56
|
+
|
|
57
|
+
OrdDb.connect( adapter: 'sqlite3',
|
|
58
|
+
database: './ord.db' )
|
|
59
|
+
|
|
60
|
+
OrdDb.create_all # build table schema
|
|
61
|
+
|
|
62
|
+
puts
|
|
63
|
+
puts " #{Inscribe.count} inscribe(s)"
|
|
64
|
+
puts " #{Blob.count} blob(s)"
|
|
65
|
+
puts " #{Collection.count} collection(s)"
|
|
66
|
+
puts " #{Generative.count} generative(s)"
|
|
67
|
+
|
|
68
|
+
#=> 0 inscribe(s)
|
|
69
|
+
#=> 0 blob(s)
|
|
70
|
+
#=> 0 collection(s)
|
|
71
|
+
#=> 0 generative(s)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
### Example No 1 - Query Ordgen Deploy / Mint Inscriptions
|
|
78
|
+
|
|
79
|
+
``` ruby
|
|
80
|
+
require 'ordlite'
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
OrdDb.connect( adapter: 'sqlite3',
|
|
84
|
+
database: './ord.db' )
|
|
85
|
+
|
|
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
|
+
##
|
|
95
|
+
|
|
96
|
+
deploys = Inscribe.deploys
|
|
97
|
+
puts " #{deploys.size} deploy candidate(s)"
|
|
98
|
+
|
|
99
|
+
deploys.each_with_index do |rec,i|
|
|
100
|
+
puts "==> deploy #{i} - num #{rec.num} - #{rec.bytes} bytes - #{rec.date}"
|
|
101
|
+
puts rec.content
|
|
102
|
+
end
|
|
17
103
|
|
|
18
104
|
|
|
105
|
+
punks_deploys = Inscribe.deploys_by( slug: 'diypunks')
|
|
106
|
+
puts " #{punks_deploys.size} deploy candidate(s)"
|
|
19
107
|
|
|
20
108
|
|
|
21
109
|
|
|
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%')
|
|
117
|
+
|
|
118
|
+
mints = Inscribe.mints
|
|
119
|
+
puts " #{mints.size} mint candidate(s)"
|
|
120
|
+
|
|
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
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
phunks_mints = Inscribe.mints_by( slug: 'diyphunks')
|
|
129
|
+
puts " #{phunks_mints.size} mint candidate(s)"
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
puts " #{deploys.size} deploy candidate(s)"
|
|
133
|
+
puts " #{mints.size} mint candidate(s)"
|
|
134
|
+
|
|
135
|
+
#=> 123 deploy candidate(s)
|
|
136
|
+
#=> 7453 mint candidate(s)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
### Bonus: Import (Cached) Inscription Meta Datafiles (& Content Blobs)
|
|
143
|
+
|
|
144
|
+
Let's import all cached
|
|
145
|
+
inscriptions metadata datafiles (& content blobs)
|
|
146
|
+
from [/ordinals.cache](https://github.com/ordbase/ordinals.cache)
|
|
147
|
+
into an (sql) database e.g. `ord.db`:
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
``` ruby
|
|
151
|
+
require 'ordlite'
|
|
152
|
+
|
|
153
|
+
OrdDb.connect( adapter: 'sqlite3',
|
|
154
|
+
database: './ord.db' )
|
|
155
|
+
|
|
156
|
+
OrdDb.create_all # build table schema
|
|
157
|
+
|
|
158
|
+
cache_dir = './ordinals.cache/inscription'
|
|
159
|
+
cache = OrdDb::Cache.new( cache_dir )
|
|
160
|
+
cache.import_all
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
puts
|
|
164
|
+
puts " #{Inscribe.count} inscribe(s)"
|
|
165
|
+
puts " #{Blob.count} blob(s)"
|
|
166
|
+
|
|
167
|
+
#=> 8505 inscribe(s)
|
|
168
|
+
#=> 7611 blob(s)
|
|
169
|
+
```
|
|
170
|
+
|
|
22
171
|
|
|
23
172
|
## License
|
|
24
173
|
|
|
@@ -26,9 +175,12 @@ The scripts are dedicated to the public domain.
|
|
|
26
175
|
Use it as you please with no restrictions whatsoever.
|
|
27
176
|
|
|
28
177
|
|
|
178
|
+
## Questions? Comments?
|
|
179
|
+
|
|
180
|
+
Join us in the [Ordgen / ORC-721 discord (chat server)](https://discord.gg/dDhvHKjm2t). Yes you can.
|
|
181
|
+
Your questions and commetary welcome.
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
Or post them over at the [Help & Support](https://github.com/geraldb/help) page. Thanks.
|
|
29
185
|
|
|
30
|
-
Please post in the #generative-orc-721 channel
|
|
31
|
-
in the ordinal punks discord.
|
|
32
|
-
For an invite
|
|
33
|
-
see <https://twitter.com/OrdinalPunks/status/1620230583711576068>.
|
|
34
186
|
|
data/Rakefile
CHANGED
|
@@ -9,7 +9,7 @@ Hoe.spec 'ordlite' do
|
|
|
9
9
|
self.summary = "ordlite - ordinals inscription (on bitcoin & co) database let's you query via sql and more"
|
|
10
10
|
self.description = summary
|
|
11
11
|
|
|
12
|
-
self.urls = { home: 'https://github.com/ordbase/
|
|
12
|
+
self.urls = { home: 'https://github.com/ordbase/ordbase' }
|
|
13
13
|
|
|
14
14
|
self.author = 'Gerald Bauer'
|
|
15
15
|
self.email = 'gerald.bauer@gmail.com'
|
|
@@ -19,6 +19,7 @@ Hoe.spec 'ordlite' do
|
|
|
19
19
|
self.history_file = 'CHANGELOG.md'
|
|
20
20
|
|
|
21
21
|
self.extra_deps = [
|
|
22
|
+
['ordinals'],
|
|
22
23
|
['activerecord'],
|
|
23
24
|
['activerecord-utils'],
|
|
24
25
|
['logutils'],
|
data/lib/ordlite/base.rb
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
# core and stlibs
|
|
2
|
+
require 'ordinals' ## will pull-in cocos & friends
|
|
2
3
|
|
|
3
|
-
require 'pp'
|
|
4
|
-
require 'fileutils'
|
|
5
|
-
require 'uri'
|
|
6
|
-
require 'json'
|
|
7
|
-
require 'yaml'
|
|
8
4
|
|
|
9
5
|
require 'logger' # Note: use for ActiveRecord::Base.logger -- remove/replace later w/ LogUtils::Logger ???
|
|
10
6
|
|
|
@@ -31,6 +27,9 @@ require_relative 'models/forward'
|
|
|
31
27
|
|
|
32
28
|
require_relative 'models/inscribe'
|
|
33
29
|
require_relative 'models/blob'
|
|
30
|
+
require_relative 'models/collection'
|
|
31
|
+
require_relative 'models/factory'
|
|
32
|
+
require_relative 'models/generative'
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
require_relative 'schema'
|
|
@@ -38,6 +37,10 @@ require_relative 'schema'
|
|
|
38
37
|
require_relative 'cache'
|
|
39
38
|
|
|
40
39
|
|
|
40
|
+
require_relative 'importer' ## note: require (soft dep) ordinals gems!!!
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
41
44
|
|
|
42
45
|
module OrdDb
|
|
43
46
|
|
|
@@ -53,6 +56,35 @@ module OrdDb
|
|
|
53
56
|
OrdDb.create
|
|
54
57
|
end
|
|
55
58
|
|
|
59
|
+
def self.auto_migrate!
|
|
60
|
+
### todo/fix:
|
|
61
|
+
## check props table and versions!!!!!
|
|
62
|
+
|
|
63
|
+
# first time? - auto-run db migratation, that is, create db tables
|
|
64
|
+
unless LogDb::Model::Log.table_exists?
|
|
65
|
+
LogDb.create # add logs table
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
unless ConfDb::Model::Prop.table_exists?
|
|
69
|
+
ConfDb.create # add props table
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
unless OrdDb::Model::Inscribe.table_exists?
|
|
73
|
+
OrdDb.create
|
|
74
|
+
end
|
|
75
|
+
end # method auto_migrate!
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def self.open( database='./ord.db' ) ## convenience helper for sqlite only
|
|
79
|
+
connect( adapter: 'sqlite3',
|
|
80
|
+
database: database )
|
|
81
|
+
|
|
82
|
+
## build schema if database new/empty
|
|
83
|
+
auto_migrate!
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
56
88
|
def self.connect( config={} )
|
|
57
89
|
|
|
58
90
|
if config.empty?
|
data/lib/ordlite/cache.rb
CHANGED
|
@@ -1,123 +1,64 @@
|
|
|
1
|
+
###
|
|
2
|
+
## add (database) import machinery to cache
|
|
1
3
|
|
|
2
|
-
module
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Inscribe = Model::Inscribe
|
|
8
|
-
Blob = Model::Blob
|
|
9
|
-
|
|
10
|
-
def initialize( dir='.' )
|
|
11
|
-
@dir = dir
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def import_all
|
|
17
|
-
paths = Dir.glob( "#{@dir}/**.json" )
|
|
18
|
-
puts " #{paths.size} inscribe datafile(s) found"
|
|
4
|
+
module Ordinals
|
|
5
|
+
class Cache
|
|
6
|
+
Inscribe = OrdDb::Model::Inscribe
|
|
7
|
+
Blob = OrdDb::Model::Blob
|
|
19
8
|
|
|
9
|
+
def import_all
|
|
10
|
+
paths = _find_meta
|
|
11
|
+
puts " #{paths.size} inscribe metaddatafile(s) found"
|
|
20
12
|
paths.each_with_index do |path, i|
|
|
21
|
-
puts "==> inscribe #{i+1}/#{paths.size}..."
|
|
13
|
+
## puts "==> inscribe #{i+1}/#{paths.size}..."
|
|
22
14
|
data = _read_inscribe( path )
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
id = data['id']
|
|
16
|
+
|
|
17
|
+
## skip if exists (use update later - why? why not?)
|
|
18
|
+
rec = Inscribe.find_by( id: id )
|
|
19
|
+
if rec
|
|
20
|
+
## skip - already in db
|
|
21
|
+
print '.'
|
|
22
|
+
else
|
|
23
|
+
print " #{id}" # NEW - add / insert into db"
|
|
24
|
+
rec = Inscribe.create_from_cache( data )
|
|
25
|
+
end
|
|
25
26
|
end
|
|
27
|
+
puts
|
|
26
28
|
|
|
27
29
|
|
|
28
|
-
paths =
|
|
29
|
-
puts " #{paths.size}
|
|
30
|
-
|
|
30
|
+
paths = _find_blobs
|
|
31
|
+
puts " #{paths.size} inscribe blob(s) found"
|
|
31
32
|
paths.each_with_index do |path, i|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
## puts "==> blob #{i+1}/#{paths.size}..."
|
|
34
|
+
content = read_blob( path )
|
|
35
|
+
id = File.basename( File.dirname(path)) +
|
|
36
|
+
File.basename( path, File.extname( path ))
|
|
37
|
+
|
|
38
|
+
rec = Blob.find_by( id: id )
|
|
39
|
+
if rec
|
|
40
|
+
## skip - already in db
|
|
41
|
+
print '.'
|
|
42
|
+
else
|
|
43
|
+
print " #{id}" # NEW - add / insert into db"
|
|
44
|
+
rec = Blob.create( id: id,
|
|
45
|
+
content: content )
|
|
46
|
+
end
|
|
38
47
|
end
|
|
48
|
+
puts
|
|
39
49
|
end
|
|
40
50
|
|
|
41
|
-
|
|
42
51
|
def import( id )
|
|
43
|
-
data = read( id )
|
|
44
|
-
rec = Inscribe.
|
|
45
|
-
rec
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def read( id )
|
|
49
|
-
_read_inscribe( "#{@dir}/#{id}.json" )
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def _read_inscribe( path )
|
|
53
|
-
JSON.parse( _read_text( path ))
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def _read_blob( path )
|
|
57
|
-
blob = File.open( path, 'rb' ) { |f| f.read }
|
|
58
|
-
## auto force to ASCII-7BIT if not already - why? why not?
|
|
59
|
-
blob
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def _read_text( path )
|
|
64
|
-
File.open( path, 'r:utf-8' ){ |f| f.read }
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def _parse_inscribe( data )
|
|
68
|
-
## num via title
|
|
69
|
-
attributes = {
|
|
70
|
-
id: data['id'],
|
|
71
|
-
num: _title_to_num( data['title'] ),
|
|
72
|
-
bytes: _content_length_to_bytes( data['content length'] ),
|
|
73
|
-
sat: data['sat'].to_i(10),
|
|
74
|
-
content_type: data['content type'],
|
|
75
|
-
block: data['genesis height'].to_i(10),
|
|
76
|
-
fee: data['genesis fee'].to_i(10),
|
|
77
|
-
tx: data['genesis transaction'],
|
|
78
|
-
address: data['address'],
|
|
79
|
-
output: data['output'],
|
|
80
|
-
value: data['output value'].to_i(10),
|
|
81
|
-
offset: data['offset'].to_i(10),
|
|
82
|
-
# "2023-06-01 05:00:57 UTC"
|
|
83
|
-
date: DateTime.strptime( data['timestamp'],
|
|
84
|
-
'%Y-%m-%d %H:%M:%S %z')
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
attributes
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
## "title": "Inscription 9992615",
|
|
93
|
-
TITLE_RX = /^Inscription (?<num>[0-9]+)$/i
|
|
94
|
-
|
|
95
|
-
def _title_to_num( str )
|
|
96
|
-
if m=TITLE_RX.match( str )
|
|
97
|
-
m[:num].to_i(10) ## use base 10
|
|
52
|
+
data = read( id )
|
|
53
|
+
rec = Inscribe.find_by( id: id )
|
|
54
|
+
if rec
|
|
55
|
+
# skip - already in db
|
|
98
56
|
else
|
|
99
|
-
|
|
100
|
-
exit 1 ## not found - raise exception - why? why not?
|
|
57
|
+
rec = Inscribe.create_from_cache( data )
|
|
101
58
|
end
|
|
102
59
|
end
|
|
103
60
|
|
|
104
|
-
CONTENT_LENGTH_RX = /^(?<num>[0-9]+) bytes$/i
|
|
105
|
-
|
|
106
|
-
def _content_length_to_bytes( str )
|
|
107
|
-
if m=CONTENT_LENGTH_RX.match( str )
|
|
108
|
-
m[:num].to_i(10) ## use base 10
|
|
109
|
-
else
|
|
110
|
-
puts "!! ERROR - bytes found in content lenght >#{str}<"
|
|
111
|
-
exit 1 ## not found - raise exception - why? why not?
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
end # class Cache
|
|
119
|
-
end # module OrdDb
|
|
120
|
-
|
|
121
|
-
|
|
122
61
|
|
|
62
|
+
end # class Cache
|
|
63
|
+
end # module Ordinals
|
|
123
64
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
module OrdDb
|
|
4
|
+
|
|
5
|
+
def self.import_collection( path, content: true )
|
|
6
|
+
data = read_json( path )
|
|
7
|
+
|
|
8
|
+
meta = data['collection']
|
|
9
|
+
pp meta
|
|
10
|
+
|
|
11
|
+
name = meta['name']
|
|
12
|
+
|
|
13
|
+
col = Model::Collection.find_by( name: name )
|
|
14
|
+
if col
|
|
15
|
+
puts "!! WARN - collection already in db; delete first to reimport"
|
|
16
|
+
return
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
col = Model::Collection.create(
|
|
20
|
+
name: name,
|
|
21
|
+
desc: meta['description'],
|
|
22
|
+
max: meta['max_supply']
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
items = data['items']
|
|
26
|
+
puts " #{items.size} inscribe id(s)"
|
|
27
|
+
items.each_with_index do |rec,i|
|
|
28
|
+
id = rec['inscription_id']
|
|
29
|
+
name = rec['name']
|
|
30
|
+
puts "==> #{i+1}/#{items.size} @ #{id}..."
|
|
31
|
+
|
|
32
|
+
col.items.create( pos: i,
|
|
33
|
+
inscribe_id: id,
|
|
34
|
+
name: name )
|
|
35
|
+
|
|
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
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def self.import_csv( path, content: true )
|
|
65
|
+
recs = read_csv( path )
|
|
66
|
+
puts " #{recs.size} inscribe id(s)"
|
|
67
|
+
#=> 1000 inscribe id(s)
|
|
68
|
+
|
|
69
|
+
recs.each_with_index do |rec,i|
|
|
70
|
+
id = rec['id']
|
|
71
|
+
puts "==> #{i+1}/#{rec.size} @ #{id}..."
|
|
72
|
+
|
|
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
|
|
83
|
+
|
|
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
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end # method self.import_csv
|
|
99
|
+
end # module OrdDb
|
data/lib/ordlite/models/blob.rb
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
module OrdDb
|
|
3
|
+
module Model
|
|
4
|
+
|
|
5
|
+
class Factory < ActiveRecord::Base
|
|
6
|
+
self.table_name = 'factories' ## non-standard plural (factory/factories)
|
|
7
|
+
|
|
8
|
+
belongs_to :inscribe
|
|
9
|
+
|
|
10
|
+
has_many :inscriberefs, -> { order('pos') } ## join table (use habtm - why? why not?)
|
|
11
|
+
has_many :layers, :through => :inscriberefs,
|
|
12
|
+
:source => :inscribe
|
|
13
|
+
|
|
14
|
+
has_many :generatives
|
|
15
|
+
has_many :inscribes, :through => :generatives
|
|
16
|
+
end # class Factory
|
|
17
|
+
|
|
18
|
+
end # module Model
|
|
19
|
+
end # module OrdDb
|
|
20
|
+
|
|
@@ -12,12 +12,31 @@ Prop = ConfDb::Model::Prop
|
|
|
12
12
|
|
|
13
13
|
class Inscribe < ActiveRecord::Base ; end
|
|
14
14
|
class Blob < ActiveRecord::Base ; end
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
class Collection < ActiveRecord::Base ; end
|
|
16
|
+
class Item < ActiveRecord::Base ## change to CollectionItem - why? why not?
|
|
17
|
+
belongs_to :collection
|
|
18
|
+
belongs_to :inscribe
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Factory < ActiveRecord::Base ; end
|
|
22
|
+
class Generative < ActiveRecord::Base ; end
|
|
23
|
+
|
|
24
|
+
### join tables - add inline here - why? why not?
|
|
25
|
+
## rename to CollectionLayer? or
|
|
26
|
+
## CollectionInscribeRef? or
|
|
27
|
+
## Layerref? or
|
|
28
|
+
## InscribeRef?
|
|
29
|
+
## FactoryItem ????
|
|
30
|
+
class Inscriberef < ActiveRecord::Base
|
|
31
|
+
belongs_to :factory
|
|
32
|
+
belongs_to :inscribe
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end # module Model
|
|
17
36
|
|
|
18
37
|
# note: convenience alias for Model
|
|
19
38
|
# lets you use include OrdDb::Models
|
|
20
39
|
Models = Model
|
|
21
|
-
end # module
|
|
40
|
+
end # module OrdDb
|
|
22
41
|
|
|
23
42
|
|
|
@@ -4,6 +4,271 @@ module OrdDb
|
|
|
4
4
|
|
|
5
5
|
class Inscribe < ActiveRecord::Base
|
|
6
6
|
has_one :blob, foreign_key: 'id'
|
|
7
|
+
|
|
8
|
+
has_one :factory ## optional (auto-added via og/orc-721 deploy)
|
|
9
|
+
has_one :generative, foreign_key: 'id' ## optional (auto-added via og/orc-721 deploy)
|
|
10
|
+
|
|
11
|
+
## convernience helper
|
|
12
|
+
## forward to blob.content
|
|
13
|
+
## blob.content - encoding is BINARY (ASCII-7BIT)
|
|
14
|
+
## blob.text - force_encoding is UTF-8 (return a copy)
|
|
15
|
+
def content() blob.content; end
|
|
16
|
+
def text() blob.text; end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
################################
|
|
20
|
+
### scope like helpers
|
|
21
|
+
def self.deploys
|
|
22
|
+
where_clause =<<SQL
|
|
23
|
+
content LIKE '%deploy%'
|
|
24
|
+
AND ( content LIKE '%orc-721%'
|
|
25
|
+
OR content LIKE '%og%')
|
|
26
|
+
SQL
|
|
27
|
+
|
|
28
|
+
joins(:blob).where( where_clause ).order( 'num' )
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.deploys_by( slug: )
|
|
32
|
+
where_clause =<<SQL
|
|
33
|
+
content LIKE '%deploy%'
|
|
34
|
+
AND ( content LIKE '%orc-721%'
|
|
35
|
+
OR content LIKE '%og%')
|
|
36
|
+
AND content LIKE '%#{slug}%'
|
|
37
|
+
SQL
|
|
38
|
+
|
|
39
|
+
joins(:blob).where( where_clause ).order( 'num' )
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.mints
|
|
43
|
+
where_clause =<<SQL
|
|
44
|
+
content LIKE '%mint%'
|
|
45
|
+
AND ( content LIKE '%orc-721%'
|
|
46
|
+
OR content LIKE '%og%')
|
|
47
|
+
SQL
|
|
48
|
+
|
|
49
|
+
joins(:blob).where( where_clause ).order( 'num' )
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.mints_by( slug: )
|
|
53
|
+
where_clause =<<SQL
|
|
54
|
+
content LIKE '%mint%'
|
|
55
|
+
AND ( content LIKE '%orc-721%'
|
|
56
|
+
OR content LIKE '%og%')
|
|
57
|
+
AND content LIKE '%#{slug}%'
|
|
58
|
+
SQL
|
|
59
|
+
|
|
60
|
+
joins(:blob).where( where_clause ).order( 'num' )
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.sub1k() where( 'num < 1000' ); end
|
|
64
|
+
def self.sub2k() where( 'num < 2000' ); end
|
|
65
|
+
def self.sub10k() where( 'num < 10000' ); end
|
|
66
|
+
def self.sub20k() where( 'num < 20000' ); end
|
|
67
|
+
def self.sub100k() where( 'num < 100000' ); end
|
|
68
|
+
def self.sub1m() where( 'num < 1000000' ); end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def self.largest
|
|
72
|
+
order( 'bytes DESC' )
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.block_counts
|
|
76
|
+
group( 'block' ).count
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.block_with_timestamp_counts
|
|
80
|
+
group( Arel.sql( "block || ' @ ' || date" )).count
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def self.content_type_counts
|
|
84
|
+
group( 'content_type' )
|
|
85
|
+
.order( Arel.sql( 'COUNT(*) DESC, content_type')).count
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def self.date_counts
|
|
90
|
+
## note: strftime is SQLite specific/only!!!
|
|
91
|
+
group( Arel.sql("strftime('%Y-%m-%d', date)"))
|
|
92
|
+
.order( Arel.sql("strftime('%Y-%m-%d', date)")).count
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.month_counts
|
|
96
|
+
## note: strftime is SQLite specific/only!!!
|
|
97
|
+
group( Arel.sql("strftime('%Y-%m', date)"))
|
|
98
|
+
.order( Arel.sql("strftime('%Y-%m', date)")).count
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.hour_counts
|
|
102
|
+
## note: strftime is SQLite specific/only!!!
|
|
103
|
+
group( Arel.sql("strftime('%Y-%m-%d %Hh', date)"))
|
|
104
|
+
.order( Arel.sql("strftime('%Y-%m-%d %Hh', date)")).count
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class << self
|
|
109
|
+
alias_method :biggest, :largest
|
|
110
|
+
alias_method :counts_by_content_type, :content_type_counts
|
|
111
|
+
alias_method :counts_by_date, :date_counts
|
|
112
|
+
alias_method :counts_by_day, :date_counts
|
|
113
|
+
alias_method :counts_by_month, :month_counts
|
|
114
|
+
alias_method :counts_by_hour, :hour_counts
|
|
115
|
+
alias_method :counts_by_block, :block_counts
|
|
116
|
+
alias_method :counts_by_block_with_timestamp, :block_with_timestamp_counts
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def self.text
|
|
121
|
+
## note: for now include:
|
|
122
|
+
## - text/plain (all variants)
|
|
123
|
+
## - text/json (all variants)
|
|
124
|
+
## - text/markdown
|
|
125
|
+
where( content_type:
|
|
126
|
+
['text/plain',
|
|
127
|
+
'text/plain;charset=utf-8',
|
|
128
|
+
'text/markdown',
|
|
129
|
+
'application/json',
|
|
130
|
+
]
|
|
131
|
+
)
|
|
132
|
+
end
|
|
133
|
+
def self.png() where( content_type: 'image/png' ); end
|
|
134
|
+
|
|
135
|
+
###
|
|
136
|
+
## add support for ordinals.com api txt (headers format)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def self.create_from_api( data ) create( _parse_api( data )); end
|
|
140
|
+
class << self
|
|
141
|
+
alias_method :create_from_cache, :create_from_api ## add alias - why? why not?
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def self._parse_api( data ) ## parse api json data
|
|
146
|
+
## num via title
|
|
147
|
+
attributes = {
|
|
148
|
+
id: data['id'],
|
|
149
|
+
num: _title_to_num( data['title'] ),
|
|
150
|
+
bytes: _content_length_to_bytes( data['content-length'] ),
|
|
151
|
+
sat: data['sat'].to_i(10),
|
|
152
|
+
content_type: data['content-type'],
|
|
153
|
+
block: data['genesis-height'].to_i(10),
|
|
154
|
+
fee: data['genesis-fee'].to_i(10),
|
|
155
|
+
tx: data['genesis-transaction'],
|
|
156
|
+
address: data['address'],
|
|
157
|
+
output: data['output'],
|
|
158
|
+
value: data['output-value'].to_i(10),
|
|
159
|
+
offset: data['offset'].to_i(10),
|
|
160
|
+
# "2023-06-01 05:00:57 UTC"
|
|
161
|
+
date: DateTime.strptime( data['timestamp'],
|
|
162
|
+
'%Y-%m-%d %H:%M:%S %z')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
attributes
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
## "title": "Inscription 9992615",
|
|
170
|
+
TITLE_RX = /^Inscription (?<num>[0-9]+)$/i
|
|
171
|
+
|
|
172
|
+
def self._title_to_num( str )
|
|
173
|
+
if m=TITLE_RX.match( str )
|
|
174
|
+
m[:num].to_i(10) ## use base 10
|
|
175
|
+
else
|
|
176
|
+
puts "!! ERROR - no inscribe num found in title >#{str}<"
|
|
177
|
+
exit 1 ## not found - raise exception - why? why not?
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
CONTENT_LENGTH_RX = /^(?<num>[0-9]+) bytes$/i
|
|
182
|
+
|
|
183
|
+
def self._content_length_to_bytes( str )
|
|
184
|
+
if m=CONTENT_LENGTH_RX.match( str )
|
|
185
|
+
m[:num].to_i(10) ## use base 10
|
|
186
|
+
else
|
|
187
|
+
puts "!! ERROR - bytes found in content lenght >#{str}<"
|
|
188
|
+
exit 1 ## not found - raise exception - why? why not?
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
###
|
|
195
|
+
# instance methods
|
|
196
|
+
def extname
|
|
197
|
+
## map mime type to file extname
|
|
198
|
+
## see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
|
|
199
|
+
## for real-world usage, see https://dune.com/dgtl_assets/bitcoin-ordinals-analysis
|
|
200
|
+
## https://github.com/casey/ord/blob/master/src/media.rs
|
|
201
|
+
|
|
202
|
+
if content_type.start_with?( 'text/plain' )
|
|
203
|
+
'.txt'
|
|
204
|
+
elsif content_type.start_with?( 'text/markdown' )
|
|
205
|
+
'.md'
|
|
206
|
+
elsif content_type.start_with?( 'text/html' )
|
|
207
|
+
'.html'
|
|
208
|
+
elsif content_type.start_with?( 'text/javascript' ) ||
|
|
209
|
+
content_type.start_with?( 'application/javascript' )
|
|
210
|
+
## note: application/javascript is considered bad practice/legacy
|
|
211
|
+
'.js'
|
|
212
|
+
elsif content_type.start_with?( 'image/png' )
|
|
213
|
+
## Portable Network Graphics (PNG)
|
|
214
|
+
'.png'
|
|
215
|
+
elsif content_type.start_with?( 'image/jpeg' )
|
|
216
|
+
## Joint Photographic Expert Group image (JPEG)
|
|
217
|
+
'.jpg' ## use jpeg - why? why not?
|
|
218
|
+
elsif content_type.start_with?( 'image/webp' )
|
|
219
|
+
## Web Picture format (WEBP)
|
|
220
|
+
'.webp' ## note: no three-letter extension available
|
|
221
|
+
elsif content_type.start_with?( 'image/svg' )
|
|
222
|
+
## Scalable Vector Graphics (SVG)
|
|
223
|
+
'.svg'
|
|
224
|
+
elsif content_type.start_with?( 'image/gif' )
|
|
225
|
+
## Graphics Interchange Format (GIF)
|
|
226
|
+
'.gif'
|
|
227
|
+
elsif content_type.start_with?( 'image/avif' )
|
|
228
|
+
## AV1 Image File Format (AVIF)
|
|
229
|
+
'.avif'
|
|
230
|
+
elsif content_type.start_with?( 'application/epub' )
|
|
231
|
+
'.epub'
|
|
232
|
+
elsif content_type.start_with?( 'application/pdf' )
|
|
233
|
+
'.pdf'
|
|
234
|
+
elsif content_type.start_with?( 'application/json' )
|
|
235
|
+
'.json'
|
|
236
|
+
elsif content_type.start_with?( 'application/pgp-signature' )
|
|
237
|
+
'.sig'
|
|
238
|
+
elsif content_type.start_with?( 'audio/mpeg' )
|
|
239
|
+
'.mp3'
|
|
240
|
+
elsif content_type.start_with?( 'audio/midi' )
|
|
241
|
+
'.midi'
|
|
242
|
+
elsif content_type.start_with?( 'video/mp4' )
|
|
243
|
+
'.mp4'
|
|
244
|
+
elsif content_type.start_with?( 'video/webm' )
|
|
245
|
+
'.wepm'
|
|
246
|
+
elsif content_type.start_with?( 'audio/mod' )
|
|
247
|
+
## is typo? possible? only one inscription in 20m?
|
|
248
|
+
'.mod' ## check/todo/fix if is .wav??
|
|
249
|
+
else
|
|
250
|
+
puts "!! ERROR - no file extension configured for content type >#{content_type}<; sorry:"
|
|
251
|
+
pp self
|
|
252
|
+
exit 1
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def export_path ## default export path
|
|
257
|
+
numstr = "%08d" % num ### e.g. 00000001
|
|
258
|
+
"./tmp/#{numstr}#{extname}"
|
|
259
|
+
end
|
|
260
|
+
def export( path=export_path )
|
|
261
|
+
if blob
|
|
262
|
+
write_blob( path, blob.content )
|
|
263
|
+
else
|
|
264
|
+
## todo/fix: raise exception - no content
|
|
265
|
+
puts "!! ERROR - inscribe has no content (blob); sorry:"
|
|
266
|
+
pp self
|
|
267
|
+
exit 1
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
|
|
7
272
|
end # class Inscribe
|
|
8
273
|
|
|
9
274
|
end # module Model
|
data/lib/ordlite/schema.rb
CHANGED
|
@@ -87,7 +87,7 @@ create_table :inscribes, :id => :string do |t|
|
|
|
87
87
|
## what is location ???
|
|
88
88
|
## "location": "0a3a4dbf6630338bc4df8e36bd081f8f7d2dee9441131cb03a18d43eb4882d5c:0:0",
|
|
89
89
|
|
|
90
|
-
## timestamp
|
|
90
|
+
## timestamp last
|
|
91
91
|
t.timestamps
|
|
92
92
|
end
|
|
93
93
|
|
|
@@ -99,14 +99,117 @@ create_table :blobs, :id => :string do |t|
|
|
|
99
99
|
## t.string :id, null: false, index: { unique: true, name: 'blob_uuids' }
|
|
100
100
|
|
|
101
101
|
t.binary :content, null: false
|
|
102
|
+
t.string :sha256 ## sha256 hash
|
|
103
|
+
t.string :md5 ## md5 hash - add why? why not?
|
|
102
104
|
|
|
103
|
-
## timestamp
|
|
105
|
+
## timestamp last
|
|
104
106
|
t.timestamps
|
|
105
107
|
end
|
|
106
108
|
|
|
107
109
|
|
|
110
|
+
=begin
|
|
111
|
+
"name": "Planetary Ordinals",
|
|
112
|
+
"inscription_icon": "98da33abe2045ec1421fcf1bc376dea5beb17ded15aa70ca5da490f50d95a6d9i0",
|
|
113
|
+
"supply": "69",
|
|
114
|
+
"slug": "planetary-ordinals",
|
|
115
|
+
"description": "",
|
|
116
|
+
"twitter_link": "https://twitter.com/ordinalswallet",
|
|
117
|
+
"discord_link": "https://discord.com/invite/ordinalswallet",
|
|
118
|
+
"website_link": ""
|
|
119
|
+
=end
|
|
120
|
+
|
|
121
|
+
create_table :collections do |t|
|
|
122
|
+
t.string :name, null: false
|
|
123
|
+
t.string :slug
|
|
124
|
+
t.text :desc # description
|
|
125
|
+
t.integer :max # supply
|
|
126
|
+
t.string :icon_id ## rename to inscribe_icon_id or such - why? why not?
|
|
127
|
+
## add twitter_link, discord_link, website_link - why? why not?
|
|
128
|
+
|
|
129
|
+
## if on-chain and metadata inscribed - add why? why not??
|
|
130
|
+
## t.string :source_id, null: false ## foreign key reference
|
|
131
|
+
|
|
132
|
+
## timestamp last
|
|
133
|
+
t.timestamps
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
create_table :items do |t|
|
|
137
|
+
t.integer :collection_id, null: false
|
|
138
|
+
t.string :inscribe_id, null: false
|
|
139
|
+
t.integer :pos, null: false
|
|
140
|
+
t.string :name
|
|
141
|
+
|
|
142
|
+
## timestamp last
|
|
143
|
+
t.timestamps
|
|
144
|
+
|
|
145
|
+
## todo/fix: add unique index for :pos+:collection_id !!!
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
###
|
|
151
|
+
# generative (collection) factory
|
|
152
|
+
create_table :factories, :id => :string do |t|
|
|
153
|
+
t.string :name
|
|
154
|
+
t.integer :max # max limit
|
|
155
|
+
t.integer :maxblock # max block limit
|
|
156
|
+
t.string :dim # dimension e.g. 24x24 (in px)
|
|
157
|
+
|
|
158
|
+
t.string :inscribe_id, null: false ## foreign key reference
|
|
159
|
+
|
|
160
|
+
## timestamp last
|
|
161
|
+
t.timestamps
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
#####
|
|
165
|
+
## join table (factory has_many modules)
|
|
166
|
+
## rename to layer / sprites / blocks / tiles / modules / submodules / subs / mods / ...etc - why? why not?
|
|
167
|
+
## layerlists or inscribelists or ???
|
|
168
|
+
## change/rename to factory_items or layer_items or such?
|
|
169
|
+
create_table :inscriberefs, :id => false do |t|
|
|
170
|
+
t.string :factory_id, null: false
|
|
171
|
+
t.string :inscribe_id, null: false
|
|
172
|
+
t.integer :pos, null: false ## position (index) in list (starting at 0)
|
|
173
|
+
## todo/fix: make factory_id + inscribe_id + pos unique index - why? why not?
|
|
174
|
+
|
|
175
|
+
## timestamp last
|
|
176
|
+
t.timestamps
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
create_table :generatives, :id => :string do |t|
|
|
181
|
+
t.string :factory_id, null: false
|
|
182
|
+
t.string :g, null: false ## use space separated numbers - why? why not?
|
|
183
|
+
t.binary :content ### optional for now - why? why not?
|
|
184
|
+
|
|
185
|
+
## timestamp last
|
|
186
|
+
t.timestamps
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
108
192
|
end # block Schema.define
|
|
109
193
|
|
|
110
194
|
end # method up
|
|
111
195
|
end # class CreateDb
|
|
196
|
+
|
|
197
|
+
###
|
|
198
|
+
# migrations helpers
|
|
199
|
+
class AddGeneratives
|
|
200
|
+
|
|
201
|
+
def up
|
|
202
|
+
ActiveRecord::Schema.define do
|
|
203
|
+
create_table :generatives, :id => :string do |t|
|
|
204
|
+
t.string :factory_id, null: false
|
|
205
|
+
t.string :g, null: false ## use space separated numbers - why? why not?
|
|
206
|
+
t.binary :content ### optional for now - why? why not?
|
|
207
|
+
|
|
208
|
+
## timestamp last
|
|
209
|
+
t.timestamps
|
|
210
|
+
end
|
|
211
|
+
end # block Schema.define
|
|
212
|
+
end # method up
|
|
213
|
+
end # class AddGeneratives
|
|
214
|
+
|
|
112
215
|
end # module OrdDb
|
data/lib/ordlite/version.rb
CHANGED
data/lib/ordlite.rb
CHANGED
|
@@ -2,11 +2,21 @@
|
|
|
2
2
|
require_relative 'ordlite/base'
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
5
8
|
## add convenience helpers
|
|
6
9
|
## use require 'ordlite/base' if you do NOT want automagic aliases
|
|
7
10
|
|
|
8
11
|
|
|
9
|
-
Inscribe
|
|
10
|
-
Blob
|
|
12
|
+
Inscribe = OrdDb::Model::Inscribe
|
|
13
|
+
Blob = OrdDb::Model::Blob
|
|
14
|
+
Collection = OrdDb::Model::Collection
|
|
15
|
+
Factory = OrdDb::Model::Factory
|
|
16
|
+
Generative = OrdDb::Model::Generative
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
require 'active_support/number_helper'
|
|
20
|
+
include ActiveSupport::NumberHelper ## e.g. number_to_human_size
|
|
11
21
|
|
|
12
22
|
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ordlite
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.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: 2023-07-
|
|
11
|
+
date: 2023-07-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: ordinals
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
13
27
|
- !ruby/object:Gem::Dependency
|
|
14
28
|
name: activerecord
|
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -159,12 +173,16 @@ files:
|
|
|
159
173
|
- lib/ordlite.rb
|
|
160
174
|
- lib/ordlite/base.rb
|
|
161
175
|
- lib/ordlite/cache.rb
|
|
176
|
+
- lib/ordlite/importer.rb
|
|
162
177
|
- lib/ordlite/models/blob.rb
|
|
178
|
+
- lib/ordlite/models/collection.rb
|
|
179
|
+
- lib/ordlite/models/factory.rb
|
|
163
180
|
- lib/ordlite/models/forward.rb
|
|
181
|
+
- lib/ordlite/models/generative.rb
|
|
164
182
|
- lib/ordlite/models/inscribe.rb
|
|
165
183
|
- lib/ordlite/schema.rb
|
|
166
184
|
- lib/ordlite/version.rb
|
|
167
|
-
homepage: https://github.com/ordbase/
|
|
185
|
+
homepage: https://github.com/ordbase/ordbase
|
|
168
186
|
licenses:
|
|
169
187
|
- Public Domain
|
|
170
188
|
metadata: {}
|