Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
BEGIN;

SET ROLE TO postgres;

DROP FUNCTION ticket_state_next(bigint, enum_ticket_type, enum_ticket_state);
CREATE OR REPLACE FUNCTION ticket_state_next(param_project_id bigint, param_ticket_type enum_ticket_type, param_ticket_state enum_ticket_state, param_ticket_id bigint default NULL)
RETURNS TABLE(ticket_state enum_ticket_state, service_executable boolean) AS
$$
DECLARE
BEGIN
RETURN QUERY
SELECT
pts.ticket_state, pts.service_executable
FROM
tbl_ticket_state ts1
JOIN
tbl_project_ticket_state pts ON pts.ticket_type = ts1.ticket_type AND pts.ticket_state = ts1.ticket_state
JOIN
tbl_ticket_state ts2 ON ts1.ticket_type = ts2.ticket_type AND ts1.sort > ts2.sort
WHERE
pts.project_id = param_project_id AND
ts2.ticket_type = param_ticket_type AND
ts2.ticket_state = param_ticket_state AND
(pts.skip_on_dependent = false OR
( /* is master encoding ticket */
SELECT ep.depends_on
FROM tbl_ticket t
JOIN tbl_encoding_profile_version epv ON epv.id = t.encoding_profile_version_id
JOIN tbl_encoding_profile ep ON ep.id = epv.encoding_profile_id
WHERE t.id = param_ticket_id
) IS NULL
)
ORDER BY
ts1.sort ASC
LIMIT 1;
IF NOT FOUND THEN
RETURN QUERY SELECT NULL::enum_ticket_state, false;
END IF;
END
$$
LANGUAGE plpgsql;

DROP FUNCTION ticket_state_previous(bigint, enum_ticket_type, enum_ticket_state);
CREATE OR REPLACE FUNCTION ticket_state_previous(param_project_id bigint, param_ticket_type enum_ticket_type, param_ticket_state enum_ticket_state, param_ticket_id bigint default NULL)
RETURNS TABLE(ticket_state enum_ticket_state, service_executable boolean) AS
$$
DECLARE
BEGIN
RETURN QUERY
SELECT
pts.ticket_state, pts.service_executable
FROM
tbl_ticket_state ts1
JOIN
tbl_project_ticket_state pts ON pts.ticket_type = ts1.ticket_type AND pts.ticket_state = ts1.ticket_state
JOIN
tbl_ticket_state ts2 ON ts1.ticket_type = ts2.ticket_type AND ts1.sort < ts2.sort
WHERE
pts.project_id = param_project_id AND
ts2.ticket_type = param_ticket_type AND
ts2.ticket_state = param_ticket_state AND
(pts.skip_on_dependent = false OR
( /* is master encoding ticket */
SELECT ep.depends_on
FROM tbl_ticket t
JOIN tbl_encoding_profile_version epv ON epv.id = t.encoding_profile_version_id
JOIN tbl_encoding_profile ep ON ep.id = epv.encoding_profile_id
WHERE t.id = param_ticket_id
) IS NULL
)
ORDER BY
ts1.sort DESC
LIMIT 1;
IF NOT FOUND THEN
RETURN QUERY SELECT NULL::enum_ticket_state, false;
END IF;
END
$$
LANGUAGE plpgsql;

DROP FUNCTION ticket_state_commence(bigint, enum_ticket_type);
CREATE OR REPLACE FUNCTION ticket_state_commence(param_project_id bigint, param_ticket_type enum_ticket_type, param_ticket_id bigint)
RETURNS enum_ticket_state AS
$$
DECLARE
ret enum_ticket_state;
next_state record;
BEGIN
-- special case: meta ticket, since it has no serviceable states
IF param_ticket_type = 'meta' THEN
RETURN 'staged'::enum_ticket_state;
END IF;

ret := (SELECT ticket_state_initial(param_project_id, param_ticket_type));

WHILE ret IS NOT NULL LOOP
SELECT * INTO next_state FROM ticket_state_next(param_project_id, param_ticket_type, ret, param_ticket_id);
IF NOT FOUND THEN
ret := NULL;
EXIT;
END IF;

-- exit, if serviceable state is found
EXIT WHEN next_state.service_executable IS TRUE;

-- otherwise set current state as possible commence state
ret := next_state.ticket_state;
END LOOP;

RETURN ret;
END
$$
LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION update_ticket_next_state()
RETURNS trigger AS
$BODY$
DECLARE
next_state record;
BEGIN
next_state := ticket_state_next(NEW.project_id, NEW.ticket_type, NEW.ticket_state, NEW.id);

NEW.ticket_state_next := next_state.ticket_state;
NEW.service_executable := next_state.service_executable;

RETURN NEW;
END
$BODY$
LANGUAGE plpgsql VOLATILE;

CREATE OR REPLACE FUNCTION update_all_tickets_progress_and_next_state(param_project_id bigint)
RETURNS VOID AS
$BODY$
BEGIN

UPDATE tbl_ticket t SET
(progress, ticket_state_next, service_executable)
= (tp, (n).ticket_state, (n).service_executable)
FROM (
SELECT id, ticket_state_next(t2.project_id, t2.ticket_type, t2.ticket_state, t2.id) AS n, ticket_progress(t2.id) as tp
FROM tbl_ticket t2
WHERE t2.project_id = param_project_id AND param_project_id IS NOT NULL
) AS x
WHERE t.id = x.id;

END;
$BODY$
LANGUAGE plpgsql VOLATILE;

ALTER TABLE tbl_project_ticket_state ADD COLUMN skip_on_dependent BOOLEAN NOT NULL DEFAULT FALSE;

COMMIT;
2 changes: 1 addition & 1 deletion src/Application/Controller/XMLRPC/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ public function setCommenceTicketState($ticket_id) {
throw new Exception(__FUNCTION__.': ticket is not in initial state!',1304);
}

$commenceState = ProjectTicketState::getCommenceState($ticket['project_id'], $ticket['ticket_type']);
$commenceState = ProjectTicketState::getCommenceState($ticket['project_id'], $ticket['ticket_type'], $ticket_id);
if(!$commenceState) {
throw new Exception(__FUNCTION__.': ticket has no commence state!',1305);
}
Expand Down
1 change: 1 addition & 0 deletions src/Application/Migrations/04_projects.sql
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ CREATE TABLE tbl_project_ticket_state
ticket_type enum_ticket_type NOT NULL,
ticket_state enum_ticket_state NOT NULL,
service_executable boolean NOT NULL DEFAULT false,
skip_on_dependent boolean NOT NULL DEFAULT false,
CONSTRAINT tbl_project_ticket_state_pk PRIMARY KEY (project_id, ticket_type, ticket_state),
CONSTRAINT tbl_project_ticket_state_project_fk FOREIGN KEY (project_id)
REFERENCES tbl_project (id) MATCH SIMPLE
Expand Down
4 changes: 2 additions & 2 deletions src/Application/Migrations/06_tickets.sql
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ $BODY$
DECLARE
next_state record;
BEGIN
next_state := ticket_state_next(NEW.project_id, NEW.ticket_type, NEW.ticket_state);
next_state := ticket_state_next(NEW.project_id, NEW.ticket_type, NEW.ticket_state, NEW.id);

NEW.ticket_state_next := next_state.ticket_state;
NEW.service_executable := next_state.service_executable;
Expand Down Expand Up @@ -76,7 +76,7 @@ $BODY$
(progress, ticket_state_next, service_executable)
= (tp, (n).ticket_state, (n).service_executable)
FROM (
SELECT id, ticket_state_next(t2.project_id, t2.ticket_type, t2.ticket_state) AS n, ticket_progress(t2.id) as tp
SELECT id, ticket_state_next(t2.project_id, t2.ticket_type, t2.ticket_state, t2.id) AS n, ticket_progress(t2.id) as tp
FROM tbl_ticket t2
WHERE t2.project_id = param_project_id AND param_project_id IS NOT NULL
) AS x
Expand Down
30 changes: 24 additions & 6 deletions src/Application/Migrations/15_function_ticket_state.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ BEGIN;

SET ROLE TO postgres;

CREATE OR REPLACE FUNCTION ticket_state_next(param_project_id bigint, param_ticket_type enum_ticket_type, param_ticket_state enum_ticket_state)
CREATE OR REPLACE FUNCTION ticket_state_next(param_project_id bigint, param_ticket_type enum_ticket_type, param_ticket_state enum_ticket_state, param_ticket_id bigint default NULL)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mh, not really convinced having that extra parameter is a good idea.
Before this change, the function was generic, independent of a specific ticket, hence all the parameters to answer the question at hand. But now it's for a single ticket, so you could go ahead and just have ticket_id as only parameter, since all the other information is stored in the database as well.

Copy link
Member Author

@jjeising jjeising Apr 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mh, not really convinced having that extra parameter is a good idea.

What do you suggest? Moving to ticket_id as only parameter or switching to encoding_profile_[version_]_id?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both would work. I don't have a strong opinion on this.
Are there any callers, where no ticket_id is available or hard to determine?
I'm all for simplifying, if possible.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should behave the same way as the old function when calling, without ticket_id, but we should check that again.

RETURNS TABLE(ticket_state enum_ticket_state, service_executable boolean) AS
$$
DECLARE
Expand All @@ -19,7 +19,16 @@ BEGIN
WHERE
pts.project_id = param_project_id AND
ts2.ticket_type = param_ticket_type AND
ts2.ticket_state = param_ticket_state
ts2.ticket_state = param_ticket_state AND
(pts.skip_on_dependent = false OR
( /* is master encoding ticket */
SELECT ep.depends_on
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like with other properties before, for performance improvements a column "is_master" in tbl_ticket filled on INSERT e.g. using a trigger might be useful.

FROM tbl_ticket t
JOIN tbl_encoding_profile_version epv ON epv.id = t.encoding_profile_version_id
JOIN tbl_encoding_profile ep ON ep.id = epv.encoding_profile_id
WHERE t.id = param_ticket_id
) IS NULL
)
ORDER BY
ts1.sort ASC
LIMIT 1;
Expand All @@ -30,7 +39,7 @@ END
$$
LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION ticket_state_previous(param_project_id bigint, param_ticket_type enum_ticket_type, param_ticket_state enum_ticket_state)
CREATE OR REPLACE FUNCTION ticket_state_previous(param_project_id bigint, param_ticket_type enum_ticket_type, param_ticket_state enum_ticket_state, param_ticket_id bigint default NULL)
RETURNS TABLE(ticket_state enum_ticket_state, service_executable boolean) AS
$$
DECLARE
Expand All @@ -47,7 +56,16 @@ BEGIN
WHERE
pts.project_id = param_project_id AND
ts2.ticket_type = param_ticket_type AND
ts2.ticket_state = param_ticket_state
ts2.ticket_state = param_ticket_state AND
(pts.skip_on_dependent = false OR
( /* is master encoding ticket */
SELECT ep.depends_on
FROM tbl_ticket t
JOIN tbl_encoding_profile_version epv ON epv.id = t.encoding_profile_version_id
JOIN tbl_encoding_profile ep ON ep.id = epv.encoding_profile_id
WHERE t.id = param_ticket_id
) IS NULL
)
ORDER BY
ts1.sort DESC
LIMIT 1;
Expand Down Expand Up @@ -96,7 +114,7 @@ END
$$
LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION ticket_state_commence(param_project_id bigint, param_ticket_type enum_ticket_type)
CREATE OR REPLACE FUNCTION ticket_state_commence(param_project_id bigint, param_ticket_type enum_ticket_type, param_ticket_id bigint)
RETURNS enum_ticket_state AS
$$
DECLARE
Expand All @@ -111,7 +129,7 @@ BEGIN
ret := (SELECT ticket_state_initial(param_project_id, param_ticket_type));

WHILE ret IS NOT NULL LOOP
SELECT * INTO next_state FROM ticket_state_next(param_project_id, param_ticket_type, ret);
SELECT * INTO next_state FROM ticket_state_next(param_project_id, param_ticket_type, ret, param_ticket_id);
IF NOT FOUND THEN
ret := NULL;
EXIT;
Expand Down
18 changes: 9 additions & 9 deletions src/Application/Model/ProjectTicketState.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,30 @@ class ProjectTicketState extends Model {
];

// TODO: use Ticket::queryNextState / queryPreviousState?
public static function getNextState($project, $type, $state) {
public static function getNextState($project, $type, $state, $ticket) {
$handle = Database::$Instance->query(
'SELECT * FROM ticket_state_next(?, ?, ?)',
[$project, $type, $state]
'SELECT * FROM ticket_state_next(?, ?, ?, ?)',
[$project, $type, $state, $ticket]
);
$row = $handle->fetch();

return ($row === false)? null : $row;
}

public static function getPreviousState($project, $type, $state) {
public static function getPreviousState($project, $type, $state, $ticket) {
$handle = Database::$Instance->query(
'SELECT * FROM ticket_state_previous(?, ?, ?)',
[$project, $type, $state]
'SELECT * FROM ticket_state_previous(?, ?, ?, ?)',
[$project, $type, $state, $ticket]
);

$row = $handle->fetch();
return ($row === false)? null : $row;
}

public static function getCommenceState($project, $type) {
public static function getCommenceState($project, $type, $ticket) {
$handle = Database::$Instance->query(
'SELECT ticket_state_commence(?, ?)',
[$project, $type]
'SELECT ticket_state_commence(?, ?, ?)',
[$project, $type, $ticket]
);

return $handle->fetch()['ticket_state_commence'];
Expand Down
12 changes: 7 additions & 5 deletions src/Application/Model/Ticket.php
Original file line number Diff line number Diff line change
Expand Up @@ -855,12 +855,13 @@ public function queryPreviousState($state = null) {
return (new Database_Query(''))
->select('ticket_state')
->from(
'ticket_state_previous(?, ?, ?)',
'ticket_state_previous(?, ?, ?, ?)',
'previous_state',
[
$this['project_id'],
$this['ticket_type'],
($state === null)? $this['ticket_state'] : $state
($state === null)? $this['ticket_state'] : $state,
$this['id']
]
);
}
Expand All @@ -869,16 +870,17 @@ public function queryNextState($state = null) {
return (new Database_Query(''))
->select('ticket_state')
->from(
'ticket_state_next(?, ?, ?)',
'ticket_state_next(?, ?, ?, ?)',
'next_state',
[
$this['project_id'],
$this['ticket_type'],
($state === null)? $this['ticket_state'] : $state
($state === null)? $this['ticket_state'] : $state,
$this['id']
]
);
}

public function findNextForAction($state) {
$next = null;

Expand Down
9 changes: 8 additions & 1 deletion src/Application/Model/TicketState.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ class TicketState extends Model {
public $hasOne = [
'ProjectTicketState' => [
'foreign_key' => ['ticket_type', 'ticket_state'],
'select' => '(ticket_state IS NOT NULL) AS project_enabled, service_executable AS project_service_executable'
'select' => '(ticket_state IS NOT NULL) AS project_enabled,' .
'service_executable AS project_service_executable,' .
'skip_on_dependent AS project_skip_on_dependent'
]
];

Expand All @@ -31,6 +33,11 @@ public static function getStateByAction($action) {

return self::$_actions[$action];
}

public static function isSkippable($state) {
return ($state === 'postencoded' ||
$state === 'checking');
}

public function defaultScope(Model_Resource $resource) {
$resource->orderBy('ticket_type, sort');
Expand Down
Loading