feat: rm infer type and regex logic
This commit is contained in:
@@ -131,8 +131,13 @@ export async function writeDataToAirtable(
|
|||||||
const base = airtable.base(baseId);
|
const base = airtable.base(baseId);
|
||||||
|
|
||||||
const existingFields = await getExistingFields(base, tableName);
|
const existingFields = await getExistingFields(base, tableName);
|
||||||
|
console.log(`Found ${existingFields.length} existing fields in Airtable`);
|
||||||
|
|
||||||
const dataFields = [...new Set(data.flatMap(row => Object.keys(row)))];
|
const dataFields = [...new Set(data.flatMap(row => Object.keys(row)))];
|
||||||
|
console.log(`Found ${dataFields.length} fields in data: ${dataFields.join(', ')}`);
|
||||||
|
|
||||||
const missingFields = dataFields.filter(field => !existingFields.includes(field));
|
const missingFields = dataFields.filter(field => !existingFields.includes(field));
|
||||||
|
console.log(`Found ${missingFields.length} missing fields: ${missingFields.join(', ')}`);
|
||||||
|
|
||||||
for (const field of missingFields) {
|
for (const field of missingFields) {
|
||||||
const sampleRow = data.find(row => field in row);
|
const sampleRow = data.find(row => field in row);
|
||||||
@@ -238,18 +243,12 @@ async function createAirtableField(
|
|||||||
retries = MAX_RETRIES
|
retries = MAX_RETRIES
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const sanitizedFieldName = sanitizeFieldName(fieldName);
|
|
||||||
const fieldType = inferFieldType(sampleValue);
|
|
||||||
|
|
||||||
console.log(`Creating field ${sanitizedFieldName} with type ${fieldType}`);
|
|
||||||
|
|
||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`https://api.airtable.com/v0/meta/bases/${baseId}/tables/${tableId}/fields`,
|
`https://api.airtable.com/v0/meta/bases/${baseId}/tables/${tableId}/fields`,
|
||||||
{ name: sanitizedFieldName, type: fieldType },
|
{ name: fieldName },
|
||||||
{ headers: { Authorization: `Bearer ${accessToken}` } }
|
{ headers: { Authorization: `Bearer ${accessToken}` } }
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.log('info', `Created field: ${sanitizedFieldName} (${fieldType})`);
|
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (retries > 0 && error.response?.status === 429) {
|
if (retries > 0 && error.response?.status === 429) {
|
||||||
@@ -268,35 +267,6 @@ async function createAirtableField(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sanitizeFieldName(fieldName: string): string {
|
|
||||||
return fieldName
|
|
||||||
.trim()
|
|
||||||
.replace(/^[^a-zA-Z]+/, '')
|
|
||||||
.replace(/[^\w\s]/gi, ' ')
|
|
||||||
.substring(0, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
function inferFieldType(value: any): string {
|
|
||||||
if (value === null || value === undefined) return 'singleLineText';
|
|
||||||
if (typeof value === 'number') return 'number';
|
|
||||||
if (typeof value === 'boolean') return 'checkbox';
|
|
||||||
if (value instanceof Date) return 'dateTime';
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
return value.length > 0 && typeof value[0] === 'object' ? 'multipleRecordLinks' : 'multipleSelects';
|
|
||||||
}
|
|
||||||
if (typeof value === 'string' && isValidUrl(value)) return 'url';
|
|
||||||
return 'singleLineText';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValidUrl(str: string): boolean {
|
|
||||||
try {
|
|
||||||
new URL(str);
|
|
||||||
return true;
|
|
||||||
} catch (_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const processAirtableUpdates = async () => {
|
export const processAirtableUpdates = async () => {
|
||||||
while (true) {
|
while (true) {
|
||||||
let hasPendingTasks = false;
|
let hasPendingTasks = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user