lib/pg_conn.rb in pg_conn-0.26.2 vs lib/pg_conn.rb in pg_conn-0.27.0

- old
+ new

@@ -248,11 +248,11 @@ # Quote argument as an identifier. The argument should be a non-nil string # or a symbol def quote_identifier(s) s = s.to_s if s.is_a?(Symbol) - @pg_connection.escape_identifier(s) + @pg_connection.escape_identifier(s).gsub(/\./, '"."').sub(/"\*"/, "*") end # Quote identifiers and concatenate them using ',' as separator def quote_identifiers(idents) = idents.map { |ident| quote_identifier(ident) }.join(", ") @@ -337,182 +337,167 @@ # exist?(table, id) # eists?(table, where_clause) # # Return true iff the query returns exactly one record. Use '!empty?' to # check if the query returns one or more records - def exist?(*args) - arg1, arg2 = *args - query = - case arg2 - when Integer; "select from #{arg1} where id = #{arg2}" - when String; "select from #{arg1} where #{arg2}" - when NilClass; arg1 - end - count(query) == 1 + def exist?(*query) + !empty?(*query) end # :call-seq: # count(query) # count(table, where_clause = nil) # # Return true if the table or the result of the query is empty - def empty?(arg, where_clause = nil) - if arg =~ /\s/ - value "select count(*) from (#{arg} limit 1) as inner_query" - elsif where_clause - value "select count(*) from (select 1 from #{arg} where #{where_clause} limit 1) as inner_query" - else - value "select count(*) from (select 1 from #{arg} limit 1) as inner_query" - end == 0 + def empty?(*query) + inner_query = parse_query *query + self.value("select count(*) from (#{inner_query} limit 1) as \"inner_query\"") == 0 end # :call-seq: # count(query) # count(table_name, where_clause = nil) # # The number of records in the table or in the query - def count(arg, where_clause = nil) - if arg =~ /\s/ - value("select count(*) from (#{arg}) as inner_query") - else - value("select count(*) from #{arg}" + (where_clause ? " where #{where_clause}" : "")) - end + def count(*query) + inner_query = parse_query *query + value("select count(*) from (#{inner_query}) as inner_query") end - # TODO - # Query variants - # (sql) - simple SQL statement - # (schema = nil, table, id-or-where-clause = nil, field-or-fields) - # - # Return a single value. It is an error if the query doesn't return a - # single record with a single column. If :transaction is true, the query - # will be executed in a transaction and also be committed if :commit is - # true (this is the default). It can also be used to execute 'insert' - # statements with a 'returning' clause - def value(query) #, transaction: false, commit: true) - r = pg_exec(query) + # single record with a single column. + # + # TODO If :transaction is true, the query will be executed in a + # transaction and also be committed if :commit is true (this is the + # default). It can also be used to execute 'insert' statements with a + # 'returning' clause + def value(*query) #, transaction: false, commit: true) + r = pg_exec(parse_query *query) check_1c(r) check_1r(r) r.values[0][0] end # Like #value but returns nil if no record was found. It is still an error # if the query returns more than one column - def value?(query) #, transaction: false, commit: true) - r = pg_exec(query) + def value?(*query) #, transaction: false, commit: true) + r = pg_exec(parse_query *query) check_1c(r) return nil if r.ntuples == 0 check_1r(r) r.values[0][0] end # Return an array of values. It is an error if the query returns records - # with more than one column. If :transaction is true, the query will be - # executed in a transaction and be committed it :commit is true (the - # default). This can be used in 'insert ... returning ...' statements - def values(query) - r = pg_exec(query) + # with more than one column. + # + # TODO If :transaction is true, the query will be executed in a + # transaction and be committed it :commit is true (the default). This can + # be used in 'insert ... returning ...' statements + def values(*query) + r = pg_exec(parse_query *query) check_1c(r) r.column_values(0) end # Return an array of column values. It is an error if the query returns - # more than one record. If :transaction is true, the query will be executed + # more than one record. + # + # TODO If :transaction is true, the query will be executed # in a transaction and be committed it :commit is true (the default). This # can be used in 'insert ... returning ...' statements - def tuple(query) - r = pg_exec(query) + def tuple(*query) + r = pg_exec(parse_query *query) check_1r(r) r.values[0] end # Like #tuple but returns nil if no record was found - def tuple?(query) - r = pg_exec(query) + def tuple?(*query) + r = pg_exec(parse_query *query) return nil if r.ntuples == 0 check_1r(r) r.values[0] end # Return an array of tuples. If :transaction is true, the query will be # executed in a transaction and be committed it :commit is true (the # default). This can be used in 'insert ... returning ...' statements - def tuples(query) - pg_exec(query).values + def tuples(*query) + pg_exec(parse_query *query).values end # Return a single-element hash from column name to value. It is an error # if the query returns more than one record or more than one column. Note - # that you will probably prefer to use #value instead when you expect only - # a single field - def field(query) - r = pg_exec(query) + # that you will probably prefer to use #value instead when you query a + # single field + def field(*query) + r = pg_exec(parse_query *query) check_1c(r) check_1r(r) r.tuple(0).to_h end # Like #field but returns nil if no record was found - def field?(query) - r = pg_exec(query) + def field?(*query) + r = pg_exec(parse_query *query) check_1c(r) return nil if r.ntuples == 0 check_1r(r) r.tuple(0).to_h end # Return an array of single-element hashes from column name to value. It # is an error if the query returns records with more than one column. Note # that you will probably prefer to use #values instead when you expect only # single-column records - def fields(query) - r = pg_exec(query) + def fields(*query) + r = pg_exec(parse_query *query) check_1c(r) r.each.to_a.map(&:to_h) end # Return a hash from column name (a Symbol) to field value. It is an error if # the query returns more than one record. It blows up if a column name is # not a valid ruby symbol - def record(query) - r = pg_exec(query) + def record(*query) + r = pg_exec(parse_query *query) check_1r(r) r.tuple(0).to_h end # Like #record but returns nil if no record was found - def record?(query) - r = pg_exec(query) + def record?(*query) + r = pg_exec(parse_query *query) return nil if r.ntuples == 0 check_1r(r) r.tuple(0).to_h end # Return an array of hashes from column name to field value - def records(query) - r = pg_exec(query) + def records(*query) + r = pg_exec(parse_query *query) r.each.to_a.map(&:to_h) end # Return a record as a OpenStruct object. It is an error if the query # returns more than one record. It blows up if a column name is not a valid # ruby symbol - def struct(query) - OpenStruct.new(**record(query)) + def struct(*query) + OpenStruct.new(**record(parse_query *query)) end # Like #struct but returns nil if no record was found - def struct?(query) - args = record?(query) + def struct?(*query) + args = record?(parse_query *query) return nil if args.nil? OpenStruct.new(**args) end # Return an array of OpenStruct objects - def structs(query) - records(query).map { |record| OpenStruct.new(**record) } + def structs(*query) + records(parse_query *query).map { |record| OpenStruct.new(**record) } end # Return a hash from the record id column to record (hash from column name # to field value) If the :key_column option is defined it will be used # instead of id as the key It is an error if the id field value is not @@ -992,9 +977,38 @@ if array "array[#{literals.join(', ')}]::#{pg_type}[]" else literals.first end + end + + # :call-seq + # parse_query(query) + # parse_query(table, id_or_where_clause = "true", fields = []) + # + # Parse a query. Used in query-functions (#value etc.). The fields argument + # can be a list of fields or arrays of fields + # + def parse_query(*args) + args.size > 0 or raise ArgumentError + return args.first if args.size == 1 && args.first =~ / / + + table = args.shift + where_clause = "true" + fields = [] + case args.first + when Integer; where_clause = "id = #{args.shift}" + when String; where_clause = args.shift + when Symbol; fields << args.shift + when Array; fields = args.shift + when nil; where_clause = "true" + else + raise ArgumentError + end + fields.concat args.flatten + field_list = fields.empty? ? "*" : self.quote_identifiers(fields) + + "select #{field_list} from #{table} where #{where_clause}" end # :call-seq: # pg_exec(string) # pg_exec(array)