@trafficgroup/knex-rel 0.1.8 → 0.1.9
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.
- package/dist/dao/VideoMinuteResultDAO.d.ts +3 -0
- package/dist/dao/VideoMinuteResultDAO.js +5 -2
- package/dist/dao/VideoMinuteResultDAO.js.map +1 -1
- package/dist/dao/camera/camera.dao.d.ts +17 -7
- package/dist/dao/camera/camera.dao.js +33 -48
- package/dist/dao/camera/camera.dao.js.map +1 -1
- package/dist/dao/folder/folder.dao.js +2 -1
- package/dist/dao/folder/folder.dao.js.map +1 -1
- package/dist/dao/location/location.dao.d.ts +17 -0
- package/dist/dao/location/location.dao.js +123 -0
- package/dist/dao/location/location.dao.js.map +1 -0
- package/dist/dao/study/study.dao.d.ts +1 -1
- package/dist/dao/study/study.dao.js +10 -10
- package/dist/dao/study/study.dao.js.map +1 -1
- package/dist/dao/video/video.dao.d.ts +7 -0
- package/dist/dao/video/video.dao.js +33 -1
- package/dist/dao/video/video.dao.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/camera/camera.interfaces.d.ts +4 -2
- package/dist/interfaces/location/location.interfaces.d.ts +9 -0
- package/dist/interfaces/location/location.interfaces.js +3 -0
- package/dist/interfaces/location/location.interfaces.js.map +1 -0
- package/dist/interfaces/study/study.interfaces.d.ts +4 -3
- package/dist/interfaces/video/video.interfaces.d.ts +1 -0
- package/migrations/20251112120000_migration.ts +89 -0
- package/migrations/20251112120100_migration.ts +21 -0
- package/migrations/20251112120200_migration.ts +50 -0
- package/migrations/20251112120300_migration.ts +27 -0
- package/package.json +1 -1
- package/src/dao/VideoMinuteResultDAO.ts +7 -2
- package/src/dao/camera/camera.dao.ts +44 -61
- package/src/dao/folder/folder.dao.ts +7 -1
- package/src/dao/location/location.dao.ts +123 -0
- package/src/dao/study/study.dao.ts +10 -10
- package/src/dao/video/video.dao.ts +45 -1
- package/src/index.ts +2 -0
- package/src/interfaces/camera/camera.interfaces.ts +4 -2
- package/src/interfaces/location/location.interfaces.ts +9 -0
- package/src/interfaces/study/study.interfaces.ts +4 -3
- package/src/interfaces/video/video.interfaces.ts +1 -0
- package/plan.md +0 -684
|
@@ -70,7 +70,8 @@ class VideoDAO {
|
|
|
70
70
|
const offset = (page - 1) * limit;
|
|
71
71
|
const query = this._knex("video as v")
|
|
72
72
|
.innerJoin("folders as f", "v.folderId", "f.id")
|
|
73
|
-
.
|
|
73
|
+
.leftJoin("cameras as c", "v.cameraId", "c.id")
|
|
74
|
+
.select("v.*", this._knex.raw("to_jsonb(f.*) as folder"), "c.name as cameraName", "c.uuid as cameraUuid");
|
|
74
75
|
if (folderId !== undefined && folderId !== null) {
|
|
75
76
|
query.where("v.folderId", folderId);
|
|
76
77
|
}
|
|
@@ -304,6 +305,37 @@ class VideoDAO {
|
|
|
304
305
|
.orderBy("v.recordingStartedAt", "asc");
|
|
305
306
|
});
|
|
306
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* Get paginated videos for a specific camera
|
|
310
|
+
* @param cameraId - The camera ID
|
|
311
|
+
* @param page - Page number
|
|
312
|
+
* @param limit - Items per page
|
|
313
|
+
*/
|
|
314
|
+
getVideosByCameraId(cameraId, page, limit) {
|
|
315
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
316
|
+
const offset = (page - 1) * limit;
|
|
317
|
+
const query = this._knex("video as v")
|
|
318
|
+
.innerJoin("folders as f", "v.folderId", "f.id")
|
|
319
|
+
.select("v.*", this._knex.raw("to_jsonb(f.*) as folder"))
|
|
320
|
+
.where("v.cameraId", cameraId);
|
|
321
|
+
const [countResult] = yield query.clone().clearSelect().count("* as count");
|
|
322
|
+
const totalCount = +countResult.count;
|
|
323
|
+
const videos = yield query
|
|
324
|
+
.clone()
|
|
325
|
+
.limit(limit)
|
|
326
|
+
.offset(offset)
|
|
327
|
+
.orderBy("v.created_at", "desc");
|
|
328
|
+
return {
|
|
329
|
+
success: true,
|
|
330
|
+
data: videos,
|
|
331
|
+
page,
|
|
332
|
+
limit,
|
|
333
|
+
count: videos.length,
|
|
334
|
+
totalCount,
|
|
335
|
+
totalPages: Math.ceil(totalCount / limit),
|
|
336
|
+
};
|
|
337
|
+
});
|
|
338
|
+
}
|
|
307
339
|
}
|
|
308
340
|
exports.VideoDAO = VideoDAO;
|
|
309
341
|
//# sourceMappingURL=video.dao.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.dao.js","sourceRoot":"","sources":["../../../src/dao/video/video.dao.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAGA,0EAA+C;AAE/C,MAAa,QAAQ;IAArB;QACU,UAAK,GAAyB,wBAAW,CAAC,aAAa,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"video.dao.js","sourceRoot":"","sources":["../../../src/dao/video/video.dao.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { BatchDAO } from "./dao/batch/batch.dao";
|
|
|
3
3
|
export { CameraDAO } from "./dao/camera/camera.dao";
|
|
4
4
|
export { ChatDAO } from "./dao/chat/chat.dao";
|
|
5
5
|
export { FolderDAO } from "./dao/folder/folder.dao";
|
|
6
|
+
export { LocationDAO } from "./dao/location/location.dao";
|
|
6
7
|
export { MessageDAO } from "./dao/message/message.dao";
|
|
7
8
|
export { ReportConfigurationDAO } from "./dao/report-configuration/report-configuration.dao";
|
|
8
9
|
export { StudyDAO } from "./dao/study/study.dao";
|
|
@@ -16,6 +17,7 @@ export { IBatch } from "./interfaces/batch/batch.interfaces";
|
|
|
16
17
|
export { ICamera } from "./interfaces/camera/camera.interfaces";
|
|
17
18
|
export { IChat, IChatCreate, IChatUpdate, } from "./interfaces/chat/chat.interfaces";
|
|
18
19
|
export { IFolder } from "./interfaces/folder/folder.interfaces";
|
|
20
|
+
export { ILocation } from "./interfaces/location/location.interfaces";
|
|
19
21
|
export { IMessage, IMessageCreate, IMessageUpdate, } from "./interfaces/message/message.interfaces";
|
|
20
22
|
export { IReportConfiguration, IReportConfigurationData, IReportConfigurationInput, ICustomClass, IValidationResult, } from "./interfaces/report-configuration/report-configuration.interfaces";
|
|
21
23
|
export { IStudy } from "./interfaces/study/study.interfaces";
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.KnexManager = exports.VideoMinuteResultDAO = exports.VideoDAO = exports.UserPushNotificationTokenDAO = exports.UserDAO = exports.StudyDAO = exports.ReportConfigurationDAO = exports.MessageDAO = exports.FolderDAO = exports.ChatDAO = exports.CameraDAO = exports.BatchDAO = exports.AuthDAO = void 0;
|
|
6
|
+
exports.KnexManager = exports.VideoMinuteResultDAO = exports.VideoDAO = exports.UserPushNotificationTokenDAO = exports.UserDAO = exports.StudyDAO = exports.ReportConfigurationDAO = exports.MessageDAO = exports.LocationDAO = exports.FolderDAO = exports.ChatDAO = exports.CameraDAO = exports.BatchDAO = exports.AuthDAO = void 0;
|
|
7
7
|
// DAOs
|
|
8
8
|
var auth_dao_1 = require("./dao/auth/auth.dao");
|
|
9
9
|
Object.defineProperty(exports, "AuthDAO", { enumerable: true, get: function () { return auth_dao_1.AuthDAO; } });
|
|
@@ -15,6 +15,8 @@ var chat_dao_1 = require("./dao/chat/chat.dao");
|
|
|
15
15
|
Object.defineProperty(exports, "ChatDAO", { enumerable: true, get: function () { return chat_dao_1.ChatDAO; } });
|
|
16
16
|
var folder_dao_1 = require("./dao/folder/folder.dao");
|
|
17
17
|
Object.defineProperty(exports, "FolderDAO", { enumerable: true, get: function () { return folder_dao_1.FolderDAO; } });
|
|
18
|
+
var location_dao_1 = require("./dao/location/location.dao");
|
|
19
|
+
Object.defineProperty(exports, "LocationDAO", { enumerable: true, get: function () { return location_dao_1.LocationDAO; } });
|
|
18
20
|
var message_dao_1 = require("./dao/message/message.dao");
|
|
19
21
|
Object.defineProperty(exports, "MessageDAO", { enumerable: true, get: function () { return message_dao_1.MessageDAO; } });
|
|
20
22
|
var report_configuration_dao_1 = require("./dao/report-configuration/report-configuration.dao");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO;AACP,gDAA8C;AAArC,mGAAA,OAAO,OAAA;AAChB,mDAAiD;AAAxC,qGAAA,QAAQ,OAAA;AACjB,sDAAoD;AAA3C,uGAAA,SAAS,OAAA;AAClB,gDAA8C;AAArC,mGAAA,OAAO,OAAA;AAChB,sDAAoD;AAA3C,uGAAA,SAAS,OAAA;AAClB,yDAAuD;AAA9C,yGAAA,UAAU,OAAA;AACnB,gGAA6F;AAApF,kIAAA,sBAAsB,OAAA;AAC/B,mDAAiD;AAAxC,qGAAA,QAAQ,OAAA;AACjB,gDAA8C;AAArC,mGAAA,OAAO,OAAA;AAChB,wHAAmH;AAA1G,gJAAA,4BAA4B,OAAA;AACrC,mDAAiD;AAAxC,qGAAA,QAAQ,OAAA;AACjB,mEAAkE;AAAzD,4HAAA,oBAAoB,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO;AACP,gDAA8C;AAArC,mGAAA,OAAO,OAAA;AAChB,mDAAiD;AAAxC,qGAAA,QAAQ,OAAA;AACjB,sDAAoD;AAA3C,uGAAA,SAAS,OAAA;AAClB,gDAA8C;AAArC,mGAAA,OAAO,OAAA;AAChB,sDAAoD;AAA3C,uGAAA,SAAS,OAAA;AAClB,4DAA0D;AAAjD,2GAAA,WAAW,OAAA;AACpB,yDAAuD;AAA9C,yGAAA,UAAU,OAAA;AACnB,gGAA6F;AAApF,kIAAA,sBAAsB,OAAA;AAC/B,mDAAiD;AAAxC,qGAAA,QAAQ,OAAA;AACjB,gDAA8C;AAArC,mGAAA,OAAO,OAAA;AAChB,wHAAmH;AAA1G,gJAAA,4BAA4B,OAAA;AACrC,mDAAiD;AAAxC,qGAAA,QAAQ,OAAA;AACjB,mEAAkE;AAAzD,4HAAA,oBAAoB,OAAA;AA4C7B,sEAA2C;AAClC,sBADF,wBAAW,CACE"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export interface ICamera {
|
|
2
2
|
id: number;
|
|
3
3
|
uuid: string;
|
|
4
|
+
locationId: number;
|
|
4
5
|
name: string;
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
description?: string;
|
|
7
|
+
status: "ACTIVE" | "INACTIVE" | "MAINTENANCE";
|
|
8
|
+
metadata: Record<string, any>;
|
|
7
9
|
created_at: string;
|
|
8
10
|
updated_at: string;
|
|
9
11
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"location.interfaces.js","sourceRoot":"","sources":["../../../src/interfaces/location/location.interfaces.ts"],"names":[],"mappings":""}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IUser } from "../user/user.interfaces";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ILocation } from "../location/location.interfaces";
|
|
3
3
|
export interface IStudy {
|
|
4
4
|
id: number;
|
|
5
5
|
uuid: string;
|
|
@@ -7,10 +7,11 @@ export interface IStudy {
|
|
|
7
7
|
description?: string;
|
|
8
8
|
type: "TMC" | "ATR";
|
|
9
9
|
createdBy: number;
|
|
10
|
-
|
|
10
|
+
locationId?: number;
|
|
11
|
+
isMultiCamera: boolean;
|
|
11
12
|
status: "COMPLETE" | "IN PROGRESS" | "FAILED";
|
|
12
13
|
created_at: string;
|
|
13
14
|
updated_at: string;
|
|
14
15
|
user?: IUser;
|
|
15
|
-
|
|
16
|
+
location?: ILocation;
|
|
16
17
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Migration: Rename cameras table to locations
|
|
5
|
+
*
|
|
6
|
+
* Purpose: Rename existing 'cameras' table to 'locations' to represent physical study sites.
|
|
7
|
+
* This is the first step in separating locations (physical sites) from cameras (devices at those sites).
|
|
8
|
+
*/
|
|
9
|
+
export async function up(knex: Knex): Promise<void> {
|
|
10
|
+
// 1. Rename the cameras table to locations
|
|
11
|
+
await knex.schema.renameTable("cameras", "locations");
|
|
12
|
+
|
|
13
|
+
// 2. Rename the uuid unique constraint to match new table name (frees up name for new cameras table)
|
|
14
|
+
await knex.raw(`
|
|
15
|
+
ALTER TABLE locations
|
|
16
|
+
RENAME CONSTRAINT cameras_uuid_unique TO locations_uuid_unique
|
|
17
|
+
`);
|
|
18
|
+
|
|
19
|
+
// 3. Rename the foreign key column in study table
|
|
20
|
+
await knex.schema.alterTable("study", (table) => {
|
|
21
|
+
table.renameColumn("cameraId", "locationId");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// 4. Drop the old foreign key constraint
|
|
25
|
+
await knex.raw(`
|
|
26
|
+
ALTER TABLE study
|
|
27
|
+
DROP CONSTRAINT IF EXISTS study_cameraid_foreign
|
|
28
|
+
`);
|
|
29
|
+
|
|
30
|
+
// 5. Add new foreign key constraint with updated name
|
|
31
|
+
await knex.schema.alterTable("study", (table) => {
|
|
32
|
+
table
|
|
33
|
+
.foreign("locationId")
|
|
34
|
+
.references("id")
|
|
35
|
+
.inTable("locations")
|
|
36
|
+
.onDelete("SET NULL");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// 6. Drop old index if it exists
|
|
40
|
+
await knex.raw(`
|
|
41
|
+
DROP INDEX IF EXISTS study_cameraid_index
|
|
42
|
+
`);
|
|
43
|
+
|
|
44
|
+
// 7. Create new index with updated name
|
|
45
|
+
await knex.schema.alterTable("study", (table) => {
|
|
46
|
+
table.index(["locationId"], "study_locationid_index");
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function down(knex: Knex): Promise<void> {
|
|
51
|
+
// 1. Drop the new foreign key constraint
|
|
52
|
+
await knex.raw(`
|
|
53
|
+
ALTER TABLE study
|
|
54
|
+
DROP CONSTRAINT IF EXISTS study_locationid_foreign
|
|
55
|
+
`);
|
|
56
|
+
|
|
57
|
+
// 2. Drop new index
|
|
58
|
+
await knex.raw(`
|
|
59
|
+
DROP INDEX IF EXISTS study_locationid_index
|
|
60
|
+
`);
|
|
61
|
+
|
|
62
|
+
// 3. Rename column back
|
|
63
|
+
await knex.schema.alterTable("study", (table) => {
|
|
64
|
+
table.renameColumn("locationId", "cameraId");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// 4. Restore original foreign key constraint
|
|
68
|
+
await knex.schema.alterTable("study", (table) => {
|
|
69
|
+
table
|
|
70
|
+
.foreign("cameraId")
|
|
71
|
+
.references("id")
|
|
72
|
+
.inTable("locations")
|
|
73
|
+
.onDelete("SET NULL");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// 5. Restore original index
|
|
77
|
+
await knex.schema.alterTable("study", (table) => {
|
|
78
|
+
table.index(["cameraId"], "study_cameraid_index");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// 6. Rename constraint back to original name
|
|
82
|
+
await knex.raw(`
|
|
83
|
+
ALTER TABLE locations
|
|
84
|
+
RENAME CONSTRAINT locations_uuid_unique TO cameras_uuid_unique
|
|
85
|
+
`);
|
|
86
|
+
|
|
87
|
+
// 7. Rename the table back to cameras
|
|
88
|
+
await knex.schema.renameTable("locations", "cameras");
|
|
89
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Migration: Add isMultiCamera field to study table
|
|
5
|
+
*
|
|
6
|
+
* Purpose: Add boolean flag to indicate whether a study uses multiple cameras.
|
|
7
|
+
* Defaults to false for backward compatibility with existing single-camera studies.
|
|
8
|
+
*/
|
|
9
|
+
export async function up(knex: Knex): Promise<void> {
|
|
10
|
+
await knex.schema.alterTable("study", (table) => {
|
|
11
|
+
table.boolean("isMultiCamera").notNullable().defaultTo(false);
|
|
12
|
+
table.index(["isMultiCamera"], "study_ismulticamera_index");
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function down(knex: Knex): Promise<void> {
|
|
17
|
+
await knex.schema.alterTable("study", (table) => {
|
|
18
|
+
table.dropIndex(["isMultiCamera"], "study_ismulticamera_index");
|
|
19
|
+
table.dropColumn("isMultiCamera");
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Migration: Create cameras table
|
|
5
|
+
*
|
|
6
|
+
* Purpose: Create new 'cameras' table to represent camera devices at locations.
|
|
7
|
+
* This allows multiple cameras to be associated with a single location.
|
|
8
|
+
*/
|
|
9
|
+
export async function up(knex: Knex): Promise<void> {
|
|
10
|
+
await knex.schema.createTable("cameras", (table) => {
|
|
11
|
+
table.increments("id").primary();
|
|
12
|
+
table
|
|
13
|
+
.uuid("uuid")
|
|
14
|
+
.defaultTo(knex.raw("uuid_generate_v4()"))
|
|
15
|
+
.unique()
|
|
16
|
+
.notNullable();
|
|
17
|
+
table
|
|
18
|
+
.integer("locationId")
|
|
19
|
+
.unsigned()
|
|
20
|
+
.notNullable()
|
|
21
|
+
.references("id")
|
|
22
|
+
.inTable("locations")
|
|
23
|
+
.onDelete("CASCADE");
|
|
24
|
+
table.string("name", 100).notNullable();
|
|
25
|
+
table.text("description").nullable();
|
|
26
|
+
table
|
|
27
|
+
.enu("status", ["ACTIVE", "INACTIVE", "MAINTENANCE"], {
|
|
28
|
+
useNative: true,
|
|
29
|
+
enumName: "camera_status_enum",
|
|
30
|
+
})
|
|
31
|
+
.defaultTo("ACTIVE")
|
|
32
|
+
.notNullable();
|
|
33
|
+
table.jsonb("metadata").defaultTo("{}").notNullable();
|
|
34
|
+
table.timestamps(true, true);
|
|
35
|
+
|
|
36
|
+
// Unique constraint: camera names must be unique within a location
|
|
37
|
+
table.unique(["locationId", "name"], "cameras_locationid_name_unique");
|
|
38
|
+
|
|
39
|
+
// Index for faster lookups
|
|
40
|
+
table.index(["locationId"], "cameras_locationid_index");
|
|
41
|
+
table.index(["status"], "cameras_status_index");
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function down(knex: Knex): Promise<void> {
|
|
46
|
+
await knex.schema.dropTableIfExists("cameras");
|
|
47
|
+
|
|
48
|
+
// Drop the enum type
|
|
49
|
+
await knex.raw("DROP TYPE IF EXISTS camera_status_enum");
|
|
50
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Migration: Add cameraId column to video table
|
|
5
|
+
*
|
|
6
|
+
* Purpose: Link videos to specific cameras in multi-camera studies.
|
|
7
|
+
* Nullable to maintain backward compatibility with existing videos.
|
|
8
|
+
*/
|
|
9
|
+
export async function up(knex: Knex): Promise<void> {
|
|
10
|
+
await knex.schema.alterTable("video", (table) => {
|
|
11
|
+
table
|
|
12
|
+
.integer("cameraId")
|
|
13
|
+
.unsigned()
|
|
14
|
+
.nullable()
|
|
15
|
+
.references("id")
|
|
16
|
+
.inTable("cameras")
|
|
17
|
+
.onDelete("SET NULL");
|
|
18
|
+
table.index(["cameraId"], "video_cameraid_index");
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function down(knex: Knex): Promise<void> {
|
|
23
|
+
await knex.schema.alterTable("video", (table) => {
|
|
24
|
+
table.dropIndex(["cameraId"], "video_cameraid_index");
|
|
25
|
+
table.dropColumn("cameraId");
|
|
26
|
+
});
|
|
27
|
+
}
|
package/package.json
CHANGED
|
@@ -71,6 +71,8 @@ interface IGroupedResponse {
|
|
|
71
71
|
interface IStudyTimeGroupResult {
|
|
72
72
|
absoluteTime: string; // ISO 8601 start of bucket
|
|
73
73
|
groupIndex: number;
|
|
74
|
+
startMinute: number; // Start minute number (0-based from video start)
|
|
75
|
+
endMinute: number; // End minute number (0-based from video start)
|
|
74
76
|
label: string; // Formatted label
|
|
75
77
|
results: ITMCResult | IATRResult;
|
|
76
78
|
minuteCount: number;
|
|
@@ -655,6 +657,8 @@ export class VideoMinuteResultDAO implements IBaseDAO<IVideoMinuteResult> {
|
|
|
655
657
|
return {
|
|
656
658
|
absoluteTime: bucket.absoluteTime.toISOString(),
|
|
657
659
|
groupIndex: bucket.groupIndex,
|
|
660
|
+
startMinute: bucket.groupIndex * groupingMinutes,
|
|
661
|
+
endMinute: (bucket.groupIndex + 1) * groupingMinutes - 1,
|
|
658
662
|
label: this.formatStudyTimeLabel(
|
|
659
663
|
bucket.absoluteTime,
|
|
660
664
|
groupingMinutes,
|
|
@@ -935,6 +939,7 @@ export class VideoMinuteResultDAO implements IBaseDAO<IVideoMinuteResult> {
|
|
|
935
939
|
/**
|
|
936
940
|
* Format time label for study-level results (time only, no dates)
|
|
937
941
|
* Used when results are already grouped by date in the UI
|
|
942
|
+
* Uses UTC time for consistency with absoluteTime field
|
|
938
943
|
*/
|
|
939
944
|
private formatStudyTimeLabel(
|
|
940
945
|
startTime: Date,
|
|
@@ -943,8 +948,8 @@ export class VideoMinuteResultDAO implements IBaseDAO<IVideoMinuteResult> {
|
|
|
943
948
|
const endTime = new Date(startTime.getTime() + durationMinutes * 60 * 1000);
|
|
944
949
|
|
|
945
950
|
const formatTime = (date: Date): string => {
|
|
946
|
-
const hours = date.
|
|
947
|
-
const minutes = date.
|
|
951
|
+
const hours = date.getUTCHours().toString().padStart(2, "0");
|
|
952
|
+
const minutes = date.getUTCMinutes().toString().padStart(2, "0");
|
|
948
953
|
return `${hours}:${minutes}`;
|
|
949
954
|
};
|
|
950
955
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Knex } from "knex";
|
|
2
2
|
import { IBaseDAO, IDataPaginator } from "../../d.types";
|
|
3
3
|
import { ICamera } from "../../interfaces/camera/camera.interfaces";
|
|
4
|
-
import { IVideo } from "../../interfaces/video/video.interfaces";
|
|
5
4
|
import KnexManager from "../../KnexConnection";
|
|
6
5
|
|
|
7
6
|
export class CameraDAO implements IBaseDAO<ICamera> {
|
|
@@ -55,45 +54,43 @@ export class CameraDAO implements IBaseDAO<ICamera> {
|
|
|
55
54
|
};
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
async
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
radiusKm: number = 1,
|
|
57
|
+
/**
|
|
58
|
+
* Get cameras for a specific location
|
|
59
|
+
* @param locationId - The location ID
|
|
60
|
+
* @param status - Optional filter by camera status
|
|
61
|
+
*/
|
|
62
|
+
async getCamerasByLocationId(
|
|
63
|
+
locationId: number,
|
|
64
|
+
status?: string,
|
|
67
65
|
): Promise<ICamera[]> {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
)`,
|
|
76
|
-
[longitude, latitude, radiusKm * 1000], // Convert km to meters
|
|
77
|
-
);
|
|
78
|
-
return cameras;
|
|
66
|
+
let query = this._knex("cameras").where("locationId", locationId);
|
|
67
|
+
|
|
68
|
+
if (status) {
|
|
69
|
+
query = query.where("status", status);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return query.orderBy("name", "asc");
|
|
79
73
|
}
|
|
80
74
|
|
|
81
75
|
/**
|
|
82
|
-
* Get
|
|
76
|
+
* Get cameras for a specific location with pagination
|
|
77
|
+
* @param locationId - The location ID
|
|
78
|
+
* @param page - Page number
|
|
79
|
+
* @param limit - Items per page
|
|
80
|
+
* @param status - Optional filter by camera status
|
|
83
81
|
*/
|
|
84
|
-
async
|
|
82
|
+
async getCamerasByLocationIdPaginated(
|
|
83
|
+
locationId: number,
|
|
85
84
|
page: number,
|
|
86
85
|
limit: number,
|
|
87
|
-
|
|
86
|
+
status?: string,
|
|
88
87
|
): Promise<IDataPaginator<ICamera>> {
|
|
89
88
|
const offset = (page - 1) * limit;
|
|
90
89
|
|
|
91
|
-
let query = this._knex("cameras");
|
|
90
|
+
let query = this._knex("cameras").where("locationId", locationId);
|
|
92
91
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const escapedName = name.trim().replace(/[%_\\]/g, "\\$&");
|
|
96
|
-
query = query.where("name", "ilike", `%${escapedName}%`);
|
|
92
|
+
if (status) {
|
|
93
|
+
query = query.where("status", status);
|
|
97
94
|
}
|
|
98
95
|
|
|
99
96
|
const [countResult] = await query.clone().count("* as count");
|
|
@@ -116,39 +113,25 @@ export class CameraDAO implements IBaseDAO<ICamera> {
|
|
|
116
113
|
}
|
|
117
114
|
|
|
118
115
|
/**
|
|
119
|
-
*
|
|
116
|
+
* Check if a camera name already exists for a location
|
|
117
|
+
* @param name - Camera name
|
|
118
|
+
* @param locationId - Location ID
|
|
119
|
+
* @param excludeId - Optional camera ID to exclude (for update operations)
|
|
120
120
|
*/
|
|
121
|
-
async
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
): Promise<
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
.
|
|
132
|
-
|
|
133
|
-
// Optimized count query without JOIN
|
|
134
|
-
const [countResult] = await this._knex("video as v")
|
|
135
|
-
.where("v.cameraId", cameraId)
|
|
136
|
-
.count("* as count");
|
|
137
|
-
const totalCount = +countResult.count;
|
|
138
|
-
const videos = await query
|
|
139
|
-
.clone()
|
|
140
|
-
.limit(limit)
|
|
141
|
-
.offset(offset)
|
|
142
|
-
.orderBy("v.created_at", "desc");
|
|
121
|
+
async existsByNameAndLocation(
|
|
122
|
+
name: string,
|
|
123
|
+
locationId: number,
|
|
124
|
+
excludeId?: number,
|
|
125
|
+
): Promise<boolean> {
|
|
126
|
+
let query = this._knex("cameras")
|
|
127
|
+
.where("locationId", locationId)
|
|
128
|
+
.where("name", name);
|
|
129
|
+
|
|
130
|
+
if (excludeId !== undefined) {
|
|
131
|
+
query = query.whereNot("id", excludeId);
|
|
132
|
+
}
|
|
143
133
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
data: videos,
|
|
147
|
-
page,
|
|
148
|
-
limit,
|
|
149
|
-
count: videos.length,
|
|
150
|
-
totalCount,
|
|
151
|
-
totalPages: Math.ceil(totalCount / limit),
|
|
152
|
-
};
|
|
134
|
+
const result = await query.first();
|
|
135
|
+
return result !== null && result !== undefined;
|
|
153
136
|
}
|
|
154
137
|
}
|
|
@@ -53,7 +53,13 @@ export class FolderDAO implements IBaseDAO<IFolder> {
|
|
|
53
53
|
|
|
54
54
|
const query = this._knex("folders as f")
|
|
55
55
|
.innerJoin("study as s", "f.studyId", "s.id")
|
|
56
|
-
.
|
|
56
|
+
.leftJoin("locations as l", "s.locationId", "l.id")
|
|
57
|
+
.select(
|
|
58
|
+
"f.*",
|
|
59
|
+
this._knex.raw("to_jsonb(s.*) as study"),
|
|
60
|
+
"l.name as locationName",
|
|
61
|
+
"l.uuid as locationUuid",
|
|
62
|
+
);
|
|
57
63
|
if (studyId !== undefined && studyId !== null) {
|
|
58
64
|
query.where("f.studyId", studyId);
|
|
59
65
|
}
|