ragdoll-cli 0.0.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.
data/lib/tasks/db.rake ADDED
@@ -0,0 +1,338 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rake"
4
+
5
+ namespace :db do
6
+ desc "Create the database"
7
+ task :create do
8
+ require_relative "../ragdoll-core"
9
+
10
+ config = Ragdoll::Core.configuration
11
+ puts "Creating database with config: #{config.database_config.inspect}"
12
+
13
+ case config.database_config[:adapter]
14
+ when "postgresql"
15
+ puts "PostgreSQL database setup - running as superuser to create database and role..."
16
+
17
+ # Connect as superuser to create database and role
18
+ ActiveRecord::Base.establish_connection(
19
+ adapter: 'postgresql',
20
+ database: 'postgres', # Connect to postgres database initially
21
+ username: ENV['POSTGRES_SUPERUSER'] || 'postgres',
22
+ password: ENV['POSTGRES_SUPERUSER_PASSWORD'],
23
+ host: config.database_config[:host] || 'localhost',
24
+ port: config.database_config[:port] || 5432
25
+ )
26
+
27
+ # Run individual SQL commands to avoid transaction block issues
28
+ begin
29
+ ActiveRecord::Base.connection.execute("DROP DATABASE IF EXISTS ragdoll_development")
30
+ rescue => e
31
+ puts "Note: #{e.message}" if e.message.include?("does not exist")
32
+ end
33
+
34
+ begin
35
+ ActiveRecord::Base.connection.execute("DROP ROLE IF EXISTS ragdoll")
36
+ rescue => e
37
+ puts "Note: #{e.message}" if e.message.include?("does not exist")
38
+ end
39
+
40
+ begin
41
+ ActiveRecord::Base.connection.execute("CREATE ROLE ragdoll WITH LOGIN CREATEDB")
42
+ rescue => e
43
+ puts "Note: Role already exists, continuing..." if e.message.include?("already exists")
44
+ end
45
+
46
+ begin
47
+ ActiveRecord::Base.connection.execute <<-SQL
48
+ CREATE DATABASE ragdoll_development
49
+ WITH OWNER = ragdoll
50
+ ENCODING = 'UTF8'
51
+ CONNECTION LIMIT = -1
52
+ SQL
53
+ rescue => e
54
+ puts "Note: Database already exists, continuing..." if e.message.include?("already exists")
55
+ end
56
+
57
+ ActiveRecord::Base.connection.execute("GRANT ALL PRIVILEGES ON DATABASE ragdoll_development TO ragdoll")
58
+
59
+ # Connect to the new database to set schema privileges
60
+ ActiveRecord::Base.establish_connection(
61
+ adapter: 'postgresql',
62
+ database: 'ragdoll_development',
63
+ username: ENV['POSTGRES_SUPERUSER'] || 'postgres',
64
+ password: ENV['POSTGRES_SUPERUSER_PASSWORD'],
65
+ host: config.database_config[:host] || 'localhost',
66
+ port: config.database_config[:port] || 5432
67
+ )
68
+
69
+ ActiveRecord::Base.connection.execute <<-SQL
70
+ -- Grant schema privileges (must be done while connected to the database)
71
+ GRANT ALL PRIVILEGES ON SCHEMA public TO ragdoll;
72
+ GRANT CREATE ON SCHEMA public TO ragdoll;
73
+
74
+ -- Set default privileges for future objects
75
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO ragdoll;
76
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO ragdoll;
77
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON FUNCTIONS TO ragdoll;
78
+
79
+ -- Enable pgvector extension
80
+ CREATE EXTENSION IF NOT EXISTS vector;
81
+ SQL
82
+
83
+ puts "Database and role created successfully"
84
+ when "mysql2"
85
+ # For MySQL, we'd typically create the database here
86
+ puts "MySQL database creation - ensure the database exists on your server"
87
+ end
88
+
89
+ puts "Database creation completed"
90
+ end
91
+
92
+ desc "Drop the database"
93
+ task :drop do
94
+ require_relative "../ragdoll-core"
95
+
96
+ config = Ragdoll::Core.configuration
97
+ puts "Dropping database with config: #{config.database_config.inspect}"
98
+
99
+ case config.database_config[:adapter]
100
+ when "postgresql", "mysql2"
101
+ puts "For #{config.database_config[:adapter]}, please drop the database manually on your server"
102
+ end
103
+
104
+ puts "Database drop completed"
105
+ end
106
+
107
+ desc "Setup the database (create and migrate)"
108
+ task setup: %i[create migrate]
109
+
110
+ desc "Reset the database (drop, create, and migrate)"
111
+ task reset: %i[drop create migrate]
112
+
113
+ desc "Run pending migrations"
114
+ task :migrate do
115
+ require_relative "../ragdoll-core"
116
+
117
+ puts "Running migrations..."
118
+ Ragdoll::Core::Database.setup({
119
+ auto_migrate: false
120
+ })
121
+
122
+ Ragdoll::Core::Database.migrate!
123
+ puts "Migrations completed"
124
+ end
125
+
126
+ desc "Rollback the database by one migration"
127
+ task :rollback do
128
+ require_relative "../ragdoll-core"
129
+
130
+ puts "Rolling back migrations..."
131
+ # For now, we'll implement a simple reset since our manual migration doesn't support rollback
132
+ puts "Note: Rollback not yet implemented, use db:reset to start over"
133
+ end
134
+
135
+ desc "Show migration status"
136
+ task :migrate_status do
137
+ require_relative "../ragdoll-core"
138
+
139
+ Ragdoll::Core::Database.setup({
140
+ auto_migrate: false
141
+ })
142
+
143
+ puts "\nMigration Status:"
144
+ puts "=================="
145
+
146
+ # Get migration files
147
+ migration_paths = [File.join(File.dirname(__FILE__), "..", "..", "db", "migrate")]
148
+ migration_files = Dir[File.join(migration_paths.first, "*.rb")].sort
149
+
150
+ # Get applied migrations
151
+ applied_versions = []
152
+ if ActiveRecord::Base.connection.table_exists?("schema_migrations")
153
+ applied_versions = ActiveRecord::Base.connection.select_values(
154
+ "SELECT version FROM schema_migrations ORDER BY version"
155
+ )
156
+ end
157
+
158
+ puts format("%-8s %-20s %s", "Status", "Migration ID", "Migration Name")
159
+ puts "-" * 60
160
+
161
+ migration_files.each do |migration_file|
162
+ version = File.basename(migration_file, ".rb").split("_").first
163
+ name = File.basename(migration_file, ".rb").split("_")[1..].join("_")
164
+ status = applied_versions.include?(version) ? "up" : "down"
165
+
166
+ puts format("%-8s %-20s %s", status, version, name)
167
+ end
168
+
169
+ puts "\nTotal migrations: #{migration_files.length}"
170
+ puts "Applied migrations: #{applied_versions.length}"
171
+ puts "Pending migrations: #{migration_files.length - applied_versions.length}"
172
+ end
173
+
174
+ desc "Show database schema information"
175
+ task :schema do
176
+ require_relative "../ragdoll-core"
177
+
178
+ Ragdoll::Core::Database.setup({
179
+ auto_migrate: false
180
+ })
181
+
182
+ puts "\nDatabase Schema:"
183
+ puts "================"
184
+ puts "Adapter: #{ActiveRecord::Base.connection.adapter_name}"
185
+
186
+ if ActiveRecord::Base.connection.tables.any?
187
+ ActiveRecord::Base.connection.tables.sort.each do |table|
188
+ puts "\nTable: #{table}"
189
+ columns = ActiveRecord::Base.connection.columns(table)
190
+ columns.each do |column|
191
+ puts " #{column.name}: #{column.type} (#{column.sql_type})#{unless column.null
192
+ ' NOT NULL'
193
+ end}#{if column.default
194
+ " DEFAULT #{column.default.inspect}"
195
+ end}"
196
+ end
197
+
198
+ # Show indexes
199
+ indexes = ActiveRecord::Base.connection.indexes(table)
200
+ next unless indexes.any?
201
+
202
+ puts " Indexes:"
203
+ indexes.each do |index|
204
+ unique_text = index.unique ? " (unique)" : ""
205
+ puts " #{index.name}: [#{index.columns.join(', ')}]#{unique_text}"
206
+ end
207
+ end
208
+ else
209
+ puts "No tables found. Run 'rake db:migrate' to create tables."
210
+ end
211
+ end
212
+
213
+ desc "Open database console"
214
+ task :console do
215
+ require_relative "../ragdoll-core"
216
+
217
+ config = Ragdoll::Core.configuration
218
+
219
+ case config.database_config[:adapter]
220
+ when "postgresql"
221
+ db_config = config.database_config
222
+ psql_cmd = "psql"
223
+ psql_cmd += " -h #{db_config[:host]}" if db_config[:host]
224
+ psql_cmd += " -p #{db_config[:port]}" if db_config[:port]
225
+ psql_cmd += " -U #{db_config[:username]}" if db_config[:username]
226
+ psql_cmd += " #{db_config[:database]}"
227
+ puts "Opening PostgreSQL console..."
228
+ system(psql_cmd)
229
+ when "mysql2"
230
+ db_config = config.database_config
231
+ mysql_cmd = "mysql"
232
+ mysql_cmd += " -h #{db_config[:host]}" if db_config[:host]
233
+ mysql_cmd += " -P #{db_config[:port]}" if db_config[:port]
234
+ mysql_cmd += " -u #{db_config[:username]}" if db_config[:username]
235
+ mysql_cmd += " -p" if db_config[:password]
236
+ mysql_cmd += " #{db_config[:database]}"
237
+ puts "Opening MySQL console..."
238
+ system(mysql_cmd)
239
+ else
240
+ puts "Console not supported for adapter: #{config.database_config[:adapter]}"
241
+ end
242
+ end
243
+
244
+ desc "Show database statistics"
245
+ task :stats do
246
+ require_relative "../ragdoll-core"
247
+
248
+ Ragdoll::Core::Database.setup({
249
+ auto_migrate: false
250
+ })
251
+
252
+ puts "\nDatabase Statistics:"
253
+ puts "==================="
254
+
255
+ if ActiveRecord::Base.connection.table_exists?("ragdoll_documents")
256
+ doc_count = ActiveRecord::Base.connection.select_value("SELECT COUNT(*) FROM ragdoll_documents")
257
+ puts "Documents: #{doc_count}"
258
+
259
+ if doc_count.positive?
260
+ doc_types = ActiveRecord::Base.connection.select_rows(
261
+ "SELECT document_type, COUNT(*) FROM ragdoll_documents GROUP BY document_type"
262
+ )
263
+ puts "Document types:"
264
+ doc_types.each { |type, count| puts " #{type}: #{count}" }
265
+
266
+ statuses = ActiveRecord::Base.connection.select_rows(
267
+ "SELECT status, COUNT(*) FROM ragdoll_documents GROUP BY status"
268
+ )
269
+ puts "Document statuses:"
270
+ statuses.each { |status, count| puts " #{status}: #{count}" }
271
+ end
272
+ else
273
+ puts "Documents table does not exist"
274
+ end
275
+
276
+ if ActiveRecord::Base.connection.table_exists?("ragdoll_embeddings")
277
+ embedding_count = ActiveRecord::Base.connection.select_value("SELECT COUNT(*) FROM ragdoll_embeddings")
278
+ puts "Embeddings: #{embedding_count}"
279
+
280
+ if embedding_count.positive?
281
+ models = ActiveRecord::Base.connection.select_rows(
282
+ "SELECT model_name, COUNT(*) FROM ragdoll_embeddings GROUP BY model_name"
283
+ )
284
+ puts "Embedding models:"
285
+ models.each { |model, count| puts " #{model}: #{count}" }
286
+
287
+ usage_stats = ActiveRecord::Base.connection.select_one(
288
+ "SELECT AVG(usage_count) as avg_usage, MAX(usage_count) as max_usage FROM ragdoll_embeddings"
289
+ )
290
+ puts "Usage statistics:"
291
+ puts " Average usage: #{usage_stats['avg_usage'].to_f.round(2)}"
292
+ puts " Max usage: #{usage_stats['max_usage']}"
293
+ end
294
+ else
295
+ puts "Embeddings table does not exist"
296
+ end
297
+ end
298
+
299
+ desc "Truncate all tables (remove all data but keep structure)"
300
+ task :truncate do
301
+ require_relative "../ragdoll-core"
302
+
303
+ Ragdoll::Core::Database.setup({
304
+ auto_migrate: false
305
+ })
306
+
307
+ puts "Truncating all tables..."
308
+
309
+ # Disable foreign key checks temporarily
310
+ case ActiveRecord::Base.connection.adapter_name.downcase
311
+ when "postgresql"
312
+ ActiveRecord::Base.connection.execute("SET session_replication_role = 'replica'")
313
+ when "mysql"
314
+ ActiveRecord::Base.connection.execute("SET FOREIGN_KEY_CHECKS = 0")
315
+ end
316
+
317
+ # Truncate tables in correct order (dependent tables first)
318
+ %w[ragdoll_embeddings ragdoll_documents].each do |table|
319
+ if ActiveRecord::Base.connection.table_exists?(table)
320
+ ActiveRecord::Base.connection.execute("DELETE FROM #{table}")
321
+ puts "Truncated #{table}"
322
+ end
323
+ end
324
+
325
+ # Re-enable foreign key checks
326
+ case ActiveRecord::Base.connection.adapter_name.downcase
327
+ when "postgresql"
328
+ ActiveRecord::Base.connection.execute("SET session_replication_role = 'origin'")
329
+ when "mysql"
330
+ ActiveRecord::Base.connection.execute("SET FOREIGN_KEY_CHECKS = 1")
331
+ end
332
+
333
+ puts "All tables truncated"
334
+ end
335
+ end
336
+
337
+ # Make db tasks available as top-level commands
338
+ task db: "db:migrate_status"
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ragdoll-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Dewayne VanHoozer
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Under development. Contributors welcome.
13
+ email:
14
+ - dvanhoozer@gmail.com
15
+ executables:
16
+ - ragdoll
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - Rakefile
22
+ - bin/ragdoll
23
+ - lib/ragdoll/cli.rb
24
+ - lib/ragdoll/cli/commands/config.rb
25
+ - lib/ragdoll/cli/commands/delete.rb
26
+ - lib/ragdoll/cli/commands/health.rb
27
+ - lib/ragdoll/cli/commands/list.rb
28
+ - lib/ragdoll/cli/commands/search.rb
29
+ - lib/ragdoll/cli/commands/stats.rb
30
+ - lib/ragdoll/cli/commands/status.rb
31
+ - lib/ragdoll/cli/commands/update.rb
32
+ - lib/ragdoll/cli/configuration_loader.rb
33
+ - lib/ragdoll/cli/standalone_client.rb
34
+ - lib/ragdoll/cli/version.rb
35
+ - lib/tasks/annotate.rake
36
+ - lib/tasks/db.rake
37
+ homepage: https://github.com/MadBomber/ragdoll-cli
38
+ licenses:
39
+ - MIT
40
+ metadata:
41
+ allowed_push_host: https://rubygems.org
42
+ homepage_uri: https://github.com/MadBomber/ragdoll-cli
43
+ source_code_uri: https://github.com/MadBomber/ragdoll-cli/blob/main
44
+ changelog_uri: https://github.com/MadBomber/ragdoll-cli/blob/main/CHANGELOG.md
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 3.2.0
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.7.1
60
+ specification_version: 4
61
+ summary: Multi-Modal Retrieval Augmented Generation for the CLI
62
+ test_files: []