-
Notifications
You must be signed in to change notification settings - Fork 15
Sqlite loader #67
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
Sqlite loader #67
Conversation
SQLiteLoader can load data into a local SQLite database file. Currently the table name is called "Todo" and not set by the block due to errors with the grammar.
Adds a table attribute to SQLiteLoader so that the table name can be defined. The ordering of attributes is intentially fixed as introducing unordered attributes with '&' seems to lead to a lot of COMMON_PREFIX and AMBIGUOUS_ALTERNATIVES errors with PostgresLoader.
With the addition of surrounding delimiters around column names with a recent patch, the EMPTY fallback is no longer necessary as empty column names actually work.
Cars example now uses SQLite instead of Postgres. This means it also does not need to start a local Postgres DB anymore.
See #61 regarding the problem with the attribute ordering. |
@@ -59,7 +59,7 @@ export class PostgresLoaderExecutor extends BlockExecutor< | |||
const columnTypeVisitor = new PostgresColumnTypeVisitor(); | |||
|
|||
const columnPostgresStatements = input.columnNames | |||
.map((columnName) => columnName || 'EMPTYNAME') | |||
.map((columnName) => columnName) |
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.
.map((columnName) => columnName) |
Can be omitted as it does not do anything.
@@ -88,7 +88,7 @@ export class PostgresLoaderExecutor extends BlockExecutor< | |||
.join(','); | |||
|
|||
return `INSERT INTO "${tableName}" (${input.columnNames | |||
.map((columnName) => columnName || 'EMPTYNAME') | |||
.map((columnName) => columnName) |
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.
.map((columnName) => columnName) |
Again, can be omitted.
table: "Cars"; | ||
file: "./cars.db"; |
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.
You could add a custom validator for checking the file ending and e.g. show a warning if it is not .sqlite
or .db
.
There 10000 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.
I am not actually sure there has to be a specific file extension, I don't know sqlite enough :D. In any case I'll have to leave that as a future exercise for me because it is a new system I have not worked with yet (the custom validations). I'll get to it though.
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.
We can also pair program this if you want to :)
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.
True, good idea. I'll have to keep it in mind for the future though, not sure I can get to it this week. But I'll ping you :).
|
||
TableAttribute returns StringAttribute: | ||
'table' StringAttributeFragment; |
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.
Maybe move this into the blocks
folder in a file called shared-attributes.langium
? That way attributes.langium
file does not contain any block-specific attributes.
@@ -0,0 +1,16 @@ | |||
import { DataTypeVisitor } from '@jayvee/language-server'; | |||
|
|||
export class SQLColumnTypeVisitor extends DataTypeVisitor<string> { |
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.
We could omit the subclasses PostgresColumnTypeVisitor
and SQLiteColumnTypeVisitor
because they don't add any behavior. Instead we could go with SQLColumnTypeVisitor
and add subclasses in the future when required.
Same for SQLValueRepresentationVisitor
, PostgresValueRepresentationVisitor
and SQLiteValueRepresentationVisitor
.
private buildCreateTableStatement(tableName: string, input: Table): string { | ||
const columnTypeVisitor = new SQLiteColumnTypeVisitor(); | ||
|
||
const columnStatements = input.columnNames | ||
.map((columnName) => columnName) | ||
.map((columnName) => `"${columnName}"`) | ||
.map((name, index) => { | ||
return `${name} ${( | ||
input.columnTypes[index] as AbstractDataType | ||
).acceptVisitor(columnTypeVisitor)}`; | ||
}); | ||
|
||
return `CREATE TABLE IF NOT EXISTS "${tableName}" (${columnStatements.join( | ||
',', | ||
)});`; | ||
} | ||
|
||
private buildInsertValuesStatement(tableName: string, input: Table): string { | ||
const valueRepresenationVisitor = new SQLiteValueRepresentationVisitor(); | ||
|
||
const valueRepresentationFormatters = input.columnTypes.map((type) => { | ||
return type?.acceptVisitor(valueRepresenationVisitor); | ||
}); | ||
|
||
const valuesStatement = input.data | ||
.map((row) => { | ||
return `(${row | ||
.map((value, index) => valueRepresentationFormatters[index]?.(value)) | ||
.join(',')})`; | ||
}) | ||
.join(','); | ||
|
||
return `INSERT INTO "${tableName}" (${input.columnNames | ||
.map((columnName) => columnName) | ||
.map((columnName) => `"${columnName}"`) | ||
.join(',')}) VALUES ${valuesStatement}`; | ||
} |
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.
All of this is pretty much duplicate code (compared to postgres-loader-executor
). Consider a refactoring.
}), | ||
); | ||
} finally { | ||
db && db.close(); |
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.
db && db.close(); | |
db?.close(); |
Summary
This PR adds support for a
SQLiteLoader
.Known issues
If the order of attributes in the SQLiteLoader is not fixed, the following errors are shown when running
npm run generate
. I noticed the order of attributes in the CSVFileExtractor is also fixed. I am not sure how to fix this, maybe we can spin that out into an extra task.Screenshot