Skip to content

Instantly share code, notes, and snippets.

@jenya239
Last active May 11, 2019 18:11
Show Gist options
  • Save jenya239/ed9b9ca4dd4eb78ab8c749dab0389ad3 to your computer and use it in GitHub Desktop.
Save jenya239/ed9b9ca4dd4eb78ab8c749dab0389ad3 to your computer and use it in GitHub Desktop.
sql.rb
require 'awesome_print'
require 'fileutils'
require 'time'
class Option
attr_reader :name, :underscore, :index
attr_accessor :named_value
def initialize( name =nil, underscore =false, index =false, to_sql =nil )
@name, @underscore, @index, @to_sql =name, underscore, index, to_sql
@named_value =to_sql != nil
end
def to_sql( value ) #option processing )
if @to_sql
sql =instance_exec( value, &@to_sql )
sql =' ' + sql unless @index
return sql
end
value ? " #{ get_sql( value ) }" : ''
end
protected
def get_sql( value )
name =@name .to_s .upcase
name .gsub!('_', ' ') unless @underscore
name
end
end
class Options
attr_reader :hash
def initialize
arr ={ not_null: [],
unique: Proc .new{ |val| "UNIQUE INDEX `#{ val }_UNIQUE` (`#{ val }` ASC)" },
primary: Proc .new{ |val| "PRIMARY KEY (`#{ val }`)" },
auto_increment: [ true ],
default: [ false, false,
Proc .new{ |val| val =val .is_a?( String ) ? "'#{ val }'" : val .to_s; "DEFAULT #{ val }" } ] }
@array =arr .map do |name, val|
args =val .is_a?( Array ) ? val : [ false, true, val ]
Option .new name, *args
end
@hash ={}
@array .each do |opt|
instance_variable_set ( '@' + opt .name .to_s ) .to_sym, opt
singleton_class .instance_eval { attr_reader opt .name }
@hash[ opt .name ] =opt
end
@default .named_value =false
end
def by_name( name )
@hash[ name ]
end
end
class SQL
def initialize( sql )
@sql =sql
end
def to_s
@sql
end
end
class Field
@@options =Options .new #how without singletons?
@@types ={ string: 'VARCHAR( 255 )', text: 'TEXT', int: 'INT', date: 'DATE',
timestamp: 'TIMESTAMP' }
def initialize( name, type, opts ={} )
@name, @type =name, type
defaults ={ not_null: false, unique: false, primary: false, auto_increment: false, default: nil }
@opts = defaults .merge( opts )
@opts .each do |name, val|
instance_variable_set ( '@' + name .to_s ) .to_sym, val
end
end
def self .type_to_s( type )
@@types[ type ]
end
def self .type_exists( name )
@@types .key?( name .to_sym )
end
def indexes
inject []
end
def to_s
inject "`#{ @name }` #{ self.class.type_to_s( @type ) }"
end
private
def inject( accum )
is_str =accum .is_a?( String )
@opts .each{ |name, value|
next if value ==nil
opt =@@options .by_name( name )
#print "#{ opt .name } #{ opt .index } #{ is_str ^ opt .index } #{ value }\n"
next unless is_str ^ opt .index
next if opt .index and not value
val =opt .named_value ? @name : value
sql =opt .to_sql( val )
is_str ? accum += sql : accum << sql }
accum
end
end
class Table
def initialize( name, fields =[] )
@name =name .to_s
if fields .is_a? String
args =self .class .parse( fields )
@fields =args .map{ |arr| Field .new *arr }
else
@fields =fields
end
end
def to_s
s ="CREATE TABLE IF NOT EXISTS `#{ @name }` (\n\t"
s +=( @fields .map( &:to_s ) + @fields .inject([]){|arr,f| arr + f .indexes } ) .join( ",\n\t" )
s +="\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
end
def add_field( name, type, opts ={} )
@fields << Field .new( name, type, opts )
end
def self .parse_value( str )
if ( str[ 0 ] =="'" and str[ -1 ] =="'" ) or ( str[ 0 ] =='"' and str[ -1 ] =='"' )
str[ 1..-2 ]
elsif str =~ /^\d+$/
str .to_i
elsif str =~ /^\d*\.\d+$/
str .to_f
else
SQL .new str
end
end
def self .parse_line( line )
tokens =line .strip .split
is_type = Field .type_exists( tokens .first )
if is_type
type =tokens .shift .to_sym
tokens .map{ |t| [ t, type ] }
else
name =tokens .shift
type =tokens .shift .to_sym
opts ={}
prev =nil
while tokens .size > 0
token =tokens .shift
if token =='='
opts[ prev .to_sym ] =parse_value tokens .shift
else
opts[ token .to_sym ] =true
end
prev =token
end
#opts =tokens .inject( {} ){ |h, s| h[ s .to_sym ] =true; h }
[ [ name, type, opts ] ]
#p name, type, opts
end
end
def self .parse( s )
strings =s .strip .split "\n"
strings .inject( [] ){ |arr, line| arr += parse_line line }
end
end
t =Table .new 'posts', """
id int not_null unique primary auto_increment
post_id int
created_at timestamp default = CURRENT_TIMESTAMP
string title author image
text content
"""
print t .to_s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment