Skip to content

Commit ef94ff8

Browse files
committed
chore(user-data): remove redundant withStats methods
1 parent b1e7351 commit ef94ff8

File tree

5 files changed

+39
-187
lines changed

5 files changed

+39
-187
lines changed

packages/compass-preferences-model/src/user-storage.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,4 @@ export class UserStorageImpl implements UserStorage {
7979
await this.userData.write(user.id, user);
8080
return this.getUser(user.id);
8181
}
82-
83-
private getFileName(id: string) {
84-
return `${id}.json`;
85-
}
8682
}

packages/compass-user-data/src/user-data.spec.ts

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -125,39 +125,6 @@ describe('user-data', function () {
125125
expect(result.data).to.have.lengthOf(0);
126126
expect(result.errors).to.have.lengthOf(2);
127127
});
128-
129-
it('returns file stats', async function () {
130-
await Promise.all(
131-
[
132-
['data1.json', JSON.stringify({ name: 'VSCode' })],
133-
['data2.json', JSON.stringify({ name: 'Mongosh' })],
134-
].map(([filepath, data]) => writeFileToStorage(filepath, data))
135-
);
136-
137-
const { data } = await getUserData().readAllWithStats({
138-
ignoreErrors: true,
139-
});
140-
141-
{
142-
const vscodeData = data.find((x) => x[0].name === 'VSCode');
143-
expect(vscodeData?.[0]).to.deep.equal({
144-
name: 'VSCode',
145-
hasDarkMode: true,
146-
hasWebSupport: false,
147-
});
148-
expect(vscodeData?.[1]).to.be.instanceOf(Stats);
149-
}
150-
151-
{
152-
const mongoshData = data.find((x) => x[0].name === 'Mongosh');
153-
expect(mongoshData?.[0]).to.deep.equal({
154-
name: 'Mongosh',
155-
hasDarkMode: true,
156-
hasWebSupport: false,
157-
});
158-
expect(mongoshData?.[1]).to.be.instanceOf(Stats);
159-
}
160-
});
161128
});
162129

163130
context('UserData.readOne', function () {
@@ -302,27 +269,6 @@ describe('user-data', function () {
302269
company: 'MongoDB',
303270
});
304271
});
305-
306-
it('return file stats', async function () {
307-
await writeFileToStorage(
308-
'data.json',
309-
JSON.stringify({
310-
name: 'Mongosh',
311-
company: 'MongoDB',
312-
})
313-
);
314-
315-
const [data, stats] = await getUserData().readOneWithStats('data', {
316-
ignoreErrors: false,
317-
});
318-
319-
expect(data).to.deep.equal({
320-
name: 'Mongosh',
321-
hasDarkMode: true,
322-
hasWebSupport: false,
323-
});
324-
expect(stats).to.be.instanceOf(Stats);
325-
});
326272
});
327273

328274
context('UserData.write', function () {

packages/compass-user-data/src/user-data.ts

Lines changed: 33 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@ const { log, mongoLogId } = createLogger('COMPASS-USER-STORAGE');
1010

1111
type SerializeContent<I> = (content: I) => string;
1212
type DeserializeContent = (content: string) => unknown;
13-
type GetFileName = (id: string) => string;
1413

1514
export type FileUserDataOptions<Input> = {
1615
subdir: string;
1716
basePath?: string;
1817
serialize?: SerializeContent<Input>;
1918
deserialize?: DeserializeContent;
20-
getFileName?: GetFileName;
2119
};
2220

2321
export type AtlasUserDataOptions<Input> = {
@@ -29,45 +27,11 @@ type ReadOptions = {
2927
ignoreErrors: boolean;
3028
};
3129

32-
// Copied from the Node.js fs module.
33-
export interface Stats {
34-
isFile(): boolean;
35-
isDirectory(): boolean;
36-
isBlockDevice(): boolean;
37-
isCharacterDevice(): boolean;
38-
isSymbolicLink(): boolean;
39-
isFIFO(): boolean;
40-
isSocket(): boolean;
41-
dev: number;
42-
ino: number;
43-
mode: number;
44-
nlink: number;
45-
uid: number;
46-
gid: number;
47-
rdev: number;
48-
size: number;
49-
blksize: number;
50-
blocks: number;
51-
atimeMs: number;
52-
mtimeMs: number;
53-
ctimeMs: number;
54-
birthtimeMs: number;
55-
atime: Date;
56-
mtime: Date;
57-
ctime: Date;
58-
birthtime: Date;
59-
}
60-
6130
export interface ReadAllResult<T extends z.Schema> {
6231
data: z.output<T>[];
6332
errors: Error[];
6433
}
6534

66-
export interface ReadAllWithStatsResult<T extends z.Schema> {
67-
data: [z.output<T>, Stats][];
68-
errors: Error[];
69-
}
70-
7135
export abstract class IUserData<T extends z.Schema> {
7236
protected readonly validator: T;
7337
protected readonly serialize: SerializeContent<z.input<T>>;
@@ -100,7 +64,6 @@ export abstract class IUserData<T extends z.Schema> {
10064
export class FileUserData<T extends z.Schema> extends IUserData<T> {
10165
private readonly subdir: string;
10266
private readonly basePath?: string;
103-
private readonly getFileName: GetFileName;
10467
protected readonly semaphore = new Semaphore(100);
10568

10669
constructor(
@@ -110,13 +73,15 @@ export class FileUserData<T extends z.Schema> extends IUserData<T> {
11073
basePath,
11174
serialize,
11275
deserialize,
113-
getFileName = (id) => `${id}.json`,
11476
}: FileUserDataOptions<z.input<T>>
11577
) {
11678
super(validator, { serialize, deserialize });
11779
this.subdir = subdir;
11880
this.basePath = basePath;
119-
this.getFileName = getFileName;
81+
}
82+
83+
private getFileName(id: string) {
84+
return `${id}.json`;
12085
}
12186

12287
private async getEnsuredBasePath(): Promise<string> {
@@ -148,21 +113,15 @@ export class FileUserData<T extends z.Schema> extends IUserData<T> {
148113
return path.resolve(root, pathRelativeToRoot);
149114
}
150115

151-
private async readAndParseFileWithStats(
116+
private async readAndParseFile(
152117
absolutePath: string,
153118
options: ReadOptions
154-
): Promise<[z.output<T>, Stats] | undefined> {
119+
): Promise<z.output<T> | undefined> {
155120
let data: string;
156-
let stats: Stats;
157-
let handle: fs.FileHandle | undefined = undefined;
158121
let release: (() => void) | undefined = undefined;
159122
try {
160123
release = await this.semaphore.waitForRelease();
161-
handle = await fs.open(absolutePath, 'r');
162-
[stats, data] = await Promise.all([
163-
handle.stat(),
164-
handle.readFile('utf-8'),
165-
]);
124+
data = await fs.readFile(absolutePath, 'utf-8');
166125
} catch (error) {
167126
log.error(mongoLogId(1_001_000_234), 'Filesystem', 'Error reading file', {
168127
path: absolutePath,
@@ -173,13 +132,12 @@ export class FileUserData<T extends z.Schema> extends IUserData<T> {
173132
}
174133
throw error;
175134
} finally {
176-
await handle?.close();
177135
release?.();
178136
}
179137

180138
try {
181139
const content = this.deserialize(data);
182-
return [this.validator.parse(content), stats];
140+
return this.validator.parse(content);
183141
} catch (error) {
184142
log.error(mongoLogId(1_001_000_235), 'Filesystem', 'Error parsing data', {
185143
path: absolutePath,
@@ -235,70 +193,37 @@ export class FileUserData<T extends z.Schema> extends IUserData<T> {
235193
}
236194
}
237195

238-
async readAllWithStats(
196+
async readAll(
239197
options: ReadOptions = {
240198
ignoreErrors: true,
241199
}
242-
): Promise<ReadAllWithStatsResult<T>> {
243-
const absolutePath = await this.getFileAbsolutePath();
244-
const filePathList = await fs.readdir(absolutePath);
245-
246-
const data = await Promise.allSettled(
247-
filePathList.map((x) =>
248-
this.readAndParseFileWithStats(path.join(absolutePath, x), options)
249-
)
250-
);
251-
252-
const result: ReadAllWithStatsResult<T> = {
200+
): Promise<ReadAllResult<T>> {
201+
const result: ReadAllResult<T> = {
253202
data: [],
254203
errors: [],
255204
};
256-
257-
for (const item of data) {
258-
if (item.status === 'fulfilled' && item.value) {
259-
result.data.push(item.value);
205+
try {
206+
const absolutePath = await this.getFileAbsolutePath();
207+
const filePathList = await fs.readdir(absolutePath);
208+
for (const settled of await Promise.allSettled(
209+
filePathList.map((x) => {
210+
return this.readAndParseFile(path.join(absolutePath, x), options);
211+
})
212+
)) {
213+
if (settled.status === 'fulfilled' && settled.value) {
214+
result.data.push(settled.value);
215+
}
216+
if (settled.status === 'rejected') {
217+
result.errors.push(settled.reason);
218+
}
260219
}
261-
if (item.status === 'rejected') {
262-
result.errors.push(item.reason);
220+
return result;
221+
} catch (err) {
222+
if (options.ignoreErrors) {
223+
return result;
263224
}
225+
throw err;
264226
}
265-
266-
return result;
267-
}
268-
269-
async readOneWithStats(
270-
id: string,
271-
options?: { ignoreErrors: false }
272-
): Promise<[z.output<T>, Stats]>;
273-
async readOneWithStats(
274-
id: string,
275-
options?: { ignoreErrors: true }
276-
): Promise<[z.output<T>, Stats] | undefined>;
277-
async readOneWithStats(
278-
id: string,
279-
options?: ReadOptions
280-
): Promise<[z.output<T>, Stats] | undefined>;
281-
async readOneWithStats(
282-
id: string,
283-
options: ReadOptions = {
284-
ignoreErrors: true,
285-
}
286-
) {
287-
const filepath = this.getFileName(id);
288-
const absolutePath = await this.getFileAbsolutePath(filepath);
289-
return await this.readAndParseFileWithStats(absolutePath, options);
290-
}
291-
292-
async readAll(
293-
options: ReadOptions = {
294-
ignoreErrors: true,
295-
}
296-
): Promise<ReadAllResult<T>> {
297-
const result = await this.readAllWithStats(options);
298-
return {
299-
data: result.data.map(([data]) => data),
300-
errors: result.errors,
301-
};
302227
}
303228

304229
async readOne(
@@ -319,7 +244,9 @@ export class FileUserData<T extends z.Schema> extends IUserData<T> {
319244
ignoreErrors: true,
320245
}
321246
) {
322-
return (await this.readOneWithStats(id, options))?.[0];
247+
const filepath = this.getFileName(id);
248+
const absolutePath = await this.getFileAbsolutePath(filepath);
249+
return await this.readAndParseFile(absolutePath, options);
323250
}
324251

325252
async updateAttributes(

packages/my-queries-storage/src/compass-pipeline-storage.ts

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { Stats } from '@mongodb-js/compass-user-data';
21
import { FileUserData } from '@mongodb-js/compass-user-data';
32
import { PipelineSchema } from './pipeline-storage-schema';
43
import type { SavedPipeline } from './pipeline-storage-schema';
@@ -13,21 +12,10 @@ export class CompassPipelineStorage implements PipelineStorage {
1312
});
1413
}
1514

16-
private mergeStats(pipeline: SavedPipeline, stats: Stats): SavedPipeline {
17-
return {
18-
...pipeline,
19-
lastModified: new Date(stats.ctimeMs),
20-
};
21-
}
22-
2315
async loadAll(): Promise<SavedPipeline[]> {
2416
try {
25-
const { data } = await this.userData.readAllWithStats({
26-
ignoreErrors: false,
27-
});
28-
return data.map(([item, stats]) => {
29-
return this.mergeStats(item, stats);
30-
});
17+
const { data } = await this.userData.readAll();
18+
return data;
3119
} catch {
3220
return [];
3321
}
@@ -41,16 +29,11 @@ export class CompassPipelineStorage implements PipelineStorage {
4129
}
4230

4331
private async loadOne(id: string): Promise<SavedPipeline> {
44-
const [item, stats] = await this.userData.readOneWithStats(id);
45-
return this.mergeStats(item, stats);
32+
return await this.userData.readOne(id);
4633
}
4734

4835
async createOrUpdate(id: string, attributes: SavedPipeline) {
49-
const pipelineExists = Boolean(
50-
await this.userData.readOne(id, {
51-
ignoreErrors: true,
52-
})
53-
);
36+
const pipelineExists = Boolean(await this.userData.readOne(id));
5437
return await (pipelineExists
5538
? this.updateAttributes(id, attributes)
5639
: this.create(attributes));

packages/my-queries-storage/src/pipeline-storage-schema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ export const PipelineSchema = z.preprocess(
6262
pipelineText: z.string(),
6363
lastModified: z
6464
.number()
65-
.transform((x) => new Date(x))
66-
.optional(),
65+
.default(0)
66+
.transform((x) => new Date(x)),
6767
})
6868
);
6969

0 commit comments

Comments
 (0)