New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(feat) [nan-591] insert into bigQuery #1903
Changes from 13 commits
022dcda
b0d2aa1
849f99c
86e83b8
066a82e
046bb2a
8bad306
5d428e4
2bd39b8
2b817be
88df622
a70eec9
cc32e2b
f4a70ba
4c7c6e6
68ffc72
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
tsconfig.tsbuildinfo | ||
dist/* | ||
node_modules |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { BigQuery } from '@google-cloud/bigquery'; | ||
import type { BigQuery as BigQueryType } from '@google-cloud/bigquery'; | ||
import { getLogger } from '@nangohq/utils/dist/logger.js'; | ||
import { isCloud, isLocal } from '@nangohq/utils/dist/environment/detection.js'; | ||
|
||
const logger = getLogger('BigQueryClient'); | ||
|
||
interface RunScriptRow { | ||
executionType: string; | ||
internalConnectionId: number | undefined; | ||
connectionId: string; | ||
accountId: number | undefined; | ||
scriptName: string; | ||
scriptType: string; | ||
environmentId: number; | ||
providerConfigKey: string; | ||
status: string; | ||
syncId: string; | ||
content: string; | ||
runTimeInSeconds: number; | ||
createdAt: number; | ||
} | ||
|
||
class BigQueryClient { | ||
private client: BigQuery; | ||
private datasetName: string; | ||
private tableName: string; | ||
|
||
constructor({ datasetName, tableName }: { datasetName: string; tableName: string }) { | ||
this.client = new BigQuery(); | ||
this.tableName = tableName; | ||
this.datasetName = datasetName; | ||
khaliqgant marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
static async createInstance({ datasetName, tableName }: { datasetName?: string; tableName: string }) { | ||
const instance = new BigQueryClient({ | ||
datasetName: datasetName || 'raw', | ||
tableName | ||
}); | ||
await instance.initialize(); | ||
return instance; | ||
} | ||
|
||
private async initialize() { | ||
try { | ||
if (isCloud) { | ||
await this.createDataSet(); | ||
await this.createTable(); | ||
} | ||
} catch (e) { | ||
logger.error('Error initializing', e); | ||
} | ||
} | ||
|
||
private async createDataSet() { | ||
const dataset = this.client.dataset(this.datasetName); | ||
const [exists] = await dataset.exists(); | ||
if (!exists) { | ||
await this.client.createDataset(this.datasetName); | ||
} | ||
} | ||
|
||
private async createTable() { | ||
const table = this.client.dataset(this.datasetName).table(this.tableName); | ||
const [exists] = await table.exists(); | ||
if (!exists) { | ||
await table.create({ | ||
schema: { | ||
fields: [ | ||
{ name: 'executionType', type: 'STRING' }, | ||
{ name: 'internalConnectionId', type: 'INTEGER' }, | ||
{ name: 'connectionId', type: 'STRING' }, | ||
{ name: 'accountId', type: 'INTEGER' }, | ||
{ name: 'scriptName', type: 'STRING' }, | ||
{ name: 'scriptType', type: 'STRING' }, | ||
{ name: 'environmentId', type: 'INTEGER' }, | ||
{ name: 'providerConfigKey', type: 'STRING' }, | ||
{ name: 'status', type: 'STRING' }, | ||
{ name: 'syncId', type: 'STRING' }, | ||
{ name: 'content', type: 'STRING' }, | ||
{ name: 'runTimeInSeconds', type: 'FLOAT' }, | ||
{ name: 'createdAt', type: 'INTEGER' } | ||
] | ||
} | ||
}); | ||
} | ||
} | ||
|
||
public async insert(data: RunScriptRow, tableName?: string) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we are not enforcing type and schema matching, should insert simply accept any record<string, string|number>? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Won't work as then there would be a type mismatch between the two. |
||
const table = tableName || this.tableName; | ||
try { | ||
if (isCloud) { | ||
await this.client.dataset(this.datasetName).table(table).insert(data); | ||
} | ||
if (isLocal) { | ||
logger.info(`Data would be inserted into BigQuery type ${JSON.stringify(data, null, 2)}`); | ||
} | ||
khaliqgant marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} catch (e) { | ||
logger.error('Error inserting into BigQuery', e); | ||
} | ||
} | ||
} | ||
|
||
export { BigQueryClient, BigQueryType }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"name": "@nangohq/data-ingestion", | ||
khaliqgant marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"version": "1.0.0", | ||
"description": "Package to ingest Nango data for analytics", | ||
"type": "module", | ||
"main": "dist/index.js", | ||
"typings": "dist/index.d.ts", | ||
"scripts": { | ||
"build": "rimraf ./dist && tsc" | ||
}, | ||
"keywords": [], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/NangoHQ/nango.git", | ||
"directory": "packages/utils" | ||
}, | ||
"license": "SEE LICENSE IN LICENSE FILE IN GIT REPOSITORY", | ||
"dependencies": { | ||
"@google-cloud/bigquery": "7.5.1", | ||
"@nangohq/utils": "file:../utils" | ||
}, | ||
"devDependencies": {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"extends": "../../tsconfig.json", | ||
"compilerOptions": { | ||
"rootDir": "lib", | ||
"outDir": "dist" | ||
}, | ||
"include": ["lib/**/*"], | ||
"references": [ | ||
{ | ||
"path": "../utils" | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,9 @@ | |
}, | ||
{ | ||
"path": "../utils" | ||
}, | ||
{ | ||
"path": "../data-ingestion" | ||
} | ||
], | ||
"include": ["lib/**/*"] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"watch": ["lib", "../shared/dist", "../utils/dist", "../../.env"], | ||
"ext": "ts,json", | ||
"ext": "js,ts,json", | ||
"ignore": ["lib/**/*.test.ts"], | ||
"exec": "tsc && tsx -r dotenv/config lib/app.ts dotenv_config_path=./../../.env" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"watch": ["lib", "../shared/dist", "../utils/dist", "../../.env"], | ||
"ext": "ts,json", | ||
"ext": "js,ts,json", | ||
"ignore": ["lib/**/*.test.ts"], | ||
"exec": "tsc && tsx -r dotenv/config lib/app.ts dotenv_config_path=./../../.env" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"watch": ["lib", "../shared/dist", "../utils/dist", "../../.env", "../shared/providers.yaml"], | ||
"ext": "ts,json", | ||
"ext": "js,ts,json", | ||
"ignore": ["src/**/*.spec.ts"], | ||
"exec": "tsx -r dotenv/config lib/server.ts Dotenv_config_path=./../../.env" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a blocker: the schema is not linked to the type, which could lead to desync