@atproto/ozone 0.1.50 → 0.1.51
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/CHANGELOG.md +9 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +12 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/set/addValues.d.ts +4 -0
- package/dist/api/set/addValues.d.ts.map +1 -0
- package/dist/api/set/addValues.js +24 -0
- package/dist/api/set/addValues.js.map +1 -0
- package/dist/api/set/deleteSet.d.ts +4 -0
- package/dist/api/set/deleteSet.d.ts.map +1 -0
- package/dist/api/set/deleteSet.js +28 -0
- package/dist/api/set/deleteSet.js.map +1 -0
- package/dist/api/set/deleteValues.d.ts +4 -0
- package/dist/api/set/deleteValues.d.ts.map +1 -0
- package/dist/api/set/deleteValues.js +24 -0
- package/dist/api/set/deleteValues.js.map +1 -0
- package/dist/api/set/getValues.d.ts +4 -0
- package/dist/api/set/getValues.d.ts.map +1 -0
- package/dist/api/set/getValues.js +35 -0
- package/dist/api/set/getValues.js.map +1 -0
- package/dist/api/set/querySets.d.ts +4 -0
- package/dist/api/set/querySets.d.ts.map +1 -0
- package/dist/api/set/querySets.js +33 -0
- package/dist/api/set/querySets.js.map +1 -0
- package/dist/api/set/upsertSet.d.ts +4 -0
- package/dist/api/set/upsertSet.d.ts.map +1 -0
- package/dist/api/set/upsertSet.js +32 -0
- package/dist/api/set/upsertSet.js.map +1 -0
- package/dist/context.d.ts +3 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +6 -0
- package/dist/context.js.map +1 -1
- package/dist/db/migrations/20241008T205730722Z-sets.d.ts +4 -0
- package/dist/db/migrations/20241008T205730722Z-sets.d.ts.map +1 -0
- package/dist/db/migrations/20241008T205730722Z-sets.js +46 -0
- package/dist/db/migrations/20241008T205730722Z-sets.js.map +1 -0
- package/dist/db/migrations/index.d.ts +1 -0
- package/dist/db/migrations/index.d.ts.map +1 -1
- package/dist/db/migrations/index.js +2 -1
- package/dist/db/migrations/index.js.map +1 -1
- package/dist/db/pagination.d.ts +1 -1
- package/dist/db/pagination.d.ts.map +1 -1
- package/dist/db/schema/index.d.ts +2 -1
- package/dist/db/schema/index.d.ts.map +1 -1
- package/dist/db/schema/ozone_set.d.ts +21 -0
- package/dist/db/schema/ozone_set.d.ts.map +1 -0
- package/dist/db/schema/ozone_set.js +6 -0
- package/dist/db/schema/ozone_set.js.map +1 -0
- package/dist/lexicon/index.d.ts +17 -0
- package/dist/lexicon/index.d.ts.map +1 -1
- package/dist/lexicon/index.js +44 -1
- package/dist/lexicon/index.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +292 -0
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +298 -0
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/tools/ozone/set/addValues.d.ts +32 -0
- package/dist/lexicon/types/tools/ozone/set/addValues.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/addValues.js +3 -0
- package/dist/lexicon/types/tools/ozone/set/addValues.js.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/defs.d.ts +22 -0
- package/dist/lexicon/types/tools/ozone/set/defs.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/defs.js +24 -0
- package/dist/lexicon/types/tools/ozone/set/defs.js.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/deleteSet.d.ts +41 -0
- package/dist/lexicon/types/tools/ozone/set/deleteSet.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/deleteSet.js +3 -0
- package/dist/lexicon/types/tools/ozone/set/deleteSet.js.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/deleteValues.d.ts +33 -0
- package/dist/lexicon/types/tools/ozone/set/deleteValues.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/deleteValues.js +3 -0
- package/dist/lexicon/types/tools/ozone/set/deleteValues.js.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/getValues.d.ts +41 -0
- package/dist/lexicon/types/tools/ozone/set/getValues.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/getValues.js +3 -0
- package/dist/lexicon/types/tools/ozone/set/getValues.js.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/querySets.d.ts +42 -0
- package/dist/lexicon/types/tools/ozone/set/querySets.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/querySets.js +3 -0
- package/dist/lexicon/types/tools/ozone/set/querySets.js.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/upsertSet.d.ts +35 -0
- package/dist/lexicon/types/tools/ozone/set/upsertSet.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/set/upsertSet.js +3 -0
- package/dist/lexicon/types/tools/ozone/set/upsertSet.js.map +1 -0
- package/dist/set/service.d.ts +46 -0
- package/dist/set/service.d.ts.map +1 -0
- package/dist/set/service.js +166 -0
- package/dist/set/service.js.map +1 -0
- package/package.json +3 -3
- package/src/api/index.ts +12 -0
- package/src/api/set/addValues.ts +28 -0
- package/src/api/set/deleteSet.ts +34 -0
- package/src/api/set/deleteValues.ts +31 -0
- package/src/api/set/getValues.ts +42 -0
- package/src/api/set/querySets.ts +36 -0
- package/src/api/set/upsertSet.ts +38 -0
- package/src/context.ts +8 -0
- package/src/db/migrations/20241008T205730722Z-sets.ts +53 -0
- package/src/db/migrations/index.ts +1 -0
- package/src/db/pagination.ts +1 -1
- package/src/db/schema/index.ts +2 -0
- package/src/db/schema/ozone_set.ts +24 -0
- package/src/lexicon/index.ts +82 -0
- package/src/lexicon/lexicons.ts +301 -0
- package/src/lexicon/types/tools/ozone/set/addValues.ts +41 -0
- package/src/lexicon/types/tools/ozone/set/defs.ts +44 -0
- package/src/lexicon/types/tools/ozone/set/deleteSet.ts +50 -0
- package/src/lexicon/types/tools/ozone/set/deleteValues.ts +42 -0
- package/src/lexicon/types/tools/ozone/set/getValues.ts +51 -0
- package/src/lexicon/types/tools/ozone/set/querySets.ts +52 -0
- package/src/lexicon/types/tools/ozone/set/upsertSet.ts +43 -0
- package/src/set/service.ts +227 -0
- package/tests/__snapshots__/sets.test.ts.snap +46 -0
- package/tests/sets.test.ts +246 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import Database from '../db'
|
|
2
|
+
import { Selectable } from 'kysely'
|
|
3
|
+
import { SetDetail } from '../db/schema/ozone_set'
|
|
4
|
+
import { SetView } from '../lexicon/types/tools/ozone/set/defs'
|
|
5
|
+
import { paginate, TimeIdKeyset } from '../db/pagination'
|
|
6
|
+
|
|
7
|
+
export type SetServiceCreator = (db: Database) => SetService
|
|
8
|
+
|
|
9
|
+
export class SetService {
|
|
10
|
+
constructor(public db: Database) {}
|
|
11
|
+
|
|
12
|
+
static creator() {
|
|
13
|
+
return (db: Database) => new SetService(db)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
buildQueryForSetWithSize() {
|
|
17
|
+
return this.db.db.selectFrom('set_detail as s').select([
|
|
18
|
+
's.id',
|
|
19
|
+
's.name',
|
|
20
|
+
's.description',
|
|
21
|
+
's.createdAt',
|
|
22
|
+
's.updatedAt',
|
|
23
|
+
(eb) =>
|
|
24
|
+
eb
|
|
25
|
+
.selectFrom('set_value')
|
|
26
|
+
.select((e) => e.fn.count<number>('setId').as('count'))
|
|
27
|
+
.whereRef('setId', '=', 's.id')
|
|
28
|
+
.as('setSize'),
|
|
29
|
+
])
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async query({
|
|
33
|
+
limit,
|
|
34
|
+
cursor,
|
|
35
|
+
namePrefix,
|
|
36
|
+
sortBy,
|
|
37
|
+
sortDirection,
|
|
38
|
+
}: {
|
|
39
|
+
limit: number
|
|
40
|
+
cursor?: string
|
|
41
|
+
namePrefix?: string
|
|
42
|
+
sortBy: 'name' | 'createdAt' | 'updatedAt'
|
|
43
|
+
sortDirection: 'asc' | 'desc'
|
|
44
|
+
}): Promise<{
|
|
45
|
+
sets: Selectable<SetDetail & { setSize: number }>[]
|
|
46
|
+
cursor?: string
|
|
47
|
+
}> {
|
|
48
|
+
let qb = this.buildQueryForSetWithSize().limit(limit)
|
|
49
|
+
|
|
50
|
+
if (namePrefix) {
|
|
51
|
+
qb = qb.where('s.name', 'like', `${namePrefix}%`)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (cursor) {
|
|
55
|
+
if (sortBy === 'name') {
|
|
56
|
+
qb = qb.where('s.name', sortDirection === 'asc' ? '>' : '<', cursor)
|
|
57
|
+
} else {
|
|
58
|
+
qb = qb.where(
|
|
59
|
+
`s.${sortBy}`,
|
|
60
|
+
sortDirection === 'asc' ? '>' : '<',
|
|
61
|
+
new Date(cursor),
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
qb = qb.orderBy(`s.${sortBy}`, sortDirection)
|
|
67
|
+
|
|
68
|
+
const sets = await qb.execute()
|
|
69
|
+
const lastItem = sets.at(-1)
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
sets,
|
|
73
|
+
cursor: lastItem
|
|
74
|
+
? sortBy === 'name'
|
|
75
|
+
? lastItem?.name
|
|
76
|
+
: lastItem?.[sortBy].toISOString()
|
|
77
|
+
: undefined,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async getByName(name: string): Promise<Selectable<SetDetail> | undefined> {
|
|
82
|
+
const query = this.db.db
|
|
83
|
+
.selectFrom('set_detail')
|
|
84
|
+
.selectAll()
|
|
85
|
+
.where('name', '=', name)
|
|
86
|
+
|
|
87
|
+
return await query.executeTakeFirst()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async getByNameWithSize(
|
|
91
|
+
name: string,
|
|
92
|
+
): Promise<Selectable<SetDetail & { setSize: number }> | undefined> {
|
|
93
|
+
return await this.buildQueryForSetWithSize()
|
|
94
|
+
.where('s.name', '=', name)
|
|
95
|
+
.executeTakeFirst()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async getSetWithValues({
|
|
99
|
+
name,
|
|
100
|
+
limit,
|
|
101
|
+
cursor,
|
|
102
|
+
}: {
|
|
103
|
+
name: string
|
|
104
|
+
limit: number
|
|
105
|
+
cursor?: string
|
|
106
|
+
}): Promise<
|
|
107
|
+
| {
|
|
108
|
+
set: Selectable<SetDetail & { setSize: number }>
|
|
109
|
+
values: string[]
|
|
110
|
+
cursor?: string
|
|
111
|
+
}
|
|
112
|
+
| undefined
|
|
113
|
+
> {
|
|
114
|
+
const set = await this.getByNameWithSize(name)
|
|
115
|
+
if (!set) return undefined
|
|
116
|
+
|
|
117
|
+
const { ref } = this.db.db.dynamic
|
|
118
|
+
const qb = this.db.db
|
|
119
|
+
.selectFrom('set_value')
|
|
120
|
+
.selectAll()
|
|
121
|
+
.where('setId', '=', set.id)
|
|
122
|
+
|
|
123
|
+
const keyset = new TimeIdKeyset(ref(`createdAt`), ref('id'))
|
|
124
|
+
const paginatedBuilder = paginate(qb, {
|
|
125
|
+
limit,
|
|
126
|
+
cursor,
|
|
127
|
+
keyset,
|
|
128
|
+
direction: 'asc',
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
const result = await paginatedBuilder.execute()
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
set,
|
|
135
|
+
values: result.map((v) => v.value),
|
|
136
|
+
cursor: keyset.packFromResult(result),
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async upsert({
|
|
140
|
+
name,
|
|
141
|
+
description,
|
|
142
|
+
}: Pick<SetDetail, 'name' | 'description'>): Promise<void> {
|
|
143
|
+
await this.db.db
|
|
144
|
+
.insertInto('set_detail')
|
|
145
|
+
.values({
|
|
146
|
+
name,
|
|
147
|
+
description,
|
|
148
|
+
updatedAt: new Date(),
|
|
149
|
+
})
|
|
150
|
+
.onConflict((oc) => {
|
|
151
|
+
// if description is provided as a string, even an empty one, update it
|
|
152
|
+
// otherwise, just update the updatedAt timestamp
|
|
153
|
+
return oc.column('name').doUpdateSet(
|
|
154
|
+
typeof description === 'string'
|
|
155
|
+
? {
|
|
156
|
+
description,
|
|
157
|
+
updatedAt: new Date(),
|
|
158
|
+
}
|
|
159
|
+
: { updatedAt: new Date() },
|
|
160
|
+
)
|
|
161
|
+
})
|
|
162
|
+
.execute()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async addValues(setId: number, values: string[]): Promise<void> {
|
|
166
|
+
await this.db.transaction(async (txn) => {
|
|
167
|
+
const now = new Date()
|
|
168
|
+
const query = txn.db
|
|
169
|
+
.insertInto('set_value')
|
|
170
|
+
.values(
|
|
171
|
+
values.map((value) => ({
|
|
172
|
+
setId,
|
|
173
|
+
value,
|
|
174
|
+
createdAt: now,
|
|
175
|
+
})),
|
|
176
|
+
)
|
|
177
|
+
.onConflict((oc) => oc.columns(['setId', 'value']).doNothing())
|
|
178
|
+
|
|
179
|
+
await query.execute()
|
|
180
|
+
|
|
181
|
+
// Update the set's updatedAt timestamp
|
|
182
|
+
await txn.db
|
|
183
|
+
.updateTable('set_detail')
|
|
184
|
+
.set({ updatedAt: now })
|
|
185
|
+
.where('id', '=', setId)
|
|
186
|
+
.execute()
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async removeValues(setId: number, values: string[]): Promise<void> {
|
|
191
|
+
if (values.length < 1) {
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
await this.db.transaction(async (txn) => {
|
|
195
|
+
const query = txn.db
|
|
196
|
+
.deleteFrom('set_value')
|
|
197
|
+
.where('setId', '=', setId)
|
|
198
|
+
.where('value', 'in', values)
|
|
199
|
+
|
|
200
|
+
await query.execute()
|
|
201
|
+
|
|
202
|
+
// Update the set's updatedAt timestamp
|
|
203
|
+
await txn.db
|
|
204
|
+
.updateTable('set_detail')
|
|
205
|
+
.set({ updatedAt: new Date() })
|
|
206
|
+
.where('id', '=', setId)
|
|
207
|
+
.execute()
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async removeSet(setId: number): Promise<void> {
|
|
212
|
+
await this.db.transaction(async (txn) => {
|
|
213
|
+
await txn.db.deleteFrom('set_value').where('setId', '=', setId).execute()
|
|
214
|
+
await txn.db.deleteFrom('set_detail').where('id', '=', setId).execute()
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
view(set: Selectable<SetDetail> & { setSize: number }): SetView {
|
|
219
|
+
return {
|
|
220
|
+
name: set.name,
|
|
221
|
+
description: set.description || undefined,
|
|
222
|
+
setSize: set.setSize,
|
|
223
|
+
createdAt: set.createdAt.toISOString(),
|
|
224
|
+
updatedAt: set.updatedAt.toISOString(),
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`ozone-sets querySets returns all sets when no parameters are provided 1`] = `
|
|
4
|
+
Array [
|
|
5
|
+
Object {
|
|
6
|
+
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
7
|
+
"description": "Another test set",
|
|
8
|
+
"name": "another-set",
|
|
9
|
+
"setSize": 0,
|
|
10
|
+
"updatedAt": "1970-01-01T00:00:00.000Z",
|
|
11
|
+
},
|
|
12
|
+
Object {
|
|
13
|
+
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
14
|
+
"description": "Test set 1",
|
|
15
|
+
"name": "test-set-1",
|
|
16
|
+
"setSize": 0,
|
|
17
|
+
"updatedAt": "1970-01-01T00:00:00.000Z",
|
|
18
|
+
},
|
|
19
|
+
Object {
|
|
20
|
+
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
21
|
+
"name": "test-set-2",
|
|
22
|
+
"setSize": 0,
|
|
23
|
+
"updatedAt": "1970-01-01T00:00:00.000Z",
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
exports[`ozone-sets upsertSet creates a new set 1`] = `
|
|
29
|
+
Object {
|
|
30
|
+
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
31
|
+
"description": "A new test set",
|
|
32
|
+
"name": "new-test-set",
|
|
33
|
+
"setSize": 0,
|
|
34
|
+
"updatedAt": "1970-01-01T00:00:00.000Z",
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
exports[`ozone-sets upsertSet updates an existing set 1`] = `
|
|
39
|
+
Object {
|
|
40
|
+
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
41
|
+
"description": "Updated description",
|
|
42
|
+
"name": "new-test-set",
|
|
43
|
+
"setSize": 0,
|
|
44
|
+
"updatedAt": "1970-01-01T00:00:00.000Z",
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env'
|
|
2
|
+
import AtpAgent, {
|
|
3
|
+
ToolsOzoneSetDefs,
|
|
4
|
+
ToolsOzoneSetQuerySets,
|
|
5
|
+
} from '@atproto/api'
|
|
6
|
+
import { forSnapshot } from './_util'
|
|
7
|
+
import { ids } from '../src/lexicon/lexicons'
|
|
8
|
+
|
|
9
|
+
describe('ozone-sets', () => {
|
|
10
|
+
let network: TestNetwork
|
|
11
|
+
let agent: AtpAgent
|
|
12
|
+
let sc: SeedClient
|
|
13
|
+
|
|
14
|
+
const sampleSet1 = {
|
|
15
|
+
name: 'test-set-1',
|
|
16
|
+
description: 'Test set 1',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const sampleSet2 = {
|
|
20
|
+
name: 'test-set-2',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const sampleSet3 = {
|
|
24
|
+
name: 'another-set',
|
|
25
|
+
description: 'Another test set',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const upsertSet = async (set: ToolsOzoneSetDefs.Set) => {
|
|
29
|
+
const { data } = await agent.tools.ozone.set.upsertSet(set, {
|
|
30
|
+
encoding: 'application/json',
|
|
31
|
+
headers: await network.ozone.modHeaders(
|
|
32
|
+
ids.ToolsOzoneSetUpsertSet,
|
|
33
|
+
'admin',
|
|
34
|
+
),
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
return data
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const removeSet = async (name: string) => {
|
|
41
|
+
await agent.tools.ozone.set.deleteSet(
|
|
42
|
+
{ name },
|
|
43
|
+
{
|
|
44
|
+
encoding: 'application/json',
|
|
45
|
+
headers: await network.ozone.modHeaders(
|
|
46
|
+
ids.ToolsOzoneSetDeleteSet,
|
|
47
|
+
'admin',
|
|
48
|
+
),
|
|
49
|
+
},
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const addValues = async (name: string, values: string[]) => {
|
|
54
|
+
await agent.tools.ozone.set.addValues(
|
|
55
|
+
{ name, values },
|
|
56
|
+
{
|
|
57
|
+
encoding: 'application/json',
|
|
58
|
+
headers: await network.ozone.modHeaders(
|
|
59
|
+
ids.ToolsOzoneSetAddValues,
|
|
60
|
+
'admin',
|
|
61
|
+
),
|
|
62
|
+
},
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const getValues = async (name: string, limit?: number, cursor?: string) => {
|
|
67
|
+
const { data } = await agent.tools.ozone.set.getValues(
|
|
68
|
+
{ name, limit, cursor },
|
|
69
|
+
{
|
|
70
|
+
headers: await network.ozone.modHeaders(
|
|
71
|
+
ids.ToolsOzoneSetGetValues,
|
|
72
|
+
'moderator',
|
|
73
|
+
),
|
|
74
|
+
},
|
|
75
|
+
)
|
|
76
|
+
return data
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const querySets = async (params: ToolsOzoneSetQuerySets.QueryParams) => {
|
|
80
|
+
const { data } = await agent.tools.ozone.set.querySets(params, {
|
|
81
|
+
headers: await network.ozone.modHeaders(
|
|
82
|
+
ids.ToolsOzoneSetQuerySets,
|
|
83
|
+
'moderator',
|
|
84
|
+
),
|
|
85
|
+
})
|
|
86
|
+
return data
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
beforeAll(async () => {
|
|
90
|
+
network = await TestNetwork.create({
|
|
91
|
+
dbPostgresSchema: 'ozone_sets',
|
|
92
|
+
})
|
|
93
|
+
agent = network.ozone.getClient()
|
|
94
|
+
sc = network.getSeedClient()
|
|
95
|
+
await basicSeed(sc)
|
|
96
|
+
await network.processAll()
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
afterAll(async () => {
|
|
100
|
+
await network.close()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
describe('querySets', () => {
|
|
104
|
+
beforeAll(async () => {
|
|
105
|
+
await Promise.all([
|
|
106
|
+
upsertSet(sampleSet1),
|
|
107
|
+
upsertSet(sampleSet2),
|
|
108
|
+
upsertSet(sampleSet3),
|
|
109
|
+
])
|
|
110
|
+
})
|
|
111
|
+
afterAll(async () => {
|
|
112
|
+
await Promise.all([
|
|
113
|
+
removeSet(sampleSet1.name),
|
|
114
|
+
removeSet(sampleSet2.name),
|
|
115
|
+
removeSet(sampleSet3.name),
|
|
116
|
+
])
|
|
117
|
+
})
|
|
118
|
+
it('returns all sets when no parameters are provided', async () => {
|
|
119
|
+
const result = await querySets({})
|
|
120
|
+
expect(result.sets.length).toBe(3)
|
|
121
|
+
expect(forSnapshot(result.sets)).toMatchSnapshot()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('limits the number of returned sets', async () => {
|
|
125
|
+
const result = await querySets({ limit: 2 })
|
|
126
|
+
expect(result.sets.length).toBe(2)
|
|
127
|
+
expect(result.cursor).toBeDefined()
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('returns sets after the cursor', async () => {
|
|
131
|
+
const firstPage = await querySets({ limit: 2 })
|
|
132
|
+
const secondPage = await querySets({ cursor: firstPage.cursor })
|
|
133
|
+
expect(secondPage.sets.length).toBe(1)
|
|
134
|
+
expect(secondPage.sets[0].name).toBe('test-set-2')
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('filters sets by name prefix', async () => {
|
|
138
|
+
const result = await querySets({ namePrefix: 'test-' })
|
|
139
|
+
expect(result.sets.length).toBe(2)
|
|
140
|
+
expect(result.sets.map((s) => s.name)).toEqual([
|
|
141
|
+
'test-set-1',
|
|
142
|
+
'test-set-2',
|
|
143
|
+
])
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('sorts sets by given column and direction', async () => {
|
|
147
|
+
const sortedByName = await querySets({ sortBy: 'name' })
|
|
148
|
+
expect(sortedByName.sets.map((s) => s.name)).toEqual([
|
|
149
|
+
'another-set',
|
|
150
|
+
'test-set-1',
|
|
151
|
+
'test-set-2',
|
|
152
|
+
])
|
|
153
|
+
const reverseSortedByName = await querySets({
|
|
154
|
+
sortBy: 'name',
|
|
155
|
+
sortDirection: 'desc',
|
|
156
|
+
})
|
|
157
|
+
expect(reverseSortedByName.sets.map((s) => s.name)).toEqual([
|
|
158
|
+
'test-set-2',
|
|
159
|
+
'test-set-1',
|
|
160
|
+
'another-set',
|
|
161
|
+
])
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
describe('upsertSet', () => {
|
|
166
|
+
afterAll(async () => {
|
|
167
|
+
await removeSet('new-test-set')
|
|
168
|
+
})
|
|
169
|
+
it('creates a new set', async () => {
|
|
170
|
+
const result = await upsertSet({
|
|
171
|
+
name: 'new-test-set',
|
|
172
|
+
description: 'A new test set',
|
|
173
|
+
})
|
|
174
|
+
expect(forSnapshot(result)).toMatchSnapshot()
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('updates an existing set', async () => {
|
|
178
|
+
const result = await upsertSet({
|
|
179
|
+
name: 'new-test-set',
|
|
180
|
+
description: 'Updated description',
|
|
181
|
+
})
|
|
182
|
+
expect(forSnapshot(result)).toMatchSnapshot()
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('allows setting empty description', async () => {
|
|
186
|
+
const result = await upsertSet({
|
|
187
|
+
name: 'new-test-set',
|
|
188
|
+
description: '',
|
|
189
|
+
})
|
|
190
|
+
expect(result.description).toBeUndefined()
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
describe('addValues', () => {
|
|
195
|
+
beforeAll(async () => {
|
|
196
|
+
await upsertSet(sampleSet1)
|
|
197
|
+
await upsertSet(sampleSet2)
|
|
198
|
+
})
|
|
199
|
+
afterAll(async () => {
|
|
200
|
+
await removeSet(sampleSet1.name)
|
|
201
|
+
await removeSet(sampleSet2.name)
|
|
202
|
+
})
|
|
203
|
+
it('adds new values to an existing set', async () => {
|
|
204
|
+
const newValues = ['value1', 'value2', 'value3']
|
|
205
|
+
await addValues(sampleSet1.name, newValues)
|
|
206
|
+
|
|
207
|
+
const result = await getValues(sampleSet1.name)
|
|
208
|
+
expect(result.values).toEqual(expect.arrayContaining(newValues))
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('does not duplicate existing values', async () => {
|
|
212
|
+
const initialValues = ['initial1', 'initial2']
|
|
213
|
+
await addValues(sampleSet2.name, initialValues)
|
|
214
|
+
|
|
215
|
+
const newValues = ['initial2', 'new1', 'new2']
|
|
216
|
+
await addValues(sampleSet2.name, newValues)
|
|
217
|
+
|
|
218
|
+
const result = await getValues(sampleSet2.name)
|
|
219
|
+
expect(result.values).toEqual(
|
|
220
|
+
expect.arrayContaining([...initialValues, 'new1', 'new2']),
|
|
221
|
+
)
|
|
222
|
+
expect(result.values.filter((v) => v === 'initial2').length).toBe(1)
|
|
223
|
+
})
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
describe('getValues', () => {
|
|
227
|
+
beforeAll(async () => {
|
|
228
|
+
await upsertSet(sampleSet1)
|
|
229
|
+
})
|
|
230
|
+
afterAll(async () => {
|
|
231
|
+
await removeSet(sampleSet1.name)
|
|
232
|
+
})
|
|
233
|
+
it('paginates values from a set', async () => {
|
|
234
|
+
const allValues = Array.from({ length: 9 }, (_, i) => `value${i}`)
|
|
235
|
+
await addValues(sampleSet1.name, allValues)
|
|
236
|
+
|
|
237
|
+
const firstPage = await getValues(sampleSet1.name, 3)
|
|
238
|
+
const secondPage = await getValues(sampleSet1.name, 3, firstPage.cursor)
|
|
239
|
+
const lastPage = await getValues(sampleSet1.name, 3, secondPage.cursor)
|
|
240
|
+
|
|
241
|
+
expect(firstPage.values).toEqual(allValues.slice(0, 3))
|
|
242
|
+
expect(secondPage.values).toEqual(allValues.slice(3, 6))
|
|
243
|
+
expect(lastPage.values).toEqual(allValues.slice(6, 9))
|
|
244
|
+
})
|
|
245
|
+
})
|
|
246
|
+
})
|