@balena/abstract-sql-compiler
Advanced tools
Comparing version 7.3.0 to 7.4.0-definitions-480da0c6225ce0eb484522f6d3a65e31b47bd88b
@@ -7,2 +7,6 @@ # Change Log | ||
## 7.4.0 - 2020-12-18 | ||
* Add support for table definitions [Pagan Gazzard] | ||
## 7.3.0 - 2020-12-18 | ||
@@ -9,0 +13,0 @@ |
@@ -89,11 +89,14 @@ export declare const enum Engines { | ||
TableNode: TableNode; | ||
ResourceNode: ResourceNode; | ||
} | ||
export declare type ResourceNode = ['Resource', string]; | ||
declare type FromTypeNodes = FromTypeNode[keyof FromTypeNode] | AliasNode<FromTypeNode[keyof FromTypeNode]>; | ||
declare type AliasableFromTypeNodes = FromTypeNodes | AliasNode<FromTypeNodes>; | ||
export declare type SelectNode = ['Select', AbstractSqlType[]]; | ||
export declare type FromNode = ['From', FromTypeNodes]; | ||
export declare type InnerJoinNode = ['Join', FromTypeNodes, OnNode?]; | ||
export declare type LeftJoinNode = ['LeftJoin', FromTypeNodes, OnNode?]; | ||
export declare type RightJoinNode = ['RightJoin', FromTypeNodes, OnNode?]; | ||
export declare type FullJoinNode = ['FullJoin', FromTypeNodes, OnNode?]; | ||
export declare type CrossJoinNode = ['CrossJoin', FromTypeNodes]; | ||
export declare type FromNode = ['From', AliasableFromTypeNodes]; | ||
export declare type InnerJoinNode = ['Join', AliasableFromTypeNodes, OnNode?]; | ||
export declare type LeftJoinNode = ['LeftJoin', AliasableFromTypeNodes, OnNode?]; | ||
export declare type RightJoinNode = ['RightJoin', AliasableFromTypeNodes, OnNode?]; | ||
export declare type FullJoinNode = ['FullJoin', AliasableFromTypeNodes, OnNode?]; | ||
export declare type CrossJoinNode = ['CrossJoin', AliasableFromTypeNodes]; | ||
export declare type OnNode = ['On', BooleanTypeNodes]; | ||
@@ -148,2 +151,9 @@ export declare type TableNode = ['Table', string]; | ||
} | ||
export interface BindVars extends Array<any> { | ||
[key: string]: any; | ||
} | ||
export declare type Definition = FromTypeNodes | { | ||
binds?: BindVars; | ||
abstractSql: FromTypeNodes; | ||
}; | ||
export interface AbstractSqlTable { | ||
@@ -161,2 +171,3 @@ name: string; | ||
checks?: Check[]; | ||
definition?: Definition; | ||
} | ||
@@ -220,2 +231,4 @@ export interface ReferencedFields { | ||
export declare const isFromNode: (n: AbstractSqlType) => n is FromNode; | ||
export declare const isTableNode: (n: AbstractSqlType) => n is TableNode; | ||
export declare const isResourceNode: (n: AbstractSqlType) => n is ResourceNode; | ||
export declare function compileRule(abstractSQL: UpsertQueryNode, engine: Engines, noBinds: true): [string, string]; | ||
@@ -222,0 +235,0 @@ export declare function compileRule(abstractSQL: AbstractSqlQuery, engine: Engines, noBinds: true): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.websql = exports.mysql = exports.postgres = exports.compileRule = exports.isFromNode = exports.Engines = void 0; | ||
exports.websql = exports.mysql = exports.postgres = exports.compileRule = exports.isResourceNode = exports.isTableNode = exports.isFromNode = exports.Engines = void 0; | ||
var Engines; | ||
@@ -68,2 +68,19 @@ (function (Engines) { | ||
exports.isFromNode = isFromNode; | ||
const isTableNode = (n) => n[0] === 'Table'; | ||
exports.isTableNode = isTableNode; | ||
const isResourceNode = (n) => n[0] === 'Resource'; | ||
exports.isResourceNode = isResourceNode; | ||
const containsNode = (n, checkNodeTypeFn) => { | ||
for (const p of n) { | ||
if (Array.isArray(p)) { | ||
if (checkNodeTypeFn(p)) { | ||
return true; | ||
} | ||
else if (containsNode(p, checkNodeTypeFn)) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}; | ||
const getScope = (rulePart, scope) => { | ||
@@ -182,4 +199,6 @@ scope = { ...scope }; | ||
let ifNotExistsStr = ''; | ||
let orReplaceStr = ''; | ||
if (ifNotExists) { | ||
ifNotExistsStr = 'IF NOT EXISTS '; | ||
orReplaceStr = 'OR REPLACE '; | ||
} | ||
@@ -224,2 +243,38 @@ const createSchemaStatements = []; | ||
} | ||
const { definition } = table; | ||
if (definition != null) { | ||
let definitionAbstractSql; | ||
if (Array.isArray(definition)) { | ||
definitionAbstractSql = definition; | ||
} | ||
else { | ||
if (definition.binds != null && definition.binds.length > 0) { | ||
return; | ||
} | ||
definitionAbstractSql = definition.abstractSql; | ||
} | ||
if (containsNode(definitionAbstractSql, exports.isResourceNode)) { | ||
return; | ||
} | ||
if (exports.isTableNode(definitionAbstractSql)) { | ||
definitionAbstractSql = [ | ||
'SelectQuery', | ||
['Select', [['Field', '*']]], | ||
['From', definitionAbstractSql], | ||
]; | ||
} | ||
schemaDependencyMap[table.resourceName] = { | ||
resourceName, | ||
primitive: table.primitive, | ||
createSQL: [ | ||
`\ | ||
CREATE ${orReplaceStr}VIEW "${table.name}" AS ( | ||
${compileRule(definitionAbstractSql, engine, true).replace(/^/gm, ' ')} | ||
);`, | ||
], | ||
dropSQL: [`DROP VIEW "${table.name}";`], | ||
depends: [], | ||
}; | ||
return; | ||
} | ||
const foreignKeys = []; | ||
@@ -226,0 +281,0 @@ const depends = []; |
{ | ||
"name": "@balena/abstract-sql-compiler", | ||
"version": "7.3.0", | ||
"version": "7.4.0-definitions-480da0c6225ce0eb484522f6d3a65e31b47bd88b", | ||
"description": "A translator for abstract sql into sql.", | ||
@@ -5,0 +5,0 @@ "main": "out/AbstractSQLCompiler.js", |
@@ -154,3 +154,8 @@ export const enum Engines { | ||
TableNode: TableNode; | ||
ResourceNode: ResourceNode; | ||
} | ||
/** | ||
* This is not currently understood by the abstract-sql-compiler but is a placeholder for future support | ||
*/ | ||
export type ResourceNode = ['Resource', string]; | ||
@@ -161,9 +166,11 @@ type FromTypeNodes = | ||
type AliasableFromTypeNodes = FromTypeNodes | AliasNode<FromTypeNodes>; | ||
export type SelectNode = ['Select', AbstractSqlType[]]; | ||
export type FromNode = ['From', FromTypeNodes]; | ||
export type InnerJoinNode = ['Join', FromTypeNodes, OnNode?]; | ||
export type LeftJoinNode = ['LeftJoin', FromTypeNodes, OnNode?]; | ||
export type RightJoinNode = ['RightJoin', FromTypeNodes, OnNode?]; | ||
export type FullJoinNode = ['FullJoin', FromTypeNodes, OnNode?]; | ||
export type CrossJoinNode = ['CrossJoin', FromTypeNodes]; | ||
export type FromNode = ['From', AliasableFromTypeNodes]; | ||
export type InnerJoinNode = ['Join', AliasableFromTypeNodes, OnNode?]; | ||
export type LeftJoinNode = ['LeftJoin', AliasableFromTypeNodes, OnNode?]; | ||
export type RightJoinNode = ['RightJoin', AliasableFromTypeNodes, OnNode?]; | ||
export type FullJoinNode = ['FullJoin', AliasableFromTypeNodes, OnNode?]; | ||
export type CrossJoinNode = ['CrossJoin', AliasableFromTypeNodes]; | ||
export type OnNode = ['On', BooleanTypeNodes]; | ||
@@ -248,2 +255,11 @@ export type TableNode = ['Table', string]; | ||
} | ||
export interface BindVars extends Array<any> { | ||
[key: string]: any; | ||
} | ||
export type Definition = | ||
| FromTypeNodes | ||
| { | ||
binds?: BindVars; | ||
abstractSql: FromTypeNodes; | ||
}; | ||
export interface AbstractSqlTable { | ||
@@ -261,2 +277,3 @@ name: string; | ||
checks?: Check[]; | ||
definition?: Definition; | ||
} | ||
@@ -404,3 +421,28 @@ export interface ReferencedFields { | ||
n[0] === 'From'; | ||
export const isTableNode = (n: AbstractSqlType): n is TableNode => | ||
n[0] === 'Table'; | ||
export const isResourceNode = (n: AbstractSqlType): n is ResourceNode => | ||
n[0] === 'Resource'; | ||
/** | ||
* | ||
* @param n The abstract sql to check | ||
* @param checkNodeTypeFn A function that checks if a given node is the correct type | ||
*/ | ||
const containsNode = ( | ||
n: AbstractSqlType[], | ||
checkNodeTypeFn: (n: AbstractSqlType[number]) => boolean, | ||
): boolean => { | ||
for (const p of n) { | ||
if (Array.isArray(p)) { | ||
if (checkNodeTypeFn(p)) { | ||
return true; | ||
} else if (containsNode(p as AbstractSqlType[], checkNodeTypeFn)) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}; | ||
type Scope = _.Dictionary<string>; | ||
@@ -581,4 +623,6 @@ | ||
let ifNotExistsStr = ''; | ||
let orReplaceStr = ''; | ||
if (ifNotExists) { | ||
ifNotExistsStr = 'IF NOT EXISTS '; | ||
orReplaceStr = 'OR REPLACE '; | ||
} | ||
@@ -636,2 +680,45 @@ | ||
} | ||
const { definition } = table; | ||
if (definition != null) { | ||
let definitionAbstractSql; | ||
if (Array.isArray(definition)) { | ||
definitionAbstractSql = definition; | ||
} else { | ||
if (definition.binds != null && definition.binds.length > 0) { | ||
// If there are any binds then it's a dynamic definition and cannot become a view | ||
return; | ||
} | ||
definitionAbstractSql = definition.abstractSql; | ||
} | ||
// If there are any resource nodes then it's a dynamic definition and cannot become a view | ||
if ( | ||
containsNode(definitionAbstractSql as AbstractSqlType[], isResourceNode) | ||
) { | ||
return; | ||
} | ||
if (isTableNode(definitionAbstractSql)) { | ||
// If the definition is a table node we need to wrap it in a select query for the view creation | ||
definitionAbstractSql = [ | ||
'SelectQuery', | ||
['Select', [['Field', '*']]], | ||
['From', definitionAbstractSql], | ||
]; | ||
} | ||
schemaDependencyMap[table.resourceName] = { | ||
resourceName, | ||
primitive: table.primitive, | ||
createSQL: [ | ||
`\ | ||
CREATE ${orReplaceStr}VIEW "${table.name}" AS ( | ||
${compileRule(definitionAbstractSql as AbstractSqlQuery, engine, true).replace( | ||
/^/gm, | ||
' ', | ||
)} | ||
);`, | ||
], | ||
dropSQL: [`DROP VIEW "${table.name}";`], | ||
depends: [], | ||
}; | ||
return; | ||
} | ||
const foreignKeys: string[] = []; | ||
@@ -638,0 +725,0 @@ const depends: string[] = []; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
561649
50
12322
2