Class: Tilia::Dav::PropertyStorage::Backend::Sequel

Inherits:
Object
  • Object
show all
Includes:
BackendInterface
Defined in:
lib/tilia/dav/property_storage/backend/sequel.rb

Overview

PropertyStorage PDO backend.

This backend class uses a PDO-enabled database to store webdav properties. Both sqlite and mysql have been tested.

The database structure can be found in the examples/sql/ directory.

Constant Summary collapse

VT_STRING =

Value is stored as string.

1
VT_XML =

Value is stored as XML fragment.

2
VT_OBJECT =

Value is stored as a property object.

3

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sequel) ⇒ Sequel

Creates the PDO property storage engine

Parameters:

  • Sequel

    sequel



42
43
44
45
# File 'lib/tilia/dav/property_storage/backend/sequel.rb', line 42

def initialize(sequel)
  @sequel = sequel
  @table_name = 'propertystorage'
end

Instance Attribute Details

#table_nameObject

PDO table name we’ll be using



37
38
39
# File 'lib/tilia/dav/property_storage/backend/sequel.rb', line 37

def table_name
  @table_name
end

Instance Method Details

#delete(path) ⇒ Object

This method is called after a node is deleted.

This allows a backend to clean up all associated properties.

The delete method will get called once for the deletion of an entire tree.

Parameters:

  • string

    path

Returns:

  • void



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/tilia/dav/property_storage/backend/sequel.rb', line 140

def delete(path)
  child_path = path.gsub(
    /[=%_]/,
    '=' => '==',
    '%' => '=%',
    '_' => '=_'
  )
  child_path << '/%'
  delete_ds = @sequel[
    "DELETE FROM #{@table_name} WHERE path = ? OR path LIKE ? ESCAPE '='",
    path,
    child_path
  ]
  delete_ds.delete
end

#move(source, destination) ⇒ Object

This method is called after a successful MOVE

This should be used to migrate all properties from one path to another. Note that entire collections may be moved, so ensure that all properties for children are also moved along.

Parameters:

  • string

    source

  • string

    destination

Returns:

  • void



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/tilia/dav/property_storage/backend/sequel.rb', line 165

def move(source, destination)
  # I don't know a way to write this all in a single sql query that's
  # also compatible across db engines, so we're letting PHP do all the
  # updates. Much slower, but it should still be pretty fast in most
  # cases.
  update = "UPDATE #{table_name} SET path = ? WHERE id = ?"
  @sequel.fetch("SELECT id, path FROM #{@table_name} WHERE path = ? OR path LIKE ?", source, "#{source}/%") do |row|
    # Sanity check. SQL may select too many records, such as records
    # with different cases.
    next if row[:path] != source && row[:path].index("#{source}/") != 0

    trailing_part = row[:path][source.size + 1..-1]
    new_path = destination
    new_path << "/#{trailing_part}" unless trailing_part.blank?

    update_ds = @sequel[
      update,
      new_path,
      row[:id]
    ]
    update_ds.update
  end
end

#prop_find(path, prop_find) ⇒ Object

Fetches properties for a path.

This method received a PropFind object, which contains all the information about the properties that need to be fetched.

Ususually you would just want to call ‘get404Properties’ on this object, as this will give you the exact list of properties that need to be fetched, and haven’t yet.

However, you can also support the ‘allprops’ property here. In that case, you should check for prop_find.all_props?.

Parameters:

  • string

    path

  • PropFind

    prop_find

Returns:

  • void



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/tilia/dav/property_storage/backend/sequel.rb', line 62

def prop_find(path, prop_find)
  if !prop_find.all_props? && prop_find.load_404_properties.size == 0
    return
  end

  @sequel.fetch("SELECT name, value, valuetype FROM #{@table_name} WHERE path = ?", path) do |row|
    case row[:valuetype]
    when nil, VT_STRING
      prop_find.set(row[:name], row[:value])
    when VT_XML
      prop_find.set(row[:name], Xml::Property::Complex.new(row[:value]))
    when VT_OBJECT
      prop_find.set(row[:name], YAML.load(row[:value]))
    end
  end
end

#prop_patch(path, prop_patch) ⇒ Object

Updates properties for a path

This method received a PropPatch object, which contains all the information about the update.

Usually you would want to call ‘handleRemaining’ on this object, to get a list of all properties that need to be stored.

Parameters:

  • string

    path

  • PropPatch

    prop_patch

Returns:

  • void



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/tilia/dav/property_storage/backend/sequel.rb', line 90

def prop_patch(path, prop_patch)
  prop_patch.handle_remaining(
    lambda do |properties|
      update_stmt = "REPLACE INTO #{@table_name} (path, name, valuetype, value) VALUES (?, ?, ?, ?)"
      delete_stmt = "DELETE FROM #{@table_name} WHERE path = ? AND name = ?"

      properties.each do |name, value|
        if !value.nil?
          if value.scalar?
            value_type = VT_STRING
          elsif value.is_a?(Xml::Property::Complex)
            value_type = VT_XML
            value = value.xml
          else
            value_type = VT_OBJECT
            value = YAML.dump(value)
          end

          update_ds = @sequel[
            update_stmt,
            path,
            name,
            value_type,
            value
          ]
          update_ds.update
        else
          delete_ds = @sequel[
            delete_stmt,
            path,
            name
          ]
          delete_ds.delete
        end
      end

      true
    end
  )
end