Skip to content

Commit e03719b

Browse files
beck-8SgtPooki
andauthored
feat: add --data-set and --new-data-set flags to add command (#296)
* feat: add --data-set and --new-data-set flags to add command * fix: mutual exclusivity problem * chore: fix lint and use Number.isNaN --------- Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>
1 parent c52ebbf commit e03719b

File tree

4 files changed

+91
-23
lines changed

4 files changed

+91
-23
lines changed

src/add/add.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ export async function runAdd(options: AddOptions): Promise<AddResult> {
181181
...providerOptions,
182182
dataset: {
183183
...(dataSetMetadata && { metadata: dataSetMetadata }),
184+
...(options.dataSetId && { useExisting: options.dataSetId }),
185+
...(options.createNewDataSet && { createNew: true }),
184186
},
185187
callbacks: {
186188
onProviderSelected: (provider) => {

src/add/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import type { CLIAuthOptions } from '../utils/cli-auth.js'
44
export interface AddOptions extends CLIAuthOptions {
55
filePath: string
66
bare?: boolean
7+
/** ID of the existing data set to use */
8+
dataSetId?: number
9+
/** Create a new data set instead of using an existing one */
10+
createNewDataSet?: boolean
711
/** Auto-fund: automatically ensure minimum 30 days of runway */
812
autoFund?: boolean
913
/** Piece metadata attached to each upload */

src/commands/add.ts

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Command } from 'commander'
1+
import { Command, Option } from 'commander'
22
import { runAdd } from '../add/add.js'
33
import type { AddOptions } from '../add/types.js'
44
import { MIN_RUNWAY_DAYS } from '../common/constants.js'
@@ -10,30 +10,59 @@ export const addCommand = new Command('add')
1010
.argument('<path>', 'Path to the file or directory to add')
1111
.option('--bare', 'Add file without directory wrapper (files only, not supported for directories)')
1212
.option('--auto-fund', `Automatically ensure minimum ${MIN_RUNWAY_DAYS} days of runway before upload`)
13-
.action(async (path: string, options) => {
14-
try {
15-
const {
16-
metadata: _metadata,
17-
dataSetMetadata: _dataSetMetadata,
18-
datasetMetadata: _datasetMetadata,
19-
'8004Type': _erc8004Type,
20-
'8004Agent': _erc8004Agent,
21-
...addOptionsFromCli
22-
} = options
23-
const { pieceMetadata, dataSetMetadata } = resolveMetadataOptions(options, { includeErc8004: true })
24-
25-
const addOptions: AddOptions = {
26-
...addOptionsFromCli,
27-
filePath: path,
28-
...(pieceMetadata && { pieceMetadata }),
29-
...(dataSetMetadata && { dataSetMetadata }),
13+
14+
// Add data set selection options
15+
addCommand.addOption(
16+
new Option('--data-set <id>', 'ID of the existing data set to use').conflicts(['newDataSet', 'new-data-set'])
17+
)
18+
19+
addCommand.addOption(
20+
new Option('--new-data-set', 'Create a new data set instead of using an existing one').conflicts([
21+
'dataSet',
22+
'data-set',
23+
])
24+
)
25+
26+
addCommand.action(async (path: string, options: any) => {
27+
try {
28+
const {
29+
metadata: _metadata,
30+
dataSetMetadata: _dataSetMetadata,
31+
datasetMetadata: _datasetMetadata,
32+
'8004Type': _erc8004Type,
33+
'8004Agent': _erc8004Agent,
34+
dataSet,
35+
newDataSet,
36+
...addOptionsFromCli
37+
} = options
38+
const { pieceMetadata, dataSetMetadata } = resolveMetadataOptions(options, { includeErc8004: true })
39+
40+
// Normalize dataSet ID
41+
const rawDataSetId = dataSet
42+
let dataSetId: number | undefined
43+
44+
if (rawDataSetId) {
45+
dataSetId = parseInt(rawDataSetId, 10)
46+
if (Number.isNaN(dataSetId) || dataSetId < 0 || dataSetId.toString() !== rawDataSetId) {
47+
console.error('Error: Data set ID must be a valid positive integer')
48+
process.exit(1)
3049
}
50+
}
3151

32-
await runAdd(addOptions)
33-
} catch {
34-
process.exit(1)
52+
const addOptions: AddOptions = {
53+
...addOptionsFromCli,
54+
filePath: path,
55+
...(dataSetId !== undefined && { dataSetId }),
56+
...(newDataSet && { createNewDataSet: true }),
57+
...(pieceMetadata && { pieceMetadata }),
58+
...(dataSetMetadata && { dataSetMetadata }),
3559
}
36-
})
60+
61+
await runAdd(addOptions)
62+
} catch {
63+
process.exit(1)
64+
}
65+
})
3766

3867
addAuthOptions(addCommand)
3968
addProviderOptions(addCommand)

src/test/unit/add.test.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ describe('Add Command', () => {
206206
dataSetMetadata: { purpose: 'erc8004' },
207207
})
208208
const { createStorageContext, initializeSynapse } = await import('../../core/synapse/index.js')
209+
const { performUpload } = await import('../../common/upload-flow.js')
209210

210211
expect(vi.mocked(initializeSynapse)).toHaveBeenCalledWith(
211212
expect.objectContaining({
@@ -224,7 +225,6 @@ describe('Add Command', () => {
224225
})
225226
)
226227

227-
const { performUpload } = await import('../../common/upload-flow.js')
228228
expect(vi.mocked(performUpload)).toHaveBeenCalledWith(
229229
expect.anything(),
230230
expect.anything(),
@@ -235,6 +235,39 @@ describe('Add Command', () => {
235235
)
236236
})
237237

238+
it('passes data set selection options to storage context', async () => {
239+
await runAdd({
240+
filePath: testFile,
241+
privateKey: 'test-private-key',
242+
rpcUrl: 'wss://test.rpc.url',
243+
dataSetId: 123,
244+
})
245+
const { createStorageContext } = await import('../../core/synapse/index.js')
246+
expect(vi.mocked(createStorageContext)).toHaveBeenCalledWith(
247+
expect.anything(),
248+
expect.objectContaining({
249+
dataset: expect.objectContaining({
250+
useExisting: 123,
251+
}),
252+
})
253+
)
254+
255+
await runAdd({
256+
filePath: testFile,
257+
privateKey: 'test-private-key',
258+
rpcUrl: 'wss://test.rpc.url',
259+
createNewDataSet: true,
260+
})
261+
expect(vi.mocked(createStorageContext)).toHaveBeenCalledWith(
262+
expect.anything(),
263+
expect.objectContaining({
264+
dataset: expect.objectContaining({
265+
createNew: true,
266+
}),
267+
})
268+
)
269+
})
270+
238271
it('should reject when file does not exist', async () => {
239272
const mockExit = vi.spyOn(process, 'exit')
240273

0 commit comments

Comments
 (0)