ordlite 0.1.0 → 0.1.2

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: 1d227087815f81d4a3bc1791e2fd34639074c8000568ca1c378c865d5450e39a
4
- data.tar.gz: c3697c7d069e85ade6dd427918796d5bf6cd302475299f5eb080287c80536508
3
+ metadata.gz: 238e3e5f3913821c8f0a70bdedb444deeea65da4ecdb5827f239b3b4a682a151
4
+ data.tar.gz: d01946f571d34b1b29ca7fe0216898f31fddc75e818d07300129af5d1a808c5e
5
5
  SHA512:
6
- metadata.gz: 0b7d753c4767407663ff2e29f2eaf2efe2689e0283ae332ada7404e3fc797678664a91d285e79cb09abf3f73675615f729c6e653093d9d895f710def43954503
7
- data.tar.gz: b85fd1bfe93b17dd26bd5e6e4e1c57b88cc2cad152405ef524a3a17dc3a9c50f740a9a83e2bc7c731dbf5b4a7b6fc7480c0881bf7ea174f86f593deb4f544f9a
6
+ metadata.gz: 1545c336ad9d22d92235bbe7160b3224a311cf5dd06b8a944d18d5d2e80c62a24f342be5ed3b295dd9b99cddd7654f931893f811a9571ef80688956cdff27178
7
+ data.tar.gz: 7300eb7a35ddcf56a41e10cdbc8844d81f8340147b18125d62a528d1eb27e4f8854e72ff70ec3858723ce2da99a3105b80f4414ec1706a593e81915b1aec9fb5
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.1.0 / 2023-07-01
1
+ ### 0.1.2 / 2023-07-02
2
2
  ### 0.0.1 / 2023-07-01
3
3
 
4
4
  * Everything is new. First release
data/Manifest.txt CHANGED
@@ -3,6 +3,8 @@ Manifest.txt
3
3
  README.md
4
4
  Rakefile
5
5
  lib/ordlite.rb
6
+ lib/ordlite/base.rb
7
+ lib/ordlite/cache.rb
6
8
  lib/ordlite/models/blob.rb
7
9
  lib/ordlite/models/forward.rb
8
10
  lib/ordlite/models/inscribe.rb
data/README.md CHANGED
@@ -11,13 +11,158 @@ ordlite - ordinals inscription (on bitcoin & co) database let's you query via sq
11
11
 
12
12
 
13
13
 
14
+ ## SQL Database Model
15
+
16
+ Insribes • Blobs
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
- To be done
17
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
+
66
+ #=> 0 inscribe(s)
67
+ #=> 0 blob(s)
68
+ ```
69
+
70
+
71
+
72
+
73
+ ### Example No 1 - Query Ordgen Deploy / Mint Inscriptions
74
+
75
+ ``` ruby
76
+ require 'ordlite'
77
+
78
+
79
+ OrdDb.connect( adapter: 'sqlite3',
80
+ database: './ord.db' )
81
+
82
+
83
+ ####################
84
+ ## query for deploy candidates
85
+ ##
86
+ ## e.g. sql where clause like
87
+ ## content LIKE '%deploy%'
88
+ ## AND ( content LIKE '%orc-721%'
89
+ ## OR content LIKE '%og%')
90
+ ##
91
+
92
+ deploys = Inscribe.deploys
93
+ puts " #{deploys.size} deploy candidate(s)"
94
+
95
+ deploys.each_with_index do |rec,i|
96
+ puts "==> deploy #{i} - num #{rec.num} - #{rec.bytes} bytes - #{rec.date}"
97
+ puts rec.content
98
+ end
99
+
100
+
101
+ punks_deploys = Inscribe.deploys_by( slug: 'diypunks')
102
+ puts " #{punks_deploys.size} deploy candidate(s)"
103
+
104
+
105
+
106
+ #######################
107
+ ## query for mint candidates
108
+ ##
109
+ ## e.g. sql where clause like
110
+ ## content LIKE '%mint%'
111
+ ## AND ( content LIKE '%orc-721%'
112
+ ## OR content LIKE '%og%')
113
+
114
+ mints = Inscribe.mints
115
+ puts " #{mints.size} mint candidate(s)"
116
+
117
+ ## print last hundred mint candidates
118
+ mints[-100,100].each_with_index do |rec,i|
119
+ puts "==> mint #{i} - num #{rec.num} - #{rec.bytes} bytes - #{rec.date}"
120
+ puts rec.content
121
+ end
122
+
123
+
124
+ phunks_mints = Inscribe.mints_by( slug: 'diyphunks')
125
+ puts " #{phunks_mints.size} mint candidate(s)"
126
+
127
+
128
+ puts " #{deploys.size} deploy candidate(s)"
129
+ puts " #{mints.size} mint candidate(s)"
130
+
131
+ #=> 123 deploy candidate(s)
132
+ #=> 7453 mint candidate(s)
133
+ ```
134
+
135
+
136
+
137
+
138
+ ### Bonus: Import (Cached) Inscription Datafiles (& Content)
139
+
140
+ Let's import all cached
141
+ inscriptions metadata datafiles (& content)
142
+ from [/ordinals.cache](https://github.com/ordbase/ordinals.cache)
143
+ into an (sql) database e.g. `ord.db`:
144
+
145
+
146
+ ``` ruby
147
+ require 'ordlite'
148
+
149
+ OrdDb.connect( adapter: 'sqlite3',
150
+ database: './ord.db' )
151
+
152
+ OrdDb.create_all # build table schema
153
+
154
+ cache_dir = './ordinals.cache/btc'
155
+ cache = OrdDb::Cache.new( cache_dir )
156
+ cache.import_all
18
157
 
19
158
 
159
+ puts
160
+ puts " #{Inscribe.count} inscribe(s)"
161
+ puts " #{Blob.count} blob(s)"
20
162
 
163
+ #=> 8505 inscribe(s)
164
+ #=> 7611 blob(s)
165
+ ```
21
166
 
22
167
 
23
168
  ## License
@@ -0,0 +1,106 @@
1
+ # core and stlibs
2
+
3
+ require 'pp'
4
+ require 'fileutils'
5
+ require 'uri'
6
+ require 'json'
7
+ require 'yaml'
8
+
9
+ require 'logger' # Note: use for ActiveRecord::Base.logger -- remove/replace later w/ LogUtils::Logger ???
10
+
11
+
12
+ # 3rd party gems / libs
13
+ require 'props' # see github.com/rubylibs/props
14
+ require 'logutils' # see github.com/rubylibs/logutils
15
+
16
+
17
+ require 'active_record' ## todo: add sqlite3? etc.
18
+
19
+ ## add more activerecords addons/utils
20
+ # require 'tagutils'
21
+ require 'activerecord/utils'
22
+ require 'props/activerecord' # includes ConfDb (ConfDb::Model::Prop, etc.)
23
+ require 'logutils/activerecord' # includes LogDb (LogDb::Model::Log, etc.)
24
+
25
+
26
+
27
+ # our own code
28
+ require_relative 'version' # always goes first
29
+
30
+ require_relative 'models/forward'
31
+
32
+ require_relative 'models/inscribe'
33
+ require_relative 'models/blob'
34
+
35
+
36
+ require_relative 'schema'
37
+
38
+ require_relative 'cache'
39
+
40
+
41
+
42
+ module OrdDb
43
+
44
+ def self.create
45
+ CreateDb.new.up
46
+ ConfDb::Model::Prop.create!( key: 'db.schema.ord.version',
47
+ value: Ordlite::VERSION )
48
+ end
49
+
50
+ def self.create_all
51
+ LogDb.create # add logs table
52
+ ConfDb.create # add props table
53
+ OrdDb.create
54
+ end
55
+
56
+ def self.connect( config={} )
57
+
58
+ if config.empty?
59
+ puts "ENV['DATBASE_URL'] - >#{ENV['DATABASE_URL']}<"
60
+
61
+ ### change default to ./ord.db ?? why? why not?
62
+ db = URI.parse( ENV['DATABASE_URL'] || 'sqlite3:///ord.db' )
63
+
64
+ if db.scheme == 'postgres'
65
+ config = {
66
+ adapter: 'postgresql',
67
+ host: db.host,
68
+ port: db.port,
69
+ username: db.user,
70
+ password: db.password,
71
+ database: db.path[1..-1],
72
+ encoding: 'utf8'
73
+ }
74
+ else # assume sqlite3
75
+ config = {
76
+ adapter: db.scheme, # sqlite3
77
+ database: db.path[1..-1] # ord.db (NB: cut off leading /, thus 1..-1)
78
+ }
79
+ end
80
+ end
81
+
82
+ puts "Connecting to db using settings: "
83
+ pp config
84
+ ActiveRecord::Base.establish_connection( config )
85
+ # ActiveRecord::Base.logger = Logger.new( STDOUT )
86
+ end
87
+
88
+
89
+ def self.setup_in_memory_db
90
+
91
+ # Database Setup & Config
92
+ ActiveRecord::Base.logger = Logger.new( STDOUT )
93
+ ## ActiveRecord::Base.colorize_logging = false - no longer exists - check new api/config setting?
94
+
95
+ self.connect( adapter: 'sqlite3',
96
+ database: ':memory:' )
97
+
98
+ ## build schema
99
+ OrdDb.create_all
100
+ end # setup_in_memory_db (using SQLite :memory:)
101
+
102
+ end # module OrdDb
103
+
104
+
105
+ # say hello
106
+ puts Ordlite.banner ## if defined?($RUBYCOCOS_DEBUG) && $RUBCOCOS_DEBUG
@@ -0,0 +1,123 @@
1
+
2
+ module OrdDb
3
+
4
+
5
+ class Cache
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"
19
+
20
+ paths.each_with_index do |path, i|
21
+ puts "==> inscribe #{i+1}/#{paths.size}..."
22
+ data = _read_inscribe( path )
23
+
24
+ Inscribe.create( _parse_inscribe( data ))
25
+ end
26
+
27
+
28
+ paths = Dir.glob( "#{@dir}/content/**.txt" )
29
+ puts " #{paths.size} content datafile(s) found"
30
+
31
+ paths.each_with_index do |path, i|
32
+ puts "==> blob #{i+1}/#{paths.size}..."
33
+ content = _read_blob( path )
34
+ id = File.basename( path, File.extname( path ))
35
+
36
+ Blob.create( id: id,
37
+ content: content )
38
+ end
39
+ end
40
+
41
+
42
+ def import( id )
43
+ data = read( id )
44
+ rec = Inscribe.create( _parse_inscribe( data ))
45
+ rec
46
+ end
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
98
+ else
99
+ puts "!! ERROR - no inscribe num found in title >#{str}<"
100
+ exit 1 ## not found - raise exception - why? why not?
101
+ end
102
+ end
103
+
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
+
123
+
@@ -4,6 +4,56 @@ module OrdDb
4
4
 
5
5
  class Inscribe < ActiveRecord::Base
6
6
  has_one :blob, foreign_key: 'id'
7
+
8
+ def content
9
+ ## convernience helper
10
+ ## forward to blob.content
11
+ blob.content
12
+ end
13
+
14
+ ################################
15
+ ### scope like helpers
16
+ def self.deploys
17
+ where_clause =<<SQL
18
+ content LIKE '%deploy%'
19
+ AND ( content LIKE '%orc-721%'
20
+ OR content LIKE '%og%')
21
+ SQL
22
+
23
+ joins(:blob).where( where_clause ).order( 'num' )
24
+ end
25
+
26
+ def self.deploys_by( slug: )
27
+ where_clause =<<SQL
28
+ content LIKE '%deploy%'
29
+ AND ( content LIKE '%orc-721%'
30
+ OR content LIKE '%og%')
31
+ AND content LIKE '%#{slug}%'
32
+ SQL
33
+
34
+ joins(:blob).where( where_clause ).order( 'num' )
35
+ end
36
+
37
+ def self.mints
38
+ where_clause =<<SQL
39
+ content LIKE '%mint%'
40
+ AND ( content LIKE '%orc-721%'
41
+ OR content LIKE '%og%')
42
+ SQL
43
+
44
+ joins(:blob).where( where_clause ).order( 'num' )
45
+ end
46
+
47
+ def self.mints_by( slug: )
48
+ where_clause =<<SQL
49
+ content LIKE '%mint%'
50
+ AND ( content LIKE '%orc-721%'
51
+ OR content LIKE '%og%')
52
+ AND content LIKE '%#{slug}%'
53
+ SQL
54
+
55
+ joins(:blob).where( where_clause ).order( 'num' )
56
+ end
7
57
  end # class Inscribe
8
58
 
9
59
  end # module Model
@@ -48,7 +48,8 @@ create_table :inscribes, :id => :string do |t|
48
48
 
49
49
  ## "content length": "85 bytes",
50
50
  ## note: extract bytes as integer!!!
51
- t.integer :content_length, null: false
51
+ ## change to bytes - why? why not?
52
+ t.integer :bytes, null: false
52
53
  ## "content type": "text/plain;charset=utf-8",
53
54
  ## note: make sure always lower/down case!!!
54
55
  t.string :content_type, null: false
@@ -63,10 +64,11 @@ create_table :inscribes, :id => :string do |t|
63
64
 
64
65
  ##
65
66
  ## "genesis height": "792337",
67
+ ## -> change height to block - why? why not?
66
68
  ## "genesis fee": "6118",
67
69
  ## "genesis transaction": "0a3a4dbf6630338bc4df8e36bd081f8f7d2dee9441131cb03a18d43eb4882d5c",
68
70
  ## "offset": "0"
69
- t.integer :height, null: false
71
+ t.integer :block, null: false
70
72
  t.integer :fee, null: false
71
73
  t.string :tx, null: false
72
74
  t.integer :offset, null: false
@@ -76,12 +78,15 @@ create_table :inscribes, :id => :string do |t|
76
78
  ## is this minter/inscriber addr???
77
79
  t.string :address, null: false
78
80
 
79
- ## -- ignore for now - why? why not?
80
- ## what is output ???
81
- ## "location": "0a3a4dbf6630338bc4df8e36bd081f8f7d2dee9441131cb03a18d43eb4882d5c:0:0",
82
81
  ## "output": "0a3a4dbf6630338bc4df8e36bd081f8f7d2dee9441131cb03a18d43eb4882d5c:0",
83
82
  ## "output value": "546",
84
-
83
+ t.string :output, null: false
84
+ t.integer :value, null: false
85
+
86
+ ## -- ignore for now - why? why not?
87
+ ## what is location ???
88
+ ## "location": "0a3a4dbf6630338bc4df8e36bd081f8f7d2dee9441131cb03a18d43eb4882d5c:0:0",
89
+
85
90
  ## timestamp at last
86
91
  t.timestamps
87
92
  end
@@ -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 = 1
7
- PATCH = 0
7
+ PATCH = 2
8
8
  VERSION = [MAJOR,MINOR,PATCH].join('.')
9
9
 
10
10
  def self.version
data/lib/ordlite.rb CHANGED
@@ -1,105 +1,12 @@
1
- # core and stlibs
2
1
 
3
- require 'pp'
4
- require 'fileutils'
5
- require 'uri'
6
- require 'json'
7
- require 'yaml'
2
+ require_relative 'ordlite/base'
8
3
 
9
- require 'logger' # Note: use for ActiveRecord::Base.logger -- remove/replace later w/ LogUtils::Logger ???
10
4
 
5
+ ## add convenience helpers
6
+ ## use require 'ordlite/base' if you do NOT want automagic aliases
11
7
 
12
- # 3rd party gems / libs
13
- require 'props' # see github.com/rubylibs/props
14
- require 'logutils' # see github.com/rubylibs/logutils
15
8
 
9
+ Inscribe = OrdDb::Model::Inscribe
10
+ Blob = OrdDb::Model::Blob
16
11
 
17
- require 'active_record' ## todo: add sqlite3? etc.
18
12
 
19
- ## add more activerecords addons/utils
20
- # require 'tagutils'
21
- require 'activerecord/utils'
22
- require 'props/activerecord' # includes ConfDb (ConfDb::Model::Prop, etc.)
23
- require 'logutils/activerecord' # includes LogDb (LogDb::Model::Log, etc.)
24
-
25
-
26
-
27
- # our own code
28
-
29
- require 'ordlite/version' # always goes first
30
-
31
- require 'ordlite/models/forward'
32
-
33
- require 'ordlite/models/inscribe'
34
- require 'ordlite/models/blob'
35
-
36
-
37
- require 'ordlite/schema'
38
-
39
-
40
-
41
- module OrdDb
42
-
43
- def self.create
44
- CreateDb.new.up
45
- ConfDb::Model::Prop.create!( key: 'db.schema.ord.version',
46
- value: Ordlite::VERSION )
47
- end
48
-
49
- def self.create_all
50
- LogDb.create # add logs table
51
- ConfDb.create # add props table
52
- OrdDb.create
53
- end
54
-
55
- def self.connect( config={} )
56
-
57
- if config.empty?
58
- puts "ENV['DATBASE_URL'] - >#{ENV['DATABASE_URL']}<"
59
-
60
- ### change default to ./ord.db ?? why? why not?
61
- db = URI.parse( ENV['DATABASE_URL'] || 'sqlite3:///ord.db' )
62
-
63
- if db.scheme == 'postgres'
64
- config = {
65
- adapter: 'postgresql',
66
- host: db.host,
67
- port: db.port,
68
- username: db.user,
69
- password: db.password,
70
- database: db.path[1..-1],
71
- encoding: 'utf8'
72
- }
73
- else # assume sqlite3
74
- config = {
75
- adapter: db.scheme, # sqlite3
76
- database: db.path[1..-1] # ord.db (NB: cut off leading /, thus 1..-1)
77
- }
78
- end
79
- end
80
-
81
- puts "Connecting to db using settings: "
82
- pp config
83
- ActiveRecord::Base.establish_connection( config )
84
- # ActiveRecord::Base.logger = Logger.new( STDOUT )
85
- end
86
-
87
-
88
- def self.setup_in_memory_db
89
-
90
- # Database Setup & Config
91
- ActiveRecord::Base.logger = Logger.new( STDOUT )
92
- ## ActiveRecord::Base.colorize_logging = false - no longer exists - check new api/config setting?
93
-
94
- self.connect( adapter: 'sqlite3',
95
- database: ':memory:' )
96
-
97
- ## build schema
98
- OrdDb.create_all
99
- end # setup_in_memory_db (using SQLite :memory:)
100
-
101
- end # module OrdDb
102
-
103
-
104
- # say hello
105
- puts Ordlite.banner ## if defined?($RUBYCOCOS_DEBUG) && $RUBCOCOS_DEBUG
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.1.0
4
+ version: 0.1.2
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-01 00:00:00.000000000 Z
11
+ date: 2023-07-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -157,6 +157,8 @@ files:
157
157
  - README.md
158
158
  - Rakefile
159
159
  - lib/ordlite.rb
160
+ - lib/ordlite/base.rb
161
+ - lib/ordlite/cache.rb
160
162
  - lib/ordlite/models/blob.rb
161
163
  - lib/ordlite/models/forward.rb
162
164
  - lib/ordlite/models/inscribe.rb