Class: RubynCode::Tasks::Manager

Inherits:
Object
  • Object
show all
Defined in:
lib/rubyn_code/tasks/manager.rb

Overview

CRUD manager for tasks backed by SQLite.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(db) ⇒ Manager

Returns a new instance of Manager.

Parameters:



14
15
16
17
18
# File 'lib/rubyn_code/tasks/manager.rb', line 14

def initialize(db)
  @db = db
  ensure_table
  @dag = DAG.new(db)
end

Instance Attribute Details

#dbObject (readonly)

Returns the value of attribute db.



11
12
13
# File 'lib/rubyn_code/tasks/manager.rb', line 11

def db
  @db
end

Instance Method Details

#claim(id, owner:) ⇒ Task

Claims a task by setting the owner and moving it to in_progress.

Parameters:

  • id (String)
  • owner (String)

Returns:



101
102
103
104
105
106
107
108
# File 'lib/rubyn_code/tasks/manager.rb', line 101

def claim(id, owner:)
  @db.execute(
    "UPDATE tasks SET owner = ?, status = 'in_progress', updated_at = datetime('now') WHERE id = ?",
    [owner, id]
  )

  get(id)
end

#complete(id, result: nil) ⇒ Task

Marks a task as completed and cascades unblocking via the DAG.

Parameters:

  • id (String)
  • result (String, nil) (defaults to: nil)

Returns:



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rubyn_code/tasks/manager.rb', line 75

def complete(id, result: nil)
  sets = ["status = 'completed'", "updated_at = datetime('now')"]
  values = []

  if result
    sets << 'result = ?'
    values << result
  end

  values << id

  @db.execute(
    "UPDATE tasks SET #{sets.join(', ')} WHERE id = ?",
    values
  )

  @dag.unblock_cascade(id)

  get(id)
end

#create(title:, description: nil, session_id: nil, blocked_by: [], priority: 0) ⇒ Task

Creates a new task and persists it.

Parameters:

  • title (String)
  • description (String, nil) (defaults to: nil)
  • session_id (String, nil) (defaults to: nil)
  • blocked_by (Array<String>) (defaults to: [])

    IDs of tasks this one depends on

  • priority (Integer) (defaults to: 0)

Returns:



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/rubyn_code/tasks/manager.rb', line 28

def create(title:, description: nil, session_id: nil, blocked_by: [], priority: 0)
  id = SecureRandom.uuid
  now = Time.now.utc.strftime('%Y-%m-%d %H:%M:%S')
  status = blocked_by.empty? ? 'pending' : 'blocked'

  @db.transaction do
    @db.execute(<<~SQL, [id, session_id, title, description, status, priority, now, now])
      INSERT INTO tasks (id, session_id, title, description, status, priority, created_at, updated_at)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    SQL

    blocked_by.each do |dep_id|
      @dag.add_dependency(id, dep_id)
    end
  end

  get(id)
end

#delete(id) ⇒ void

This method returns an undefined value.

Deletes a task and its dependency edges (via CASCADE).

Parameters:

  • id (String)


161
162
163
# File 'lib/rubyn_code/tasks/manager.rb', line 161

def delete(id)
  @db.execute('DELETE FROM tasks WHERE id = ?', [id])
end

#get(id) ⇒ Task?

Fetches a single task by ID.

Parameters:

  • id (String)

Returns:



114
115
116
117
# File 'lib/rubyn_code/tasks/manager.rb', line 114

def get(id)
  rows = @db.query('SELECT * FROM tasks WHERE id = ?', [id]).to_a
  row_to_task(rows.first)
end

#list(status: nil, session_id: nil) ⇒ Array<Task>

Lists tasks with optional filters.

Parameters:

  • status (String, nil) (defaults to: nil)
  • session_id (String, nil) (defaults to: nil)

Returns:



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/rubyn_code/tasks/manager.rb', line 124

def list(status: nil, session_id: nil)
  conditions = []
  params = []

  if status
    conditions << 'status = ?'
    params << status
  end

  if session_id
    conditions << 'session_id = ?'
    params << session_id
  end

  sql = 'SELECT * FROM tasks'
  sql += " WHERE #{conditions.join(' AND ')}" unless conditions.empty?
  sql += ' ORDER BY priority DESC, created_at ASC'

  @db.query(sql, params).to_a.filter_map { |row| row_to_task(row) }
end

#ready_tasksArray<Task>

Returns tasks that are pending, unowned, and have no unmet dependencies.

Returns:



148
149
150
151
152
153
154
155
# File 'lib/rubyn_code/tasks/manager.rb', line 148

def ready_tasks
  rows = @db.query(
    "SELECT * FROM tasks WHERE status = 'pending' AND owner IS NULL ORDER BY priority DESC, created_at ASC"
  ).to_a

  rows.filter_map { |row| row_to_task(row) }
      .reject { |task| @dag.blocked?(task.id) }
end

#update(id, **attrs) ⇒ Task

Updates arbitrary attributes on a task.

Parameters:

  • id (String)
  • attrs (Hash)

    supported keys: status, priority, owner, result, description, title, metadata

Returns:



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rubyn_code/tasks/manager.rb', line 52

def update(id, **attrs)
  allowed = %i[status priority owner result description title metadata]
  filtered = attrs.slice(*allowed)
  return get(id) if filtered.empty?

  sets = filtered.map { |k, _| "#{k} = ?" }
  sets << "updated_at = datetime('now')"
  values = filtered.values
  values << id

  @db.execute(
    "UPDATE tasks SET #{sets.join(', ')} WHERE id = ?",
    values
  )

  get(id)
end