@managemint-solutions/sdk 0.25.0 → 0.26.0

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/README.md CHANGED
@@ -144,7 +144,9 @@ const page = await supabase.projects.list({
144
144
  client_id: clientId, // a UUID, or the base64-JSON option value a select sends
145
145
  });
146
146
  // `search` matches name/specification; `created_*`, `start_date_*` and `end_date_*` bound the
147
- // date columns, and `status_id_in` filters by status.
147
+ // date columns, and `status_id_in` filters by status. `status_id_not_in` is the exclusion form —
148
+ // it keeps rows with no status, which `status_id_in` cannot express. `completed` is carried but
149
+ // not acted on here: the api resolves it to status ids against the statuses catalogue first.
148
150
 
149
151
  const project = await supabase.projects.create({
150
152
  name: 'Website rebuild',
@@ -178,7 +180,9 @@ const page = await supabase.tasks.list({
178
180
  priority_in: [1, 3],
179
181
  });
180
182
  // `search` matches name/description, and `client_id`, `assigned_to_id`, the date ranges and
181
- // `status_id_in` narrow it further.
183
+ // `status_id_in` narrow it further. `status_id_not_in` excludes statuses while keeping rows with
184
+ // no status; `completed` is carried but not acted on here — the api resolves it to status ids
185
+ // against the statuses catalogue first.
182
186
 
183
187
  const task = await supabase.tasks.create({
184
188
  name: 'Draft the proposal',
@@ -1,5 +1,5 @@
1
1
  import type { CreateProjectDto as CreateProjectDtoType, GetProjectsDto as GetProjectsDtoType, ProjectIdDto as ProjectIdDtoType, UpdateProjectDto as UpdateProjectDtoType } from '@managemint-solutions/entities/projects/dto';
2
- export declare class GetProjectsDto implements Omit<GetProjectsDtoType, 'status_id_in'> {
2
+ export declare class GetProjectsDto implements Omit<GetProjectsDtoType, 'status_id_in' | 'status_id_not_in'> {
3
3
  readonly search?: string | null;
4
4
  readonly page: number;
5
5
  readonly page_size: number;
@@ -10,6 +10,8 @@ export declare class GetProjectsDto implements Omit<GetProjectsDtoType, 'status_
10
10
  readonly end_date_after?: string | null;
11
11
  readonly end_date_before?: string | null;
12
12
  readonly status_id_in?: string[] | null;
13
+ readonly status_id_not_in?: string[] | null;
14
+ readonly completed?: boolean | null;
13
15
  readonly client_id?: string | null;
14
16
  readonly archive: boolean;
15
17
  }
@@ -16,9 +16,10 @@ const transforms_1 = require("../transforms");
16
16
  const validators_1 = require("../validators");
17
17
  // class-validator versions of the shared DTO types from @managemint-solutions/entities, so the
18
18
  // wire contract cannot drift.
19
- // `status_id_in` is omitted from the implemented type on purpose: the entities type carries the
20
- // CSV wire value (`string | null`), while this class carries the `@Transform`-parsed
21
- // `string[] | null` the query builder feeds to `.in('status_id', ...)`.
19
+ // `status_id_in` and `status_id_not_in` are omitted from the implemented type on purpose: the
20
+ // entities type carries the CSV wire values (`string | null`), while this class carries the
21
+ // `@Transform`-parsed `string[] | null` the query builder feeds to `.in('status_id', ...)` and to
22
+ // the `status_id.is.null,status_id.not.in.(...)` exclusion.
22
23
  class GetProjectsDto {
23
24
  search;
24
25
  page = 1;
@@ -30,6 +31,10 @@ class GetProjectsDto {
30
31
  end_date_after;
31
32
  end_date_before;
32
33
  status_id_in;
34
+ status_id_not_in;
35
+ // Tri-state: true = only completed rows, false = only rows that are not completed, omitted = no
36
+ // completion filter. The api resolves it to status ids before it reaches `list`.
37
+ completed;
33
38
  client_id;
34
39
  archive = false;
35
40
  }
@@ -99,6 +104,20 @@ __decorate([
99
104
  (0, class_validator_1.IsUUID)('7', { each: true, message: 'Each status ID must be a valid UUID v7' }),
100
105
  __metadata("design:type", Object)
101
106
  ], GetProjectsDto.prototype, "status_id_in", void 0);
107
+ __decorate([
108
+ (0, class_validator_1.IsOptional)(),
109
+ (0, validators_1.IsNullable)(),
110
+ (0, class_transformer_1.Transform)(({ value }) => value ? value.split(',').map((id) => id.trim()) : null, { toClassOnly: true }),
111
+ (0, class_validator_1.IsUUID)('7', { each: true, message: 'Each status ID must be a valid UUID v7' }),
112
+ __metadata("design:type", Object)
113
+ ], GetProjectsDto.prototype, "status_id_not_in", void 0);
114
+ __decorate([
115
+ (0, class_validator_1.IsOptional)(),
116
+ (0, validators_1.IsNullable)(),
117
+ (0, class_transformer_1.Transform)(({ value }) => value === 'true' ? true : value === 'false' ? false : value, { toClassOnly: true }),
118
+ (0, class_validator_1.IsBoolean)({ message: 'Completed must be true or false' }),
119
+ __metadata("design:type", Object)
120
+ ], GetProjectsDto.prototype, "completed", void 0);
102
121
  __decorate([
103
122
  (0, class_validator_1.IsOptional)(),
104
123
  (0, validators_1.IsNullable)(),
@@ -124,6 +124,15 @@ class ProjectsResource {
124
124
  if (query.status_id_in && query.status_id_in.length > 0) {
125
125
  projectsQuery = projectsQuery.in('status_id', query.status_id_in);
126
126
  }
127
+ // Excluding statuses has to be spelled out as "no status OR not one of these": PostgREST can
128
+ // only filter a parent row by an embedded column with `!inner`, which would drop projects that
129
+ // have no status at all — and a project with no status is not complete, so it belongs in the
130
+ // default view. SQL's `NOT IN` drops nulls for the same reason, hence the explicit null arm.
131
+ // The ids are `@IsUUID('7')`-validated by the DTO, so interpolating them is safe. Repeated
132
+ // `or` params are ANDed by PostgREST, so this composes with the search filter above.
133
+ if (query.status_id_not_in && query.status_id_not_in.length > 0) {
134
+ projectsQuery = projectsQuery.or(`status_id.is.null,status_id.not.in.(${query.status_id_not_in.join(',')})`);
135
+ }
127
136
  if (query.client_id) {
128
137
  projectsQuery = projectsQuery.eq('client_id', query.client_id);
129
138
  }
@@ -2,7 +2,7 @@ import type { CreateTaskDto as CreateTaskDtoType, GetTasksDto as GetTasksDtoType
2
2
  export declare class TaskIdDto implements TaskIdDtoType {
3
3
  readonly taskId: string;
4
4
  }
5
- export declare class GetTasksDto implements Omit<GetTasksDtoType, 'status_id_in' | 'priority_in'> {
5
+ export declare class GetTasksDto implements Omit<GetTasksDtoType, 'status_id_in' | 'status_id_not_in' | 'priority_in'> {
6
6
  readonly search?: string | null;
7
7
  readonly page: number;
8
8
  readonly page_size: number;
@@ -16,6 +16,8 @@ export declare class GetTasksDto implements Omit<GetTasksDtoType, 'status_id_in'
16
16
  readonly end_date_after?: string | null;
17
17
  readonly end_date_before?: string | null;
18
18
  readonly status_id_in?: string[] | null;
19
+ readonly status_id_not_in?: string[] | null;
20
+ readonly completed?: boolean | null;
19
21
  readonly priority_in?: number[] | null;
20
22
  readonly archive: boolean;
21
23
  }
package/dist/tasks/dto.js CHANGED
@@ -25,9 +25,10 @@ __decorate([
25
25
  ,
26
26
  __metadata("design:type", String)
27
27
  ], TaskIdDto.prototype, "taskId", void 0);
28
- // `status_id_in` and `priority_in` are omitted from the implemented type on purpose: the entities
29
- // type carries the CSV wire values, while this class carries the `@Transform`-parsed arrays the
30
- // query builder feeds to `.in('status_id', ...)` / `.in('priority', ...)`.
28
+ // `status_id_in`, `status_id_not_in` and `priority_in` are omitted from the implemented type on
29
+ // purpose: the entities type carries the CSV wire values, while this class carries the
30
+ // `@Transform`-parsed arrays the query builder feeds to `.in('status_id', ...)` /
31
+ // `.in('priority', ...)` and to the `status_id.is.null,status_id.not.in.(...)` exclusion.
31
32
  class GetTasksDto {
32
33
  search;
33
34
  page = 1;
@@ -42,6 +43,10 @@ class GetTasksDto {
42
43
  end_date_after;
43
44
  end_date_before;
44
45
  status_id_in;
46
+ status_id_not_in;
47
+ // Tri-state: true = only completed rows, false = only rows that are not completed, omitted = no
48
+ // completion filter. The api resolves it to status ids before it reaches `list`.
49
+ completed;
45
50
  priority_in;
46
51
  archive = false;
47
52
  }
@@ -135,6 +140,20 @@ __decorate([
135
140
  (0, class_validator_1.IsUUID)('7', { each: true, message: 'Invalid status ID format' }),
136
141
  __metadata("design:type", Object)
137
142
  ], GetTasksDto.prototype, "status_id_in", void 0);
143
+ __decorate([
144
+ (0, class_validator_1.IsOptional)(),
145
+ (0, validators_1.IsNullable)(),
146
+ (0, class_transformer_1.Transform)(({ value }) => value ? value.split(',').map((id) => id.trim()) : null, { toClassOnly: true }),
147
+ (0, class_validator_1.IsUUID)('7', { each: true, message: 'Invalid status ID format' }),
148
+ __metadata("design:type", Object)
149
+ ], GetTasksDto.prototype, "status_id_not_in", void 0);
150
+ __decorate([
151
+ (0, class_validator_1.IsOptional)(),
152
+ (0, validators_1.IsNullable)(),
153
+ (0, class_transformer_1.Transform)(({ value }) => value === 'true' ? true : value === 'false' ? false : value, { toClassOnly: true }),
154
+ (0, class_validator_1.IsBoolean)({ message: 'Completed must be true or false' }),
155
+ __metadata("design:type", Object)
156
+ ], GetTasksDto.prototype, "completed", void 0);
138
157
  __decorate([
139
158
  (0, class_validator_1.IsOptional)(),
140
159
  (0, validators_1.IsNullable)(),
@@ -133,6 +133,15 @@ class TasksResource {
133
133
  if (query.status_id_in && query.status_id_in.length > 0) {
134
134
  tasksQuery = tasksQuery.in('status_id', query.status_id_in);
135
135
  }
136
+ // Excluding statuses has to be spelled out as "no status OR not one of these": PostgREST can
137
+ // only filter a parent row by an embedded column with `!inner`, which would drop tasks that
138
+ // have no status at all — and a task with no status is not complete, so it belongs in the
139
+ // default view. SQL's `NOT IN` drops nulls for the same reason, hence the explicit null arm.
140
+ // The ids are `@IsUUID('7')`-validated by the DTO, so interpolating them is safe. Repeated
141
+ // `or` params are ANDed by PostgREST, so this composes with the search filter above.
142
+ if (query.status_id_not_in && query.status_id_not_in.length > 0) {
143
+ tasksQuery = tasksQuery.or(`status_id.is.null,status_id.not.in.(${query.status_id_not_in.join(',')})`);
144
+ }
136
145
  if (query.priority_in && query.priority_in.length > 0) {
137
146
  tasksQuery = tasksQuery.in('priority', query.priority_in);
138
147
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@managemint-solutions/sdk",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "Typed Supabase data-access SDK for ManageMint Solutions",
5
5
  "license": "UNLICENSED",
6
6
  "author": "Scott Bebington <scottbebington@gmail.com>",
@@ -47,7 +47,7 @@
47
47
  "testEnvironment": "node"
48
48
  },
49
49
  "dependencies": {
50
- "@managemint-solutions/entities": "^1.9.0"
50
+ "@managemint-solutions/entities": "^1.10.0"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "@nestjs/common": "^11.0.0",