mirror of https://github.com/nocodb/nocodb
mertmit
3 years ago
committed by
Raju Udava
4 changed files with 1162 additions and 1 deletions
@ -0,0 +1,337 @@ |
|||||||
|
{ |
||||||
|
"appBlanket": { |
||||||
|
"userInfoById": { |
||||||
|
"usrcTFn14vKTIgbW3": { |
||||||
|
"id": "usrcTFn14vKTIgbW3", |
||||||
|
"firstName": "Steyer", |
||||||
|
"lastName": "Rom", |
||||||
|
"email": "steyerrom@gmail.com", |
||||||
|
"profilePicUrl": "https://static.airtable.com/images/userIcons/user_icon_9.png", |
||||||
|
"permissionLevel": "owner", |
||||||
|
"appBlanketUserState": "active" |
||||||
|
} |
||||||
|
}, |
||||||
|
"externalAccountInfoById": {}, |
||||||
|
"userGroupInfoById": {}, |
||||||
|
"workspaceSyncSources": [], |
||||||
|
"activeUserIdByAcceptedInviteId": {}, |
||||||
|
"isWorkspaceOptedOutOfUserContentCdnAuth": false, |
||||||
|
"isEnterpriseAccountOptedOutOfUserContentCdnAuth": false, |
||||||
|
"enterpriseAttachmentRestrictions": { |
||||||
|
"restrictionType": "unrestricted", |
||||||
|
"attachmentTypeAllowlist": [] |
||||||
|
}, |
||||||
|
"isWorkspaceLinkedToEnterpriseAccount": false |
||||||
|
}, |
||||||
|
"description": null, |
||||||
|
"sortTiebreakerKey": "appEHTLsc4lSaia9A", |
||||||
|
"defaultViewMutability": null, |
||||||
|
"maintenanceModeSettings": null, |
||||||
|
"sharesById": { |
||||||
|
"shrqM5QS9sSZ94mQx": { |
||||||
|
"id": "shrqM5QS9sSZ94mQx", |
||||||
|
"modelId": "appEHTLsc4lSaia9A", |
||||||
|
"createdByUserId": "usrcTFn14vKTIgbW3", |
||||||
|
"canBeCloned": false, |
||||||
|
"canBeExported": false, |
||||||
|
"includeHiddenColumns": false, |
||||||
|
"includeBlocks": true, |
||||||
|
"emailDomain": null, |
||||||
|
"hasPassword": false, |
||||||
|
"generationNumber": 0, |
||||||
|
"metadata": null |
||||||
|
} |
||||||
|
}, |
||||||
|
"workflowSectionsById": {}, |
||||||
|
"applicationTransactionNumber": 21, |
||||||
|
"tableSchemas": [ |
||||||
|
{ |
||||||
|
"id": "tblXYuhMZ3hWZkBCa", |
||||||
|
"name": "Table 1", |
||||||
|
"primaryColumnId": "fldrhmH0EYnOXfnUA", |
||||||
|
"columns": [ |
||||||
|
{ |
||||||
|
"id": "fldrhmH0EYnOXfnUA", |
||||||
|
"name": "Name", |
||||||
|
"type": "text" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": "fldVFoK7t6aC92xzj", |
||||||
|
"name": "Notes", |
||||||
|
"type": "multilineText" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": "fld66bK6Pq8AG4m3h", |
||||||
|
"name": "Attachments", |
||||||
|
"type": "multipleAttachment", |
||||||
|
"typeOptions": { |
||||||
|
"unreversed": true |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": "fldRC8zKoyGzM6agG", |
||||||
|
"name": "Status", |
||||||
|
"type": "select", |
||||||
|
"typeOptions": { |
||||||
|
"choices": { |
||||||
|
"selQSYarqhTyVrwZw": { |
||||||
|
"id": "selQSYarqhTyVrwZw", |
||||||
|
"name": "Todo", |
||||||
|
"color": "red" |
||||||
|
}, |
||||||
|
"selOFyoifOyV50QI7": { |
||||||
|
"id": "selOFyoifOyV50QI7", |
||||||
|
"name": "In progress", |
||||||
|
"color": "yellow" |
||||||
|
}, |
||||||
|
"selsxseijq4XvcTB8": { |
||||||
|
"id": "selsxseijq4XvcTB8", |
||||||
|
"name": "Done", |
||||||
|
"color": "green" |
||||||
|
} |
||||||
|
}, |
||||||
|
"choiceOrder": [ |
||||||
|
"selQSYarqhTyVrwZw", |
||||||
|
"selOFyoifOyV50QI7", |
||||||
|
"selsxseijq4XvcTB8" |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
"meaningfulColumnOrder": [ |
||||||
|
{ |
||||||
|
"columnId": "fldrhmH0EYnOXfnUA", |
||||||
|
"visibility": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"columnId": "fldVFoK7t6aC92xzj", |
||||||
|
"visibility": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"columnId": "fld66bK6Pq8AG4m3h", |
||||||
|
"visibility": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"columnId": "fldRC8zKoyGzM6agG", |
||||||
|
"visibility": true |
||||||
|
} |
||||||
|
], |
||||||
|
"views": [ |
||||||
|
{ |
||||||
|
"id": "viwbgKWGvUoZCosF1", |
||||||
|
"name": "Grid view", |
||||||
|
"type": "grid", |
||||||
|
"createdByUserId": "usrcTFn14vKTIgbW3" |
||||||
|
} |
||||||
|
], |
||||||
|
"viewOrder": [ |
||||||
|
"viwbgKWGvUoZCosF1" |
||||||
|
], |
||||||
|
"viewsById": { |
||||||
|
"viwbgKWGvUoZCosF1": { |
||||||
|
"id": "viwbgKWGvUoZCosF1", |
||||||
|
"name": "Grid view", |
||||||
|
"type": "grid", |
||||||
|
"createdByUserId": "usrcTFn14vKTIgbW3" |
||||||
|
} |
||||||
|
}, |
||||||
|
"viewSectionsById": {}, |
||||||
|
"schemaChecksum": "412180368d81674e723b957501f16a57c9264fc69d19668b70d1547888c29413" |
||||||
|
} |
||||||
|
], |
||||||
|
"tableDatas": [ |
||||||
|
{ |
||||||
|
"id": "tblXYuhMZ3hWZkBCa", |
||||||
|
"rows": [ |
||||||
|
{ |
||||||
|
"id": "recv9Z8uFFNt50rqX", |
||||||
|
"createdTime": "2022-04-27T18:48:37.000Z", |
||||||
|
"cellValuesByColumnId": { |
||||||
|
"fld66bK6Pq8AG4m3h": [ |
||||||
|
{ |
||||||
|
"id": "attdRIU80oCDC8u6X", |
||||||
|
"url": "https://dl.airtable.com/.attachments/247a5881e7742c2d55cb8f814fe7263a/964d1018/512x512.png", |
||||||
|
"filename": "512x512.png", |
||||||
|
"type": "image/png", |
||||||
|
"size": 77822, |
||||||
|
"width": 2763, |
||||||
|
"height": 2763, |
||||||
|
"smallThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/f5f0717d00f1f61c402fec203d16efd7/61bea79e", |
||||||
|
"smallThumbWidth": 36, |
||||||
|
"smallThumbHeight": 36, |
||||||
|
"largeThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/8f49ea3dcdaf3aa9788e84f1a3e3f3e2/81284101", |
||||||
|
"largeThumbWidth": 512, |
||||||
|
"largeThumbHeight": 512, |
||||||
|
"fullThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/c5300e8cda92de966de82c760cd44533/89d51367", |
||||||
|
"fullThumbWidth": 3000, |
||||||
|
"fullThumbHeight": 3000 |
||||||
|
} |
||||||
|
], |
||||||
|
"fldrhmH0EYnOXfnUA": "nc" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": "recmAktd3OQe3Wg8C", |
||||||
|
"createdTime": "2022-04-27T18:48:37.000Z", |
||||||
|
"cellValuesByColumnId": { |
||||||
|
"fld66bK6Pq8AG4m3h": [ |
||||||
|
{ |
||||||
|
"id": "attLBB2eqE9grLlUU", |
||||||
|
"url": "https://dl.airtable.com/.attachments/a67aaa1efa29d40c3633ca03f0b366e6/9b56c6e2/Abstract-Nord.png", |
||||||
|
"filename": "Abstract-Nord.png", |
||||||
|
"type": "image/png", |
||||||
|
"size": 140219, |
||||||
|
"width": 1920, |
||||||
|
"height": 1080, |
||||||
|
"smallThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/d5daa7de864a8302ad9d2c43a257a52d/2b709aa8", |
||||||
|
"smallThumbWidth": 64, |
||||||
|
"smallThumbHeight": 36, |
||||||
|
"largeThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/7b388a8484a1bc8f9f91bbf304c9b42e/4663133b", |
||||||
|
"largeThumbWidth": 910, |
||||||
|
"largeThumbHeight": 512, |
||||||
|
"fullThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/4d5dfa21efa34198c740443551531eea/ea51b594", |
||||||
|
"fullThumbWidth": 3000, |
||||||
|
"fullThumbHeight": 3000 |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": "attIzZpRBBWwRI5Wz", |
||||||
|
"url": "https://dl.airtable.com/.attachments/107f2f1d886b1f1ae0d528ba7f76df03/931109ad/archlinux.png", |
||||||
|
"filename": "archlinux.png", |
||||||
|
"type": "image/png", |
||||||
|
"size": 184887, |
||||||
|
"width": 3840, |
||||||
|
"height": 2160, |
||||||
|
"smallThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/cb9894ae30f7a264a87639d5ce4980ec/e000fb24", |
||||||
|
"smallThumbWidth": 64, |
||||||
|
"smallThumbHeight": 36, |
||||||
|
"largeThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/1f4146a90346325a8ab51d5d7f4f40be/9a73928f", |
||||||
|
"largeThumbWidth": 910, |
||||||
|
"largeThumbHeight": 512, |
||||||
|
"fullThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/9954669a1ba7bc2d4e4d50f9c0130435/7d46d64a", |
||||||
|
"fullThumbWidth": 3000, |
||||||
|
"fullThumbHeight": 3000 |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": "atttj7OPAZ1iDtHBt", |
||||||
|
"url": "https://dl.airtable.com/.attachments/4eec95e15a951829c2b12e4375bece7f/8ff26ede/arctic-landscape.png", |
||||||
|
"filename": "arctic-landscape.png", |
||||||
|
"type": "image/png", |
||||||
|
"size": 155548, |
||||||
|
"width": 1920, |
||||||
|
"height": 1080, |
||||||
|
"smallThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/dd63a0d18ed1c4bf3e7096145fc5fa0f/ebfc95ac", |
||||||
|
"smallThumbWidth": 64, |
||||||
|
"smallThumbHeight": 36, |
||||||
|
"largeThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/c9b441a88304b53cdc44fa0fcfdb57e6/8c6b629d", |
||||||
|
"largeThumbWidth": 910, |
||||||
|
"largeThumbHeight": 512, |
||||||
|
"fullThumbUrl": "https://dl.airtable.com/.attachmentThumbnails/f5b74f24a31f22e8e859954499abfa67/fd11b916", |
||||||
|
"fullThumbWidth": 3000, |
||||||
|
"fullThumbHeight": 3000 |
||||||
|
} |
||||||
|
], |
||||||
|
"fldrhmH0EYnOXfnUA": "wp" |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": "recAFj2eQVsynoDJa", |
||||||
|
"createdTime": "2022-04-27T18:48:37.000Z", |
||||||
|
"cellValuesByColumnId": { |
||||||
|
"fldrhmH0EYnOXfnUA": "test" |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
"viewDatas": [ |
||||||
|
{ |
||||||
|
"id": "viwbgKWGvUoZCosF1", |
||||||
|
"frozenColumnCount": 1, |
||||||
|
"columnOrder": [ |
||||||
|
{ |
||||||
|
"columnId": "fldrhmH0EYnOXfnUA", |
||||||
|
"visibility": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"columnId": "fldVFoK7t6aC92xzj", |
||||||
|
"visibility": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"columnId": "fld66bK6Pq8AG4m3h", |
||||||
|
"visibility": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"columnId": "fldRC8zKoyGzM6agG", |
||||||
|
"visibility": true |
||||||
|
} |
||||||
|
], |
||||||
|
"sharesById": {}, |
||||||
|
"createdByUserId": "usrcTFn14vKTIgbW3", |
||||||
|
"applicationTransactionNumber": 21, |
||||||
|
"rowOrder": [ |
||||||
|
{ |
||||||
|
"rowId": "recv9Z8uFFNt50rqX", |
||||||
|
"visibility": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"rowId": "recmAktd3OQe3Wg8C", |
||||||
|
"visibility": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"rowId": "recAFj2eQVsynoDJa", |
||||||
|
"visibility": true |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
], |
||||||
|
"hasOnlyIncludedRowAndCellDataForIncludedViews": false |
||||||
|
} |
||||||
|
], |
||||||
|
"hasBlockInstallations": false, |
||||||
|
"applicationAdminFlags": { |
||||||
|
"UPDATE_PRIMITIVE_CELL_THROTTLE_MS": null, |
||||||
|
"MAX_WORKFLOWS_PER_APPLICATION": null, |
||||||
|
"MAX_SYNC_SOURCES_PER_APPLICATION": null, |
||||||
|
"MAX_SYNC_SOURCES_PER_TABLE": null, |
||||||
|
"MAX_SYNCED_TABLES_PER_APPLICATION": null, |
||||||
|
"CUSTOM_MAX_NUM_ROWS_PER_TABLE": null |
||||||
|
}, |
||||||
|
"pageBundles": [], |
||||||
|
"uploadedUserContentCdnSetting": { |
||||||
|
"applicationScopedAuthMode": "public" |
||||||
|
}, |
||||||
|
"applicationV2TargetedFeatureFlagClientConfiguration": { |
||||||
|
"nonCollaboratorsInCollaboratorField": { |
||||||
|
"trafficLevel": 0 |
||||||
|
}, |
||||||
|
"applicationInsights": { |
||||||
|
"trafficLevel": 0 |
||||||
|
}, |
||||||
|
"autoOpenInsightsPaneOnUnseenSuggestion": { |
||||||
|
"trafficLevel": 0 |
||||||
|
}, |
||||||
|
"disabledWorkflowOnSchemaChangeSuggestion": { |
||||||
|
"trafficLevel": 0 |
||||||
|
}, |
||||||
|
"syncFailureSuggestion": { |
||||||
|
"trafficLevel": 0 |
||||||
|
}, |
||||||
|
"unusedViewsSuggestion": { |
||||||
|
"trafficLevel": 0 |
||||||
|
}, |
||||||
|
"filterUnusedViewsUsingDependencyGraph": { |
||||||
|
"trafficLevel": 100 |
||||||
|
}, |
||||||
|
"unusedSelectChoicesSuggestion": { |
||||||
|
"trafficLevel": 0 |
||||||
|
}, |
||||||
|
"unifiedEventLog": { |
||||||
|
"trafficLevel": 0 |
||||||
|
}, |
||||||
|
"constantPoolingForCrudResponses": { |
||||||
|
"trafficLevel": 0 |
||||||
|
} |
||||||
|
}, |
||||||
|
"applicationV2EnabledFeatureNames": [ |
||||||
|
"filterUnusedViewsUsingDependencyGraph" |
||||||
|
], |
||||||
|
"isConstantPooledData": false |
||||||
|
} |
@ -0,0 +1,761 @@ |
|||||||
|
import { Api, UITypes } from 'nocodb-sdk'; |
||||||
|
import Airtable from 'airtable'; |
||||||
|
import jsonfile from 'jsonfile'; |
||||||
|
import FormData from 'form-data' |
||||||
|
import axios from 'axios'; |
||||||
|
|
||||||
|
|
||||||
|
//RUN: npx ts-node src/nc-sync.ts
|
||||||
|
|
||||||
|
function syncLog(log) { |
||||||
|
console.log(`nc-sync: ${log}`) |
||||||
|
} |
||||||
|
|
||||||
|
// apiKey & baseID configurations required to read data using Airtable APIs
|
||||||
|
//
|
||||||
|
const syncDB = { |
||||||
|
airtable: { |
||||||
|
apiKey: 'keyfaOQmPOpigyJV8', |
||||||
|
baseId: 'appEHTLsc4lSaia9A', |
||||||
|
schemaJson: 'attachment.json' |
||||||
|
}, |
||||||
|
projectName: 'sample', |
||||||
|
baseURL: 'http://localhost:8080', |
||||||
|
authToken: |
||||||
|
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAdGVzdC50ZXN0IiwiZmlyc3RuYW1lIjpudWxsLCJsYXN0bmFtZSI6bnVsbCwiaWQiOiJ1c183eHJ5b25jYWZzbHd2diIsInJvbGVzIjoidXNlcixzdXBlciIsImlhdCI6MTY1MDcxMjMyN30.zB_E46qkQy1mCqjjJL89WPa1jCY101BAAoLAyE7b1n8' |
||||||
|
}; |
||||||
|
|
||||||
|
const api = new Api({ |
||||||
|
baseURL: syncDB.baseURL, |
||||||
|
headers: { |
||||||
|
'xc-auth': syncDB.authToken |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// global schema store
|
||||||
|
let global_schema: any = getAtableSchema().tableSchemas; |
||||||
|
|
||||||
|
function getAtableSchema() { |
||||||
|
return jsonfile.readFileSync(syncDB.airtable.schemaJson); |
||||||
|
} |
||||||
|
|
||||||
|
// base mapping table
|
||||||
|
const aTblNcTypeMap = { |
||||||
|
foreignKey: UITypes.LinkToAnotherRecord, |
||||||
|
text: UITypes.SingleLineText, |
||||||
|
multilineText: UITypes.LongText, |
||||||
|
multipleAttachment: UITypes.Attachment, |
||||||
|
checkbox: UITypes.Checkbox, |
||||||
|
multiSelect: UITypes.MultiSelect, |
||||||
|
select: UITypes.SingleSelect, |
||||||
|
collaborator: UITypes.Collaborator, |
||||||
|
date: UITypes.Date, |
||||||
|
// kludge: phone: UITypes.PhoneNumber,
|
||||||
|
phone: UITypes.SingleLineText, |
||||||
|
number: UITypes.Number, |
||||||
|
rating: UITypes.Rating, |
||||||
|
// kludge: formula: UITypes.Formula,
|
||||||
|
formula: UITypes.SingleLineText, |
||||||
|
rollup: UITypes.Rollup, |
||||||
|
count: UITypes.Count, |
||||||
|
lookup: UITypes.Lookup, |
||||||
|
autoNumber: UITypes.AutoNumber, |
||||||
|
barcode: UITypes.Barcode, |
||||||
|
button: UITypes.Button |
||||||
|
}; |
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// aTbl helper routines
|
||||||
|
//
|
||||||
|
|
||||||
|
// aTbl: retrieve table name from table ID
|
||||||
|
//
|
||||||
|
function aTbl_getTableName(tblId) { |
||||||
|
const sheetObj = global_schema.find(tbl => tbl.id === tblId); |
||||||
|
return { |
||||||
|
tn: sheetObj.name |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// aTbl: retrieve column name from column ID
|
||||||
|
//
|
||||||
|
function aTbl_getColumnName(colId) { |
||||||
|
for (let i = 0; i < global_schema.length; i++) { |
||||||
|
let sheetObj = global_schema[i]; |
||||||
|
const column = sheetObj.columns.find(col => col.id === colId); |
||||||
|
if (column !== undefined) |
||||||
|
return { |
||||||
|
tn: sheetObj.name, |
||||||
|
cn: column.name |
||||||
|
}; |
||||||
|
} |
||||||
|
return {}; |
||||||
|
} |
||||||
|
|
||||||
|
// nc dump schema
|
||||||
|
/* |
||||||
|
async function nc_DumpTableSchema() { |
||||||
|
console.log('['); |
||||||
|
let ncTblList = await api.dbTable.list(global_ncCreatedProjectSchema.id); |
||||||
|
for (let i = 0; i < ncTblList.list.length; i++) { |
||||||
|
let ncTbl = await api.dbTable.read(ncTblList.list[i].id); |
||||||
|
console.log(JSON.stringify(ncTbl, null, 2)); |
||||||
|
console.log(','); |
||||||
|
} |
||||||
|
console.log(']'); |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
// retrieve nc column schema from using aTbl field ID as reference
|
||||||
|
//
|
||||||
|
async function nc_getColumnSchema(aTblFieldId) { |
||||||
|
let ncTblList = await api.dbTable.list(global_ncCreatedProjectSchema.id); |
||||||
|
let aTblField = aTbl_getColumnName(aTblFieldId); |
||||||
|
let ncTblId = ncTblList.list.filter(x => x.title === aTblField.tn)[0].id; |
||||||
|
let ncTbl = await api.dbTable.read(ncTblId); |
||||||
|
let ncCol = ncTbl.columns.find(x => x.title === aTblField.cn); |
||||||
|
return ncCol; |
||||||
|
} |
||||||
|
|
||||||
|
// retrieve nc table schema using table name
|
||||||
|
async function nc_getTableSchema(tableName) { |
||||||
|
let ncTblList = await api.dbTable.list(global_ncCreatedProjectSchema.id); |
||||||
|
let ncTblId = ncTblList.list.filter(x => x.title === tableName)[0].id; |
||||||
|
let ncTbl = await api.dbTable.read(ncTblId); |
||||||
|
return ncTbl; |
||||||
|
} |
||||||
|
|
||||||
|
// delete project if already exists
|
||||||
|
async function init() { |
||||||
|
// delete 'sample' project if already exists
|
||||||
|
let x = await api.project.list() |
||||||
|
|
||||||
|
let sampleProj = x.list.find(a => a.title === syncDB.projectName) |
||||||
|
if (sampleProj) { |
||||||
|
await api.project.delete(sampleProj.id) |
||||||
|
} |
||||||
|
|
||||||
|
syncLog('Init') |
||||||
|
} |
||||||
|
|
||||||
|
// map UIDT
|
||||||
|
//
|
||||||
|
function getNocoType(col) { |
||||||
|
// start with default map
|
||||||
|
let ncType = aTblNcTypeMap[col.type]; |
||||||
|
|
||||||
|
// types email & url are marked as text
|
||||||
|
// types currency & percent, duration are marked as number
|
||||||
|
// types createTime & modifiedTime are marked as formula
|
||||||
|
|
||||||
|
switch (col.type) { |
||||||
|
case 'text': |
||||||
|
if (col.typeOptions?.validatorName === 'email') ncType = UITypes.Email; |
||||||
|
else if (col.typeOptions?.validatorName === 'url') ncType = UITypes.URL; |
||||||
|
break; |
||||||
|
|
||||||
|
case 'number': |
||||||
|
// kludge: currency validation error with decimal places
|
||||||
|
if (col.typeOptions?.format === 'percentV2') ncType = UITypes.Percent; |
||||||
|
else if (col.typeOptions?.format === 'duration') |
||||||
|
ncType = UITypes.Duration; |
||||||
|
else if (col.typeOptions?.format === 'currency') |
||||||
|
ncType = UITypes.Currency; |
||||||
|
break; |
||||||
|
|
||||||
|
case 'formula': |
||||||
|
if (col.typeOptions?.formulaTextParsed === 'CREATED_TIME()') |
||||||
|
ncType = UITypes.CreateTime; |
||||||
|
else if (col.typeOptions?.formulaTextParsed === 'LAST_MODIFIED_TIME()') |
||||||
|
ncType = UITypes.LastModifiedTime; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
return ncType; |
||||||
|
} |
||||||
|
|
||||||
|
// retrieve additional options associated with selected data types
|
||||||
|
//
|
||||||
|
function getNocoTypeOptions(col) { |
||||||
|
switch (col.type) { |
||||||
|
case 'select': |
||||||
|
case 'multiSelect': |
||||||
|
// prepare options list in CSV format
|
||||||
|
// note: NC doesn't allow comma's in options
|
||||||
|
//
|
||||||
|
let opt = []; |
||||||
|
for (let [, value] of Object.entries(col.typeOptions.choices) as any) { |
||||||
|
opt.push(value.name); |
||||||
|
} |
||||||
|
let csvOpt = "'" + opt.join("','") + "'"; |
||||||
|
return { type: 'select', data: csvOpt }; |
||||||
|
|
||||||
|
default: |
||||||
|
return { type: undefined }; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// convert to Nc schema (basic, excluding relations)
|
||||||
|
//
|
||||||
|
function tablesPrepare(tblSchema) { |
||||||
|
let tables = []; |
||||||
|
for (let i = 0; i < tblSchema.length; ++i) { |
||||||
|
let table: any = {}; |
||||||
|
|
||||||
|
syncLog(`Preparing base schema (sans relations): ${tblSchema[i].name}`) |
||||||
|
|
||||||
|
// table name
|
||||||
|
table.table_name = tblSchema[i].name; |
||||||
|
table.title = tblSchema[i].name; |
||||||
|
|
||||||
|
// insert record_id of type ID by default
|
||||||
|
table.columns = [ |
||||||
|
{ |
||||||
|
title: 'record_id', |
||||||
|
column_name: 'record_id', |
||||||
|
uidt: UITypes.ID |
||||||
|
// uidt: UITypes.SingleLineText,
|
||||||
|
// pk: true
|
||||||
|
} |
||||||
|
]; |
||||||
|
|
||||||
|
for (let j = 0; j < tblSchema[i].columns.length; j++) { |
||||||
|
let col = tblSchema[i].columns[j]; |
||||||
|
|
||||||
|
// skip link, lookup, rollup fields in this iteration
|
||||||
|
if (['foreignKey', 'lookup', 'rollup'].includes(col.type)) continue; |
||||||
|
|
||||||
|
// not supported datatype
|
||||||
|
// if (['formula'].includes(col.type)) continue;
|
||||||
|
|
||||||
|
// base column schema
|
||||||
|
// kludge: error observed in Nc with space around column-name
|
||||||
|
let ncCol: any = { |
||||||
|
title: col.name.trim(), |
||||||
|
|
||||||
|
// knex complains use of '?' in field name
|
||||||
|
//column_name: col.name.replace(/\?/g, '\\?').trim(),
|
||||||
|
column_name: col.name.replace(/\?/g, 'QQ').trim(), |
||||||
|
uidt: getNocoType(col) |
||||||
|
}; |
||||||
|
|
||||||
|
// additional column parameters when applicable
|
||||||
|
let colOptions = getNocoTypeOptions(col); |
||||||
|
|
||||||
|
switch (colOptions.type) { |
||||||
|
case 'select': |
||||||
|
ncCol.dtxp = colOptions.data; |
||||||
|
break; |
||||||
|
|
||||||
|
case undefined: |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
table.columns.push(ncCol); |
||||||
|
} |
||||||
|
|
||||||
|
tables.push(table); |
||||||
|
} |
||||||
|
return tables; |
||||||
|
} |
||||||
|
|
||||||
|
async function nocoCreateBaseSchema(srcSchema) { |
||||||
|
// base schema preparation: exclude
|
||||||
|
let tables = tablesPrepare(srcSchema.tableSchemas); |
||||||
|
|
||||||
|
// for each table schema, create nc table
|
||||||
|
for (let idx = 0; idx < tables.length; idx++) { |
||||||
|
|
||||||
|
syncLog(`dbTable.create ${tables[idx].title}`) |
||||||
|
let table = await api.dbTable.create( |
||||||
|
global_ncCreatedProjectSchema.id, |
||||||
|
tables[idx] |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// debug
|
||||||
|
// console.log(JSON.stringify(tables, null, 2));
|
||||||
|
return tables; |
||||||
|
} |
||||||
|
|
||||||
|
async function nocoCreateLinkToAnotherRecord(aTblSchema) { |
||||||
|
// Link to another RECORD
|
||||||
|
for (let idx = 0; idx < aTblSchema.length; idx++) { |
||||||
|
let aTblLinkColumns = aTblSchema[idx].columns.filter( |
||||||
|
x => x.type === 'foreignKey' |
||||||
|
); |
||||||
|
|
||||||
|
// Link columns exist
|
||||||
|
//
|
||||||
|
if (aTblLinkColumns.length) { |
||||||
|
for (let i = 0; i < aTblLinkColumns.length; i++) { |
||||||
|
|
||||||
|
{ |
||||||
|
let src = aTbl_getColumnName(aTblLinkColumns[i].id) |
||||||
|
let dst = aTbl_getColumnName(aTblLinkColumns[i].typeOptions.symmetricColumnId) |
||||||
|
syncLog(` LTAR ${src.tn}:${src.cn} <${aTblLinkColumns[i].typeOptions.relationship}> ${dst.tn}:${dst.cn}`) |
||||||
|
} |
||||||
|
|
||||||
|
// check if link already established?
|
||||||
|
if (!nc_isLinkExists(aTblLinkColumns[i].id)) { |
||||||
|
// parent table ID
|
||||||
|
let srcTableId = (await nc_getTableSchema(aTblSchema[idx].name)).id; |
||||||
|
|
||||||
|
// find child table name from symmetric column ID specified
|
||||||
|
let childTable = aTbl_getColumnName( |
||||||
|
aTblLinkColumns[i].typeOptions.symmetricColumnId |
||||||
|
); |
||||||
|
|
||||||
|
// retrieve child table ID (nc) from table name
|
||||||
|
let childTableId = (await nc_getTableSchema(childTable.tn)).id; |
||||||
|
|
||||||
|
// create link
|
||||||
|
let column = await api.dbTableColumn.create(srcTableId, { |
||||||
|
uidt: 'LinkToAnotherRecord', |
||||||
|
title: aTblLinkColumns[i].name, |
||||||
|
parentId: srcTableId, |
||||||
|
childId: childTableId, |
||||||
|
type: 'mm' |
||||||
|
// aTblLinkColumns[i].typeOptions.relationship === 'many'
|
||||||
|
// ? 'mm'
|
||||||
|
// : 'hm'
|
||||||
|
}); |
||||||
|
syncLog(`NC API: dbTableColumn.create LinkToAnotherRecord`) |
||||||
|
|
||||||
|
// store link information in separate table
|
||||||
|
// this information will be helpful in identifying relation pair
|
||||||
|
let link = { |
||||||
|
nc: { |
||||||
|
title: aTblLinkColumns[i].name, |
||||||
|
parentId: srcTableId, |
||||||
|
childId: childTableId, |
||||||
|
type: 'mm' |
||||||
|
}, |
||||||
|
aTbl: { |
||||||
|
tblId: aTblSchema[idx].id, |
||||||
|
...aTblLinkColumns[i] |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
global_ncLinkMappingTable.push(link); |
||||||
|
} else { |
||||||
|
// if link already exists, we need to change name of linked column
|
||||||
|
// to what is represented in airtable
|
||||||
|
|
||||||
|
// 1. extract associated link information from link table
|
||||||
|
// 2. retrieve parent table information (source)
|
||||||
|
// 3. using foreign parent & child column ID, find associated mapping in child table
|
||||||
|
// 4. update column name
|
||||||
|
let x = global_ncLinkMappingTable.findIndex( |
||||||
|
x => |
||||||
|
x.aTbl.tblId === aTblLinkColumns[i].typeOptions.foreignTableId && |
||||||
|
x.aTbl.id === aTblLinkColumns[i].typeOptions.symmetricColumnId |
||||||
|
); |
||||||
|
|
||||||
|
let childTblSchema = await api.dbTable.read( |
||||||
|
global_ncLinkMappingTable[x].nc.childId |
||||||
|
); |
||||||
|
let parentTblSchema = await api.dbTable.read( |
||||||
|
global_ncLinkMappingTable[x].nc.parentId |
||||||
|
); |
||||||
|
|
||||||
|
let parentLinkColumn: any = parentTblSchema.columns.find( |
||||||
|
col => col.title === global_ncLinkMappingTable[x].nc.title |
||||||
|
); |
||||||
|
|
||||||
|
let childLinkColumn: any = {}; |
||||||
|
if (parentLinkColumn.colOptions.type == 'hm') { |
||||||
|
// for hm:
|
||||||
|
// mapping between child & parent column id is direct
|
||||||
|
//
|
||||||
|
childLinkColumn = childTblSchema.columns.find( |
||||||
|
(col: any) => |
||||||
|
col.uidt === 'LinkToAnotherRecord' && |
||||||
|
col.colOptions.fk_child_column_id === |
||||||
|
parentLinkColumn.colOptions.fk_child_column_id && |
||||||
|
col.colOptions.fk_parent_column_id === |
||||||
|
parentLinkColumn.colOptions.fk_parent_column_id |
||||||
|
); |
||||||
|
} else { |
||||||
|
// for mm:
|
||||||
|
// mapping between child & parent column id is inverted
|
||||||
|
//
|
||||||
|
childLinkColumn = childTblSchema.columns.find( |
||||||
|
(col: any) => |
||||||
|
col.uidt === 'LinkToAnotherRecord' && |
||||||
|
col.colOptions.fk_child_column_id === |
||||||
|
parentLinkColumn.colOptions.fk_parent_column_id && |
||||||
|
col.colOptions.fk_parent_column_id === |
||||||
|
parentLinkColumn.colOptions.fk_child_column_id && |
||||||
|
col.colOptions.fk_mm_model_id === |
||||||
|
parentLinkColumn.colOptions.fk_mm_model_id |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// rename
|
||||||
|
// note that: current rename API requires us to send all parameters,
|
||||||
|
// not just title being renamed
|
||||||
|
let res = await api.dbTableColumn.update(childLinkColumn.id, { |
||||||
|
...childLinkColumn, |
||||||
|
title: aTblLinkColumns[i].name, |
||||||
|
}); |
||||||
|
// console.log(res.columns.find(x => x.title === aTblLinkColumns[i].name))
|
||||||
|
syncLog(`dbTableColumn.update rename symmetric column`) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function nocoCreateLookups(aTblSchema) { |
||||||
|
// LookUps
|
||||||
|
for (let idx = 0; idx < aTblSchema.length; idx++) { |
||||||
|
let aTblColumns = aTblSchema[idx].columns.filter(x => x.type === 'lookup'); |
||||||
|
|
||||||
|
// parent table ID
|
||||||
|
let srcTableId = (await nc_getTableSchema(aTblSchema[idx].name)).id; |
||||||
|
|
||||||
|
if (aTblColumns.length) { |
||||||
|
// Lookup
|
||||||
|
for (let i = 0; i < aTblColumns.length; i++) { |
||||||
|
let ncRelationColumn = await nc_getColumnSchema( |
||||||
|
aTblColumns[i].typeOptions.relationColumnId |
||||||
|
); |
||||||
|
let ncLookupColumn = await nc_getColumnSchema( |
||||||
|
aTblColumns[i].typeOptions.foreignTableRollupColumnId |
||||||
|
); |
||||||
|
|
||||||
|
let lookupColumn = await api.dbTableColumn.create(srcTableId, { |
||||||
|
uidt: 'Lookup', |
||||||
|
title: aTblColumns[i].name, |
||||||
|
fk_relation_column_id: ncRelationColumn.id, |
||||||
|
fk_lookup_column_id: ncLookupColumn.id |
||||||
|
}); |
||||||
|
|
||||||
|
syncLog(`NC API: dbTableColumn.create LOOKUP`) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function nocoCreateRollups(aTblSchema) { |
||||||
|
// Rollups
|
||||||
|
for (let idx = 0; idx < aTblSchema.length; idx++) { |
||||||
|
let aTblColumns = aTblSchema[idx].columns.filter(x => x.type === 'rollup'); |
||||||
|
|
||||||
|
// parent table ID
|
||||||
|
let srcTableId = (await nc_getTableSchema(aTblSchema[idx].name)).id; |
||||||
|
|
||||||
|
if (aTblColumns.length) { |
||||||
|
// rollup exist
|
||||||
|
for (let i = 0; i < aTblColumns.length; i++) { |
||||||
|
let ncRelationColumn = await nc_getColumnSchema( |
||||||
|
aTblColumns[i].typeOptions.relationColumnId |
||||||
|
); |
||||||
|
let ncRollupColumn = await nc_getColumnSchema( |
||||||
|
aTblColumns[i].typeOptions.foreignTableRollupColumnId |
||||||
|
); |
||||||
|
|
||||||
|
let lookupColumn = await api.dbTableColumn.create(srcTableId, { |
||||||
|
uidt: 'Rollup', |
||||||
|
title: aTblColumns[i].name, |
||||||
|
fk_relation_column_id: ncRelationColumn.id, |
||||||
|
fk_rollup_column_id: ncRollupColumn.id, |
||||||
|
rollup_function: 'sum' // fix me: hardwired
|
||||||
|
}); |
||||||
|
|
||||||
|
syncLog(`NC API: dbTableColumn.create ROLLUP`) |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function nocoSetPrimary(aTblSchema) { |
||||||
|
for (let idx = 0; idx < aTblSchema.length; idx++) { |
||||||
|
let pColId = aTblSchema[idx].primaryColumnId; |
||||||
|
let ncCol = await nc_getColumnSchema(pColId); |
||||||
|
|
||||||
|
syncLog(`NC API: dbTableColumn.primaryColumnSet`) |
||||||
|
await api.dbTableColumn.primaryColumnSet(ncCol.id); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
////////// Data processing
|
||||||
|
|
||||||
|
// https://www.airtable.com/app1ivUy7ba82jOPn/api/docs#javascript/metadata
|
||||||
|
let base = new Airtable({ apiKey: syncDB.airtable.apiKey }).base( |
||||||
|
syncDB.airtable.baseId |
||||||
|
); |
||||||
|
|
||||||
|
let aTblDataLinks = []; |
||||||
|
let aTblNcRecordMappingTable = {}; |
||||||
|
|
||||||
|
function nocoLinkProcessing(table, record, field) { |
||||||
|
(async () => { |
||||||
|
let rec = record.fields; |
||||||
|
const value = Object.values(rec) as any; |
||||||
|
let srcRow = aTblNcRecordMappingTable[`${record.id}`]; |
||||||
|
|
||||||
|
if (value.length) { |
||||||
|
for (let i = 0; i < value[0].length; i++) { |
||||||
|
let dstRow = aTblNcRecordMappingTable[`${value[0][i]}`]; |
||||||
|
|
||||||
|
syncLog(`NC API: dbTableRow.nestedAdd ${srcRow[1]}/hm/${dstRow[0]}/${dstRow[1]}`) |
||||||
|
|
||||||
|
await api.dbTableRow.nestedAdd( |
||||||
|
'noco', |
||||||
|
syncDB.projectName, |
||||||
|
table.title, |
||||||
|
`${srcRow[1]}`, |
||||||
|
'mm', // fix me
|
||||||
|
`${field}`, |
||||||
|
`${dstRow[1]}` |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
})().catch(e => { |
||||||
|
syncLog(`Link error`) |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
// fix me:
|
||||||
|
// instead of skipping data after retrieval, use select fields option in airtable API
|
||||||
|
function nocoBaseDataProcessing(table, record) { |
||||||
|
(async () => { |
||||||
|
let rec = record.fields; |
||||||
|
|
||||||
|
// kludge -
|
||||||
|
// trim spaces on either side of column name
|
||||||
|
// leads to error in NocoDB
|
||||||
|
Object.keys(rec).forEach(key => { |
||||||
|
let replacedKey = key.replace(/\?/g, 'QQ').trim() |
||||||
|
if (key !== replacedKey) { |
||||||
|
rec[replacedKey] = rec[key]; |
||||||
|
delete rec[key]; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// post-processing on the record
|
||||||
|
for (const [key, value] of Object.entries(rec) as any) { |
||||||
|
// retrieve datatype
|
||||||
|
let dt = table.columns.find(x => x.title === key)?.uidt; |
||||||
|
|
||||||
|
// if(dt === undefined)
|
||||||
|
// console.log('fix me')
|
||||||
|
|
||||||
|
// https://www.npmjs.com/package/validator
|
||||||
|
// default value: digits_after_decimal: [2]
|
||||||
|
// if currency, set decimal place to 2
|
||||||
|
//
|
||||||
|
if (dt === 'Currency') rec[key] = value.toFixed(2); |
||||||
|
|
||||||
|
// we will pick up LTAR once all table data's are in place
|
||||||
|
if (dt === 'LinkToAnotherRecord') { |
||||||
|
aTblDataLinks.push(JSON.parse(JSON.stringify(rec))); |
||||||
|
delete rec[key]; |
||||||
|
} |
||||||
|
|
||||||
|
// these will be automatically populated depending on schema configuration
|
||||||
|
if (dt === 'Lookup') delete rec[key]; |
||||||
|
if (dt === 'Rollup') delete rec[key]; |
||||||
|
|
||||||
|
if (dt === 'Attachment') { |
||||||
|
let tempArr = []; |
||||||
|
for (const v of value) { |
||||||
|
const binaryImage = await axios |
||||||
|
.get(v.url, { |
||||||
|
responseType: 'stream', |
||||||
|
headers: { |
||||||
|
'Content-Type': v.type |
||||||
|
} |
||||||
|
}) |
||||||
|
.then(response => { |
||||||
|
return response.data; |
||||||
|
}) |
||||||
|
.catch(error => { |
||||||
|
console.log(error); |
||||||
|
return false; |
||||||
|
}); |
||||||
|
|
||||||
|
var imageFile = new FormData(); |
||||||
|
imageFile.append('files', binaryImage, { |
||||||
|
filename: v.filename |
||||||
|
}); |
||||||
|
|
||||||
|
const rs = await axios |
||||||
|
.post(syncDB.baseURL + '/api/v1/db/storage/upload', imageFile, { |
||||||
|
params: { |
||||||
|
path: `noco/${syncDB.projectName}/${table.title}/${key}` |
||||||
|
}, |
||||||
|
headers: { |
||||||
|
'Content-Type': `multipart/form-data; boundary=${imageFile.getBoundary()}`, |
||||||
|
'xc-auth': syncDB.authToken |
||||||
|
} |
||||||
|
}) |
||||||
|
.then(response => { |
||||||
|
return response.data; |
||||||
|
}) |
||||||
|
.catch(e => { |
||||||
|
console.log(e); |
||||||
|
}); |
||||||
|
|
||||||
|
tempArr.push(...rs); |
||||||
|
} |
||||||
|
rec[key] = JSON.stringify(tempArr); |
||||||
|
// rec[key] = JSON.stringify(tempArr);
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// insert airtable record ID explicitly into each records
|
||||||
|
// rec['record_id'] = record.id;
|
||||||
|
|
||||||
|
// console.log(rec)
|
||||||
|
|
||||||
|
syncLog(`dbTableRow.bulkCreate ${table.title} [${JSON.stringify(rec)}]`) |
||||||
|
// console.log(JSON.stringify(rec, null, 2))
|
||||||
|
|
||||||
|
// bulk Insert
|
||||||
|
let returnValue = await api.dbTableRow.bulkCreate( |
||||||
|
'nc', |
||||||
|
syncDB.projectName, |
||||||
|
table.title, |
||||||
|
[rec] |
||||||
|
); |
||||||
|
|
||||||
|
aTblNcRecordMappingTable[record.id] = [table.title, returnValue[0]]; |
||||||
|
})().catch(e => { |
||||||
|
syncLog(`Record insert error: ${e}`) |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
async function nocoReadData(table, callback) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
base(table.title) |
||||||
|
.select({ |
||||||
|
pageSize: 25, |
||||||
|
// maxRecords: 1,
|
||||||
|
}) |
||||||
|
.eachPage( |
||||||
|
function page(records, fetchNextPage) { |
||||||
|
// console.log(JSON.stringify(records, null, 2));
|
||||||
|
|
||||||
|
// This function (`page`) will get called for each page of records.
|
||||||
|
records.forEach(record => callback(table, record)); |
||||||
|
|
||||||
|
// To fetch the next page of records, call `fetchNextPage`.
|
||||||
|
// If there are more records, `page` will get called again.
|
||||||
|
// If there are no more records, `done` will get called.
|
||||||
|
fetchNextPage(); |
||||||
|
}, |
||||||
|
function done(err) { |
||||||
|
if (err) { |
||||||
|
console.error(err); |
||||||
|
reject(err) |
||||||
|
} |
||||||
|
resolve(true) |
||||||
|
} |
||||||
|
); |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
async function nocoReadDataSelected(table, callback, fields) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
|
||||||
|
base(table.title) |
||||||
|
.select({ |
||||||
|
pageSize: 25, |
||||||
|
// maxRecords: 100,
|
||||||
|
fields: [fields] |
||||||
|
}) |
||||||
|
.eachPage( |
||||||
|
function page(records, fetchNextPage) { |
||||||
|
// console.log(JSON.stringify(records, null, 2));
|
||||||
|
|
||||||
|
// This function (`page`) will get called for each page of records.
|
||||||
|
// records.forEach(record => callback(table, record));
|
||||||
|
for (let i = 0; i < records.length; i++) { |
||||||
|
callback(table, records[i], fields) |
||||||
|
} |
||||||
|
|
||||||
|
// To fetch the next page of records, call `fetchNextPage`.
|
||||||
|
// If there are more records, `page` will get called again.
|
||||||
|
// If there are no more records, `done` will get called.
|
||||||
|
fetchNextPage(); |
||||||
|
}, |
||||||
|
function done(err) { |
||||||
|
if (err) { |
||||||
|
console.error(err); |
||||||
|
reject(err) |
||||||
|
} |
||||||
|
resolve(true) |
||||||
|
} |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
//////////
|
||||||
|
var global_ncCreatedProjectSchema: any = []; |
||||||
|
var global_ncLinkMappingTable: any = []; |
||||||
|
|
||||||
|
function nc_isLinkExists(atblFieldId) { |
||||||
|
if ( |
||||||
|
global_ncLinkMappingTable.find( |
||||||
|
x => x.aTbl.typeOptions.symmetricColumnId === atblFieldId |
||||||
|
) |
||||||
|
) |
||||||
|
return true; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// start function
|
||||||
|
async function nc_migrateATbl() { |
||||||
|
|
||||||
|
// fix me: delete project if already exists
|
||||||
|
// remove later
|
||||||
|
await init() |
||||||
|
|
||||||
|
// read schema file
|
||||||
|
const schema = getAtableSchema(); |
||||||
|
let aTblSchema = schema.tableSchemas; |
||||||
|
|
||||||
|
// create empty project (XC-DB)
|
||||||
|
global_ncCreatedProjectSchema = await api.project.create({ |
||||||
|
title: syncDB.projectName |
||||||
|
}); |
||||||
|
syncLog(`Create Project: ${syncDB.projectName}`) |
||||||
|
|
||||||
|
// prepare table schema (base)
|
||||||
|
await nocoCreateBaseSchema(schema); |
||||||
|
|
||||||
|
// add LTAR
|
||||||
|
await nocoCreateLinkToAnotherRecord(aTblSchema); |
||||||
|
|
||||||
|
// add look-ups
|
||||||
|
await nocoCreateLookups(aTblSchema); |
||||||
|
|
||||||
|
// add roll-ups
|
||||||
|
await nocoCreateRollups(aTblSchema); |
||||||
|
|
||||||
|
// configure primary values
|
||||||
|
await nocoSetPrimary(aTblSchema); |
||||||
|
|
||||||
|
// await nc_DumpTableSchema();
|
||||||
|
let ncTblList = await api.dbTable.list(global_ncCreatedProjectSchema.id); |
||||||
|
for (let i = 0; i < ncTblList.list.length; i++) { |
||||||
|
let ncTbl = await api.dbTable.read(ncTblList.list[i].id); |
||||||
|
await nocoReadData(ncTbl, nocoBaseDataProcessing); |
||||||
|
} |
||||||
|
|
||||||
|
// // Configure link @ Data row's
|
||||||
|
for (let idx = 0; idx < global_ncLinkMappingTable.length; idx++) { |
||||||
|
let x = global_ncLinkMappingTable[idx]; |
||||||
|
let ncTbl = await nc_getTableSchema(aTbl_getTableName(x.aTbl.tblId).tn); |
||||||
|
await nocoReadDataSelected(ncTbl, nocoLinkProcessing, x.aTbl.name); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
nc_migrateATbl().catch(e => { |
||||||
|
console.log(e); |
||||||
|
}); |
@ -0,0 +1,63 @@ |
|||||||
|
{ |
||||||
|
"compilerOptions": { |
||||||
|
"skipLibCheck": false, |
||||||
|
"composite": true, |
||||||
|
"target": "es2017", |
||||||
|
"outDir": "build", |
||||||
|
"rootDir": "src", |
||||||
|
"moduleResolution": "node", |
||||||
|
"module": "commonjs", |
||||||
|
"declaration": true, |
||||||
|
"inlineSourceMap": true, |
||||||
|
"esModuleInterop": true |
||||||
|
/* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, |
||||||
|
"allowJs": false, |
||||||
|
// "strict": true /* Enable all strict type-checking options. */, |
||||||
|
|
||||||
|
/* Strict Type-Checking Options */ |
||||||
|
// "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, |
||||||
|
// "strictNullChecks": true /* Enable strict null checks. */, |
||||||
|
// "strictFunctionTypes": true /* Enable strict checking of function types. */, |
||||||
|
// "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */, |
||||||
|
// "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */, |
||||||
|
// "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */, |
||||||
|
"resolveJsonModule": true, |
||||||
|
/* Additional Checks */ |
||||||
|
// "noUnusedLocals": true |
||||||
|
// /* Report errors on unused locals. */, |
||||||
|
// "noUnusedParameters": true |
||||||
|
// /* Report errors on unused parameters. */, |
||||||
|
"noImplicitReturns": true |
||||||
|
/* Report error when not all code paths in function return a value. */, |
||||||
|
"noFallthroughCasesInSwitch": true |
||||||
|
/* Report errors for fallthrough cases in switch statement. */, |
||||||
|
/* Debugging Options */ |
||||||
|
"traceResolution": false |
||||||
|
/* Report module resolution log messages. */, |
||||||
|
"listEmittedFiles": false |
||||||
|
/* Print names of generated files part of the compilation. */, |
||||||
|
"listFiles": false |
||||||
|
/* Print names of files part of the compilation. */, |
||||||
|
"pretty": true |
||||||
|
/* Stylize errors and messages using color and context. */, |
||||||
|
/* Experimental Options */ |
||||||
|
// "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, |
||||||
|
// "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, |
||||||
|
|
||||||
|
"lib": [ |
||||||
|
"es2017", |
||||||
|
"dom" |
||||||
|
], |
||||||
|
"types": [ |
||||||
|
"node" |
||||||
|
], |
||||||
|
"typeRoots": [ |
||||||
|
"../../../node_modules/@types" |
||||||
|
] |
||||||
|
}, |
||||||
|
"include": [ |
||||||
|
"src/**/*.ts", |
||||||
|
"src/**/*.json" |
||||||
|
], |
||||||
|
"compileOnSave": false |
||||||
|
} |
Loading…
Reference in new issue