ordlite 0.1.0 → 0.1.2

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: 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