Skip to content

Commit 7c30a16

Browse files
committed
Fix pulling bambu x1 data issue with missing row data
1 parent e6bbdb3 commit 7c30a16

File tree

6 files changed

+83
-38
lines changed

6 files changed

+83
-38
lines changed

src/init-dependencies/google/pull_sheet_data.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,21 @@ export const GoogleSpreadsheetDataForSheet = t.strict({
5252
sheets: tt.nonEmptyArray(
5353
// Array always has length = 1 because this is data for a single sheet.
5454
t.strict({
55-
data: tt.nonEmptyArray(
55+
data: t.array(
5656
t.strict({
57-
rowData: tt.nonEmptyArray(
58-
t.strict({
59-
values: tt.nonEmptyArray(
60-
t.strict({
61-
formattedValue: tt.withFallback(t.string, ''),
62-
})
63-
),
64-
})
65-
),
57+
rowData: t.union([
58+
t.array(
59+
t.strict({
60+
values: t.array(
61+
t.strict({
62+
formattedValue: tt.withFallback(t.string, ''),
63+
})
64+
),
65+
})
66+
),
67+
t.undefined,
68+
t.null,
69+
]),
6670
})
6771
),
6872
})

src/read-models/shared-state/async-apply-external-event-sources.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ const pullNewEquipmentQuizResultsForSheet = async (
6363
maxCol
6464
)();
6565
if (E.isLeft(data)) {
66-
logger.debug(
66+
logger.error(
67+
data.left,
6768
'Failed to pull data for sheet %s rows %s to %s, skipping rest of sheet'
6869
);
6970
return;

src/training-sheets/extract-metadata.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import * as O from 'fp-ts/Option';
33

44
import {Logger} from 'pino';
55
import {GoogleSpreadsheetDataForSheet} from '../init-dependencies/google/pull_sheet_data';
6+
import {array} from 'fp-ts';
7+
import {pipe} from 'fp-ts/lib/function';
68

79
const EMAIL_COLUMN_NAMES = ['email address', 'email'];
810

@@ -37,22 +39,29 @@ export const extractGoogleSheetMetadata =
3739
firstRowData: GoogleSpreadsheetDataForSheet
3840
): O.Option<GoogleSheetMetadata> => {
3941
logger = logger.child({sheetName: initialMeta.properties.title});
40-
const columnNames = firstRowData.sheets[0].data[0].rowData[0].values.map(
41-
col => col.formattedValue
42+
const columnNames: O.Option<string[]> = pipe(
43+
firstRowData.sheets[0].data,
44+
array.lookup(0),
45+
O.flatMap(sheetData => O.fromNullable(sheetData.rowData)),
46+
O.flatMap(array.lookup(0)),
47+
O.flatMap(firstRowData =>
48+
O.some(firstRowData.values.map(col => col.formattedValue))
49+
)
4250
);
51+
if (O.isNone(columnNames)) {
52+
logger.error('Found no column names for sheet, skipping sheet');
53+
return O.none;
54+
}
4355
logger.trace('Found column names for sheet: %o', columnNames);
4456
const timestamp = RA.findIndex<string>(
4557
val => val.toLowerCase() === 'timestamp'
46-
)(columnNames);
58+
)(columnNames.value);
4759
if (O.isNone(timestamp)) {
48-
logger.warn(
49-
'Failed to find timestamp column, skipping sheet: %s',
50-
initialMeta.properties.title
51-
);
60+
logger.warn('Failed to find timestamp column, skipping sheet');
5261
return O.none;
5362
}
5463
const score = RA.findIndex<string>(val => val.toLowerCase() === 'score')(
55-
columnNames
64+
columnNames.value
5665
);
5766
if (O.isNone(score)) {
5867
logger.warn(
@@ -63,10 +72,10 @@ export const extractGoogleSheetMetadata =
6372
}
6473
const memberNumber = RA.findIndex<string>(
6574
val => val.toLowerCase() === 'membership number'
66-
)(columnNames);
75+
)(columnNames.value);
6776
const email = RA.findIndex<string>(val =>
6877
EMAIL_COLUMN_NAMES.includes(val.toLowerCase())
69-
)(columnNames);
78+
)(columnNames.value);
7079

7180
return O.some({
7281
name: initialMeta.properties.title,

src/training-sheets/google.ts

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {EpochTimestampMilliseconds} from '../read-models/shared-state/return-typ
1212
import {GoogleSheetMetadata} from './extract-metadata';
1313
import {GoogleSpreadsheetDataForSheet} from '../init-dependencies/google/pull_sheet_data';
1414
import {lookup} from 'fp-ts/ReadonlyArray';
15+
import {array} from 'fp-ts';
1516

1617
// Bounds to prevent clearly broken parsing.
1718
const MIN_RECOGNISED_MEMBER_NUMBER = 0;
@@ -270,16 +271,35 @@ export const extractGoogleSheetData =
270271
spreadsheet: GoogleSpreadsheetDataForSheet
271272
): ReadonlyArray<EventOfType<'EquipmentTrainingQuizResult'>> => {
272273
return pipe(
273-
spreadsheet.sheets[0].data[0].rowData,
274-
RA.map(
275-
extractFromRow(logger, metadata, equipmentId, trainingSheetId, timezone)
274+
spreadsheet.sheets[0].data,
275+
array.lookup(0),
276+
O.flatMap(sheetData => O.fromNullable(sheetData.rowData)),
277+
O.flatMap(row_data =>
278+
O.some(
279+
pipe(
280+
row_data,
281+
RA.map(
282+
extractFromRow(
283+
logger,
284+
metadata,
285+
equipmentId,
286+
trainingSheetId,
287+
timezone
288+
)
289+
),
290+
RA.filterMap(e => e),
291+
RA.filter(
292+
e =>
293+
O.isNone(eventsFromExclusive) ||
294+
e.timestampEpochMS > eventsFromExclusive.value
295+
)
296+
)
297+
)
276298
),
277-
RA.filterMap(e => e),
278-
RA.filter(
279-
e =>
280-
O.isNone(eventsFromExclusive) ||
281-
e.timestampEpochMS > eventsFromExclusive.value
282-
)
299+
O.getOrElse(() => {
300+
logger.warn('Failed to get row data, skipping');
301+
return [] as ReadonlyArray<EventOfType<'EquipmentTrainingQuizResult'>>;
302+
})
283303
);
284304
};
285305

tests/init-dependencies/pull-local-google.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ const localPullGoogleSheetData = (
3333
gsheetData.TRAINING_SHEETS[trainingSheetId].sheets[sheetName]
3434
);
3535
if (sheet) {
36-
if (rowStart > sheet.sheets[0].data[0].rowData.length) {
36+
const rowData = sheet.sheets[0].data[0].rowData!;
37+
if (rowStart > rowData.length) {
3738
return TE.left('Sheet no more data');
3839
}
39-
sheet.sheets[0].data[0].rowData = sheet.sheets[0].data[0].rowData.slice(
40+
sheet.sheets[0].data[0].rowData = rowData.slice(
4041
rowStart - 1, // 1 indexed.
4142
rowEnd
4243
) as NonEmptyArray<{

tests/training-sheets/integration.test.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const getEvents = async (trainingSheetId: string) => {
3737
});
3838
const events: DomainEvent[] = [];
3939
await pullNewEquipmentQuizResults(
40-
pino({level: 'silent'}),
40+
pino({level: 'trace'}),
4141
{
4242
pullGoogleSheetData: pullGoogleSheetData(auth),
4343
pullGoogleSheetDataMetadata: pullGoogleSheetDataMetadata(auth),
@@ -189,6 +189,21 @@ describe('Google training sheet integration', () => {
189189

190190
expect(userEvents).toStrictEqual(expected);
191191
});
192+
it('Bambu X1', async () => {
193+
const events = await getEvents(
194+
'1i1vJmCO8_Dkpbv-izOSkffoAeJTNrJsmAV5hD0w2ADw'
195+
);
196+
expect(events).toHaveLength(729); // Obviously this will change so you will need to manually update.
197+
const userEvents = pipe(
198+
events,
199+
filterUserEvents(TEST_USER),
200+
RA.sort(ordByTimestampEpoch),
201+
redactEmail,
202+
stripNonStatic
203+
);
204+
console.log(userEvents);
205+
expect(userEvents).toHaveLength(3);
206+
}, 30000);
192207

193208
// it('Metal Lathe', async () => {
194209
// const events = await getEvents(
@@ -284,9 +299,4 @@ describe('Google training sheet integration', () => {
284299
// '1yulN3ewYS2XpT22joP5HteZ9H9qebvSEcFXQhxPwXlk'
285300
// );
286301
// });
287-
// it.skip('Bambu', async () => {
288-
// const _events = await getEvents(
289-
// '1i1vJmCO8_Dkpbv-izOSkffoAeJTNrJsmAV5hD0w2ADw'
290-
// );
291-
// });
292302
});

0 commit comments

Comments
 (0)