module Sequel class Dataset module Convenience # Returns the first record in the dataset. def single_record(opts = nil) each(opts) {|r| return r} nil end NAKED_HASH = {:naked => true}.freeze # Returns the first value of the first reecord in the dataset. def single_value(opts = nil) opts = opts ? NAKED_HASH.merge(opts) : NAKED_HASH each(opts) {|r| return r.values.first} end # Returns the first record in the dataset. If the num argument is specified, # an array is returned with the first num records. def first(*args) args = args.empty? ? 1 : (args.size == 1) ? args.first : args case args when 1: single_record(:limit => 1) when Fixnum: limit(args).all else filter(args).single_record(:limit => 1) end end # Returns the first record matching the condition. def [](*conditions) first(*conditions) end def []=(conditions, values) filter(conditions).update(values) end # Returns the last records in the dataset by inverting the order. If no # order is given, an exception is raised. If num is not given, the last # record is returned. Otherwise an array is returned with the last # num records. def last(*args) raise SequelError, 'No order specified' unless @opts[:order] || (opts && opts[:order]) args = args.empty? ? 1 : (args.size == 1) ? args.first : args case args when Fixnum: l = {:limit => args} opts = {:order => invert_order(@opts[:order])}. \ merge(opts ? opts.merge(l) : l) if args == 1 single_record(opts) else clone_merge(opts).all end else filter(args).last(1) end end # Maps field values for each record in the dataset (if a field name is # given), or performs the stock mapping functionality of Enumerable. def map(field_name = nil, &block) if field_name super() {|r| r[field_name]} else super(&block) end end # Returns a hash with one column used as key and another used as value. def to_hash(key_column, value_column) inject({}) do |m, r| m[r[key_column]] = r[value_column] m end end # returns a paginated dataset. The resulting dataset also provides the # total number of pages (Dataset#page_count) and the current page number # (Dataset#current_page), as well as Dataset#prev_page and Dataset#next_page # for implementing pagination controls. def paginate(page_no, page_size) total_pages = (count / page_size.to_f).ceil paginated = limit(page_size, (page_no - 1) * page_size) paginated.current_page = page_no paginated.page_count = total_pages paginated end attr_accessor :page_count, :current_page # Returns the previous page number or nil if the current page is the first def prev_page current_page > 1 ? (current_page - 1) : nil end # Returns the next page number or nil if the current page is the last page def next_page current_page < page_count ? (current_page + 1) : nil end # Returns the minimum value for the given field. def min(field) single_value(:select => [field.MIN]) end # Returns the maximum value for the given field. def max(field) single_value(:select => [field.MAX]) end # Returns the sum for the given field. def sum(field) single_value(:select => [field.SUM]) end # Returns the average value for the given field. def avg(field) single_value(:select => [field.AVG]) end # Pretty prints the records in the dataset as plain-text table. def print(*cols) Sequel::PrettyTable.print(naked.all, cols.empty? ? columns : cols) end end end end