pg-xml 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c7fafbeb6bb53498ffc42dd1efe5d683c451a28c
4
+ data.tar.gz: cf61d5ecfe41b83d6835cd251152b2551403747a
5
+ SHA512:
6
+ metadata.gz: de4899da7e8003a8b68fdad57419f9d8a2049ba5c579bc270aa0447570db23c4741d2618637970959ef7aa6c93f26e5afefae83da8d641bed56aec706b01da60
7
+ data.tar.gz: c44359eba77634a371d44f581b652d6a6f0b5772b511327a54251e1bc5887c9e87a25b13a3509a9ae1f3f455286e266b3af1eec1f911f8c245afaf0406140f7f
@@ -0,0 +1,85 @@
1
+ # use, e.g.,
2
+ # has_xml_column :properties
3
+ # in your ActiveRecord model
4
+
5
+ # in a migration, use e.g.
6
+ # add_xpath_index :users, :properties, '/xml/first_name'
7
+ # to index into the XML
8
+
9
+ module ActiveRecord
10
+
11
+ class Base
12
+
13
+ # define the has_xml_column :col_name name
14
+ def self.has_xml_column attr_name
15
+
16
+ # serialize using the custom serializer
17
+ serialize attr_name, ActiveRecord::Coders::XML
18
+ # validate XML before saving
19
+ validate "validate_#{attr_name}_xml"
20
+
21
+ # define the attribute writer to accept a string
22
+ # and convert it to XML
23
+ define_method("#{attr_name}=") do |val|
24
+ if val.is_a? String
25
+ val = PgXML.load(val)
26
+ end
27
+ self[attr_name] = val
28
+ end
29
+
30
+ # validate XML before writing to database
31
+ define_method("validate_#{attr_name}_xml") do
32
+ # TODO make this work with hpricot
33
+ return true if self[attr_name].nil? || self[attr_name].errors == []
34
+ self[attr_name].errors.each do |e|
35
+ errors.add(attr_name, e.to_s)
36
+ end
37
+ return false
38
+ end
39
+
40
+ end
41
+ end
42
+
43
+ # support the add_xpath_index and make it reversible
44
+ module ConnectionAdapters
45
+ module SchemaStatements
46
+
47
+ # enable adding an xpath index
48
+ def add_xpath_index table_name, column_name, path, index_name=nil
49
+ # generate an index name
50
+ index_name ||= "index_#{table_name}_on_#{column_name}__#{path}"
51
+ index_name = index_name.downcase.gsub(/[^a-z0-9]/, '_')
52
+
53
+ # create the index
54
+ execute "CREATE INDEX #{index_name} ON #{table_name}(xpath('#{path}',#{column_name}))"
55
+ end
56
+
57
+
58
+ # can call in any of the following ways
59
+ # remove_xpath_index :users, :properties, '/xml/name'
60
+ # remove_xpath_index :index_users_on_properties__xml_name
61
+ # remove_xpath_index :users, :properties, '/xml/name', :index_users_on_properties__xml_name
62
+ def remove_xpath_index index_name_or_table_name, column_name=nil, path=nil, index_name=nil
63
+ # figure out which version was called
64
+ index_name = index_name_or_table_name if !column_name
65
+
66
+ # transform index name
67
+ index_name ||= "index_#{table_name}_on_#{column_name}__#{path}"
68
+ index_name = index_name.downcase.gsub(/[^a-z0-9]/, '_')
69
+
70
+ # drop the index
71
+ execute "DROP INDEX #{index_name}"
72
+ end
73
+
74
+ # TODO this doesn't get called -- why?
75
+ # adding the xpath index should be reversible
76
+ def invert_add_xpath_index(args)
77
+ # table_name, column_name, path, index_name = *args
78
+ # [:remove_index, [table_name, column_name, path, index_name]]
79
+ [:remove_xpath_index, args]
80
+ end
81
+
82
+ end
83
+ end
84
+
85
+ end
@@ -0,0 +1,28 @@
1
+ module ActiveRecord
2
+ module Coders
3
+ class XML
4
+
5
+ def self.load(xml_string)
6
+ new(PgXML.default).load(xml_string)
7
+ end
8
+
9
+ def self.dump(xml_document)
10
+ new(PgXML.default).dump(xml_document)
11
+ end
12
+
13
+ def initialize(default=nil)
14
+ @default=default
15
+ end
16
+
17
+ def dump(xml_document)
18
+ (xml_document.nil? && @default.nil?) ? nil : PgXML.dump( xml_document || @default )
19
+ end
20
+
21
+ def load(xml_string)
22
+ xml_string.nil? ? @default : PgXML.load(xml_string)
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,38 @@
1
+ # note: none of this is tested against Hpricot
2
+ # the goal was to allow either hpricot or nokogiri, but
3
+ # support for "using either" is half-assed at best
4
+
5
+ module PgXML
6
+
7
+ # complex line of code determining whether we have access to nokogiri or hpricot.
8
+ XML_PARSER_TYPE = ( require('nokogiri') || true rescue # evaluates to true if we have nokogiri
9
+ require('hpricot') && false rescue # evaluates to valse if we have hpricot
10
+ raise LoadError, "Either nokogiri or hpricot is required" # raises an error if we have neither
11
+ ) ? :nokogiri : :hpricot
12
+
13
+ # get which XML parser we are using
14
+ def self.parser_type
15
+ XML_PARSER_TYPE
16
+ end
17
+
18
+ def self.load xml_str
19
+ parse xml_str
20
+ end
21
+
22
+ def self.dump xml_document
23
+ xml_document.to_s
24
+ end
25
+
26
+ # Valid xml requires a root node.
27
+ def self.default
28
+ parse '<xml></xml>'
29
+ end
30
+
31
+ # use our parser to create an XML document
32
+ # warning: nokogiri is friendly -- if you feed it invalid XML it will fail silently
33
+ # Nokogiri::XML.parse('<xml><xml>').to_s ~> <xml><xml/></xml>
34
+ def self.parse xml_str
35
+ XML_PARSER_TYPE == :nokogiri ? Nokogiri::XML.parse(xml_str) : Hpricot(xml_str)
36
+ end
37
+
38
+ end
data/lib/pg-xml.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'active_support'
2
+
3
+ # ActiveSupport.on_load :active_record do
4
+ require "pg-xml/pg_xml"
5
+ require "pg-xml/coder"
6
+ require "pg-xml/activerecord"
7
+ # end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pg-xml
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kai Stinchcombe
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pg
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: postgresql xml datatype support for activerecord -- heavily based on
28
+ pg-hstore and activerecord-postgres-hstore
29
+ email:
30
+ - k@i.stinchcom.be
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - lib/pg-xml.rb
36
+ - lib/pg-xml/activerecord.rb
37
+ - lib/pg-xml/coder.rb
38
+ - lib/pg-xml/pg_xml.rb
39
+ homepage:
40
+ licenses: []
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ - lib/pg-xml
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.0.3
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: postgresql xml datatype support for activerecord -- heavily based on pg-hstore
63
+ and activerecord-postgres-hstore
64
+ test_files: []