From 61df4771dc2a397393ab726daa66796e234e242f Mon Sep 17 00:00:00 2001 From: epitron Date: Thu, 21 Nov 2013 22:36:02 -0500 Subject: [PATCH] Added screenshot --- .gitignore | 0 LICENSE | 13 +++++++++++ README | 47 ------------------------------------- README.rdoc | 36 ++++++++++++++++++++++++++++ sqlsh.rb | 67 +++++++++++++++++++++++------------------------------ 5 files changed, 78 insertions(+), 85 deletions(-) mode change 100644 => 100755 .gitignore create mode 100644 LICENSE delete mode 100644 README create mode 100644 README.rdoc diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..90107a0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + 14 rue de Plaisance, 75014 Paris, France + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README b/README deleted file mode 100644 index 0eea3b8..0000000 --- a/README +++ /dev/null @@ -1,47 +0,0 @@ -[ This is a copy of the header from the source file. :) ] - -########################################################################### -# SQL Shell :: A shell for your SQL! -# ------------------------------------- -# -# Usage: -# -# sqlsh.rb mysql://:@/ -# -# Refactoring: -# --------------------- -# * Steal jed's display-in-colums thingy -# * Browser#for(path) returns a new browser in that path -# => ls("/what/lala") is implemented by @browser.for("/what/lala").ls -# => can all commands work without "use"? -# => #context method uses path info, not "USE" -# * option parser -# * path parser (make paths the standard db interface) -# => path.up -# => path.database_name -# => path.= -# => path.table_name -# => path.column_name -# -# Feature todos: -# --------------------- -# * shell style commands: -# => "open" command (auto-prompt for username/password) -# => "rm" command (drop database/table/column/index) -# => "mkdir" or "new" command (creates databases, tables, and columns) -# => "mv" or "rename" (for table, column, etc.) -# => "edit " pops up a curses dialog w/ types and stuff (nano/vim/pico?) -# => "ls -l" shows {db: sizes/tables, table: columns/types/indexes, column: }. -# => remember last connection and auto-connect next session -# => less-style results (scroll left/right/up/down) -# => make a reuslt object that can display in short (column) -# long (ls -l) formats. -# => pager for long results (less?) -# => assigning result sets, and _ for last set (history of results?) -# => browser.root = argv[0] -# => log sql commands without ugly timestamps -# => a way to do joins (set intersection?) -# |_ table1<=column=>table2 -# => compact table display mode (truncate) fields -# => use URI (or addressable) to parse uris -# => bookmarks diff --git a/README.rdoc b/README.rdoc new file mode 100644 index 0000000..440976a --- /dev/null +++ b/README.rdoc @@ -0,0 +1,36 @@ += sqlsh + +A shell for your SQL -- browse any kind of database, quickly and easily! + +Brings familiar Unix commands (ls, mv, rm, etc.) and metaphors (pipes) to your SQL database. + +http://chris.ill-logic.com/images/sqlsh.png + +== Installing + + gem install sqlsh + +== Usage + +=== First, load your database + +Supply an URI: + + sqlsh mysql://:@/ + sqlsh sqlite://databasefile.db + +Or just a file (tries to intelligently guess the format): + + sqlsh databasefile.db + +=== Next, explore it + +Just type "help" to see what you can do. + +== Copyright + +Copyright (c) 2005-2012 by Chris Gahan + +== License + +Licensed under the WTFPL2. (See LICENSE for details.) diff --git a/sqlsh.rb b/sqlsh.rb index 1c2f49e..923673a 100644 --- a/sqlsh.rb +++ b/sqlsh.rb @@ -10,7 +10,11 @@ # # Refactoring: # --------------------- -# * Steal jed's display-in-colums thingy +# * Specs +# * Create a "query for information class" that abstracts over the different database types +# ^- then, use this to implement the interface +# * Use something like 'Slop' +# * Use Term::Table # * Browser#for(path) returns a new browser in that path # => ls("/what/lala") is implemented by @browser.for("/what/lala").ls # => can all commands work without "use"? @@ -31,7 +35,9 @@ # => "mkdir" or "new" command (creates databases, tables, and columns) # => "mv" or "rename" (for table, column, etc.) # => "edit " pops up a curses dialog w/ types and stuff (nano/vim/pico?) -# => "ls -l" shows {db: sizes/tables, table: columns/types/indexes, column: }. +# => "ls -l" shows {db: sizes/tables, table: columns/types/indexes, column: }. +# => args can be files or urls (intelligently guess which one the user means) +# => let the user open MySQL DB files directly (for MySQLi apps) # => remember last connection and auto-connect next session # => less-style results (scroll left/right/up/down) # => make a reuslt object that can display in short (column) @@ -45,37 +51,13 @@ # => compact table display mode (truncate) fields # => use URI (or addressable) to parse uris # => bookmarks +# => import/export databases (SQL, CSV, YAML, JSON, etc.) ########################################################################### # Required modules -%w(rubygems sequel logger pp readline colorize).each{|mod| require mod} -########################################################################### - - - -########################################################################### -# Helpers (aka. MonkeyPatches) -# -class Symbol - def to_proc - Proc.new { |*args| args.shift.__send__(self, *args) } - end -end - -class String - def pad(n) - amount = [0,(n-size)].max # clip negative values to 0 - self + ' '*amount - end - - def startswith(sub) - (self =~ /^#{Regexp.escape(sub.to_s)}/) != nil - end -end - -class Array - alias_method :filter, :select -end +require 'epitools' +require 'sequel' +require 'readline' ########################################################################### @@ -135,6 +117,10 @@ def columns @db[@table].columns.map(&:to_s).sort end + def table_stats + table_stats_for(@db) + end + def use_table!(table) if table_exists? table @table = table.to_sym @@ -156,7 +142,8 @@ def tables_for(dbname) # def table_stats_for(dbname) results = {} - @db.fetch("SHOW TABLE STATUS FROM `#{dbname}`").map do |tbl| + + @db.fetch("SHOW TABLE STATUS FROM `#{dbname}`").each do |tbl| results[tbl[:Name]] = { :data_size => tbl[:Data_length], :index_size => tbl[:Index_length], @@ -170,8 +157,9 @@ def table_stats_for(dbname) :encoding => tbl[:Collation], } end + + results end - def database_size_for(dbname) db_size = 0 @@ -204,6 +192,7 @@ def ls_l(params=nil) when :tables # tables w/ rows, index size, etc. nil + when :databases # database size, table count, etc. list = databases.map { |dbname| [dbname, {:tables=>tables_for(dbname).size}] } @@ -243,9 +232,9 @@ def column_type(column) end TRANSLATE_TO_SQL_COLUMN_TYPE = { - "int" => "INTEGER", - "string" => "VARCHAR(255)", - "str" => "VARCHAR(255)", + "int" => "INTEGER", + "string" => "VARCHAR(255)", + "str" => "VARCHAR(255)", } def mv(src, dest) @@ -339,7 +328,7 @@ def ls_color def completions(sub) - ls.filter{|x| x.startswith(sub) } + ls.select{|x| x.startswith(sub) } end end @@ -399,10 +388,10 @@ def column_print(things, color=:white) things += [''] * (cols - (things.size % cols)) end - things.map!{|thing| thing.pad(col_width)} + things.map!{|thing| thing.ljust(col_width)} things.each_slice(cols) do |slice| - puts slice.join(' | ').colorize(color) + puts slice.join(' | ').send(color) end end @@ -438,6 +427,8 @@ def parse(line) @browser.mv($1, $2) when /^cd (\S+)/i @browser.cd($1) + when ".." + @browser.cd("..") when /^rm -r (\S+)/i @browser.rm_r($1) when /^rm (\S+)/i