Class: Tagm::Db

Inherits:
Object
  • Object
show all
Defined in:
lib/tagm/db.rb

Overview

rubocop:disable Metrics/ClassLength

Class Method Summary collapse

Class Method Details

.create_database!Object

rubocop:disable Metrics/MethodLength



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/tagm/db.rb', line 140

def create_database! # rubocop:disable Metrics/MethodLength
  db.execute_batch "    CREATE TABLE IF NOT EXISTS tags (\n      id INTEGER PRIMARY KEY AUTOINCREMENT,\n      name VARCHAR(30)\n    );\n    CREATE TABLE IF NOT EXISTS paths (\n      id INTEGER PRIMARY KEY AUTOINCREMENT,\n      path TEXT\n    );\n    CREATE TABLE IF NOT EXISTS paths_tags (\n      path_id INTEGER,\n      tag_id INTEGER,\n      FOREIGN KEY(path_id) REFERENCES paths(id),\n      FOREIGN KEY(tag_id) REFERENCES tags(id)\n    );\n  SQL\nend\n"

.dbObject



12
13
14
# File 'lib/tagm/db.rb', line 12

def db
  @db ||= SQLite3::Database.new Config.db_path
end

.list(*tags) ⇒ Hash

List nodes with tags

Parameters:

  • tags (Array<String>)

    List of tags for the filter

Returns:

  • (Hash)

    Hash with path as keys and tags list as value



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/tagm/db.rb', line 113

def list(*tags) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
  tags = sanitize_tags(tags)

  sql = "    SELECT paths.path, tags.name\n    FROM paths, tags\n    INNER JOIN paths_tags pt on paths.id = pt.path_id AND tags.id = pt.tag_id\n  SQL\n  sql += \"WHERE tags.name IN (\#{query_placeholders(tags)})\" unless tags.empty?\n  sql += 'ORDER BY tags.name'\n\n  results = if tags.empty?\n              db.execute sql\n            else\n              db.execute sql, [tags]\n            end\n\n  # { <path>: [<tags>] }\n  paths = {}\n  results.each do |l|\n    paths[l[0]] ||= []\n    paths[l[0]] << l[1]\n  end\n\n  paths\nend\n"

.merge(from:, into:) ⇒ nil

Merge tags

Parameters:

  • from (Array<String>)

    List of tags to be merged

  • into (String)

    Target tag

Returns:

  • (nil)


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/tagm/db.rb', line 61

def merge(from:, into:) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
  into = sanitize_tag(into)
  # Don't sanitize "from" to allow work on previously malformed tags
  from = [from] unless from.is_a? Array

  raise 'Cannot merge into itself' if from.include? into

  into = find_tag(into) # Will create target if missing

  # Merge tags
  from_ids = db.execute("SELECT id FROM tags WHERE name IN (#{query_placeholders(from)})", from).flatten
  db.execute "UPDATE paths_tags SET tag_id= ? WHERE tag_id IN (#{query_placeholders(from_ids)})",
             [into[:id]] + from_ids

  # Remove duplicate entries
  dupes = db.execute "    SELECT path_id, tag_id, count(*)\n    FROM paths_tags\n    GROUP BY path_id, tag_id\n    HAVING count(*) > 1\n  SQL\n\n  sql = dupes.map do |(path_id, tag_id)|\n    <<~SQL\n      DELETE FROM paths_tags WHERE path_id=\#{path_id} AND tag_id=\#{tag_id};\n      INSERT INTO paths_tags (path_id, tag_id) VALUES (\#{path_id}, \#{tag_id});\n    SQL\n  end\n\n  db.execute_batch sql.join\nend\n"

.show(node) ⇒ Array<String>

Show tags on a node

Parameters:

  • node (String)

    Node to check

Returns:

  • (Array<String>)

    Tags associated to the node



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/tagm/db.rb', line 97

def show(node)
  path = find_path node, create: false

  return nil unless path

  pt = db.execute "    SELECT tags.name FROM tags INNER JOIN paths_tags pt on tags.id = pt.tag_id AND pt.path_id = ? ORDER BY tags.name\n  SQL\n\n  pt.flatten\nend\n", path[:id]

.tag(node:, tags:) ⇒ nil

Tags a node

Parameters:

  • node (String)

    Node to tag

  • tags (Array<String>)

    Tags to apply

Returns:

  • (nil)


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/tagm/db.rb', line 22

def tag(node:, tags:)
  tags = sanitize_tags(tags).uniq

  path = find_path node
  existing = show(node) || []

  tags_to_create = tags - existing
  return if tags_to_create.empty?

  sql_inserts = tags_to_create.map do |t|
    tag = find_tag t
    "(#{path[:id]}, #{tag[:id]})"
  end.join(', ')

  db.execute "INSERT INTO paths_tags (path_id, tag_id) VALUES #{sql_inserts};"
end

.untag(node:, tags:) ⇒ nil

Remove tags from a node

Parameters:

  • node (String)

    Node to tag

  • tags (Array<String>)

    Tags to remove

Returns:

  • (nil)


45
46
47
48
49
50
51
52
53
# File 'lib/tagm/db.rb', line 45

def untag(node:, tags:)
  tags = sanitize_tags(tags)
  node = find_path node

  tags = find_tags(tags).map { |t| t[:id] }

  placeholders = Array.new(tags.length) { '?' }.join(', ')
  db.execute "DELETE from paths_tags WHERE path_id=? AND tag_id IN (#{placeholders})", [node[:id]] + tags
end