Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
basic
Manage
Activity
Members
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Model registry
Analyze
Contributor analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Admin message
Gitlab Maintenance 28.03.2025 | 20:00 - 23:00 MEZ
Show more breadcrumbs
xrm
basic
Commits
e871f452
Commit
e871f452
authored
5 years ago
by
Johannes Goderbauer
Browse files
Options
Downloads
Patches
Plain Diff
Liquibase_lib: first version
parent
813dc641
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
process/Liquibase_lib/Liquibase_lib.aod
+3
-0
3 additions, 0 deletions
process/Liquibase_lib/Liquibase_lib.aod
process/Liquibase_lib/process.js
+306
-45
306 additions, 45 deletions
process/Liquibase_lib/process.js
with
309 additions
and
45 deletions
process/Liquibase_lib/Liquibase_lib.aod
+
3
−
0
View file @
e871f452
...
...
@@ -3,4 +3,7 @@
<name>
Liquibase_lib
</name>
<majorModelMode>
DISTRIBUTED
</majorModelMode>
<process>
%aditoprj%/process/Liquibase_lib/process.js
</process>
<variants>
<element>
LIBRARY
</element>
</variants>
</process>
This diff is collapsed.
Click to expand it.
process/Liquibase_lib/process.js
+
306
−
45
View file @
e871f452
import
(
"
system.translate
"
);
import
(
"
Util_lib
"
);
import
(
"
system.fileIO
"
);
import
(
"
system.datetime
"
);
import
(
"
system.SQLTYPES
"
);
import
(
"
system.db
"
);
import
(
"
system.util
"
);
/**
* functions for various Liquibase-actions
* Do not create an instance of this!
*
* @class
* @static
*/
function
LiquiUtils
(){}
LiquiUtils
.
exportToLiquibase
=
function
(
pAuthor
,
pTableName
,
pColumns
,
pNewUUIDForIndexes
,
pCondition
)
/**
* exports all tables(except the liquibase-tables "DATABASECHANGELOG" and "DATABASECHANGELOGLOCK") from the database as files into a specific
* server-folder; these files are in the liquibase-changeset-format to apply them via liquibase to a database
* when a long clob-value or a blob value is exported subfolders are created with files for it's contents (no ending for blobs, .txt-ending for clobs)
*
* @param {String} pOutFolderPath path where the files and folders will be created; this folder should be empty; it must be on the server
* @param {String} [pAuthor="autogenerated"] author that will be written into the liquibase-changesets
* @param {String} [pAlias=current db-alias] alias where the data will be loaded from
* @param {Array} [pExcludedTables=none] tables that will be excluded from the tables that are exported; case-insensitive;
* note that the liquibase tables "DATABASECHANGELOG" and "DATABASECHANGELOGLOCK" will never be exported
* (regardless of what you specify here)
* @param {Boolean} [pIncludeClearTableDirective=false] if true, a delete element is added at the beginning of the changeset for the table
*
* @return void
*
*/
LiquiUtils
.
exportAllTablesAsLiquibaseFiles
=
function
(
pOutFolderPath
,
pAuthor
,
pAlias
,
pExcludedTables
,
pIncludeClearTableDirective
)
{
if
(
!
pNewUUIDForIndexes
)
pNewUUIDForIndexes
=
[]
var
xmlData
=
<
databaseChangeLog
xmlns
=
"
http://www.liquibase.org/xml/ns/dbchangelog
"
xmlns
:
ext
=
"
http://www.liquibase.org/xml/ns/dbchangelog-ext
"
xmlns
:
xsi
=
"
http://www.w3.org/2001/XMLSchema-instance
"
xsi
:
schemaLocation
=
"
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd
"
/>
;
xmlData
.
changeSet
.@
author
=
pAuthor
xmlData
.
changeSet
.@
id
=
util
.
getNewUUID
()
var
excludedTables
=
[
"
DATABASECHANGELOG
"
,
"
DATABASECHANGELOGLOCK
"
];
//liquibase-tables - therefor they shall never be included
if
(
pExcludedTables
)
excludedTables
=
excludedTables
.
concat
(
pExcludedTables
);
var
alias
=
pAlias
||
db
.
getCurrentAlias
();
var
tables
=
db
.
getTables
(
alias
);
for
(
var
i
=
0
,
l
=
tables
.
length
;
i
<
l
;
i
++
)
{
if
(
ArrayUtils
.
hasElement
(
excludedTables
,
tables
[
i
],
true
))
continue
;
var
columns
=
db
.
getColumns
(
tables
[
i
],
alias
);
var
cond
=
null
;
LiquiUtils
.
exportTableAsLiquibaseFiles
(
pOutFolderPath
,
tables
[
i
],
columns
,
cond
,
pAuthor
,
pIncludeClearTableDirective
,
alias
);
}
};
/**
* exports a single table from the database as liquibase-changeset-file(s) into a specific server-folder
* when a long clob-value or a blob value is exported subfolders are created with files for it's contents (no ending for blobs, .txt-ending for clobs)
*
* @param {String} pPath file-path where the files and folders will be created; the folder must be on the server
* @param {String} pTableName name of the DB-table that will be exported; this is also the name of the file that is stored
* @param {Array} pColumns db-columns within the table that will be exported
* @param {String} [pCondition=none] db-condition to limit the data that will be exported; if nothing given the whole content will be exported
* @param {String} [pAuthor="autogenerated"] author that will be written into the liquibase-changeset
* @param {Boolean} [pIncludeClearTableDirective=false] if true, a delete element is added at the beginning of the changeset for the table
* @param {String} [pAlias=current db-alias] alias where the data will be loaded from
*
* @return {null} returns currently always null
*/
LiquiUtils
.
exportTableAsLiquibaseFiles
=
function
(
pPath
,
pTableName
,
pColumns
,
pCondition
,
pAuthor
,
pIncludeClearTableDirective
,
pAlias
)
{
var
resXml
=
LiquiUtils
.
_getDataXml
(
pAuthor
,
pPath
,
pTableName
,
pColumns
,
pCondition
,
pIncludeClearTableDirective
,
pAlias
);
if
(
resXml
==
""
)
return
null
;
var
dbData
=
db
.
table
(
"
select
"
+
pColumns
.
join
(
"
,
"
)
+
"
from
"
+
pTableName
+
"
"
+
(
pCondition
?
pCondition
:
""
));
var
types
=
db
.
getColumnTypes
(
pTableName
,
pColumns
);
fileIO
.
mkdir
(
pPath
,
true
);
var
fullFileName
=
pPath
+=
"
/
"
+
pTableName
+
"
.xml
"
;
fileIO
.
storeData
(
fullFileName
,
resXml
,
util
.
DATA_TEXT
,
false
,
"
UTF8
"
);
return
null
;
};
/**
* generates from a table a xml-changeset for liquibase; determines the correct liquibase-xml-attribute by db-column-type;
* if a value is empty it will not be added to the xml; will load the data at once (no paging);
* if the data contains a long CLOB-value that value has to and will be stored on the server-filesystem;
* if the data contains any BLOB-value that value has to and will be stored on the server-filesystem;
*
* @param {String} [pAuthor="autogenerated"] author that will be written into the changeset
* @param {String} [pLobPath=not set] file-path where lob files and folders will be created; the folder must be on the server;
* if you've no lob-fields you don't have to specify somehing here
* @param {String} pTableName name of the DB-table that will be exported; this is also the name of the file that is stored
* @param {Array} pColumns db-columns within the table that will be exported
* @param {String} [pCondition=none] db-condition to limit the data that will be exported; if nothing given the whole content will be exported
* @param {Boolean} [pIncludeClearTableDirective=false] if true, a delete element is added at the beginning of the changeset for the table
* @param {String} [pAlias=current db-alias] alias where the data will be loaded from
*
* @return {String} the liquibase-changest in xml-form
*/
LiquiUtils
.
_getDataXml
=
function
(
pAuthor
,
pLobPath
,
pTableName
,
pColumns
,
pCondition
,
pIncludeClearTableDirective
,
pAlias
)
{
var
author
=
pAuthor
||
"
autogenerated
"
;
var
alias
=
pAlias
||
db
.
getCurrentAlias
();
//cannot be added within jdito code to the XML-object, so instead add it as string
var
XML_HEADER_LINE
=
'
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
'
;
dbData
.
forEach
(
function
(
pRow
)
{
var
node
=
<
insert
/>
;
node
.@
tableName
=
pTableName
;
for
(
let
i
=
0
;
i
<
pColumns
.
length
;
i
++
)
var
dbData
=
db
.
table
(
"
select
"
+
pColumns
.
join
(
"
,
"
)
+
"
from
"
+
pTableName
+
"
"
+
(
pCondition
?
pCondition
:
""
),
alias
);
if
(
dbData
.
length
==
0
)
return
""
;
var
colTypes
=
db
.
getColumnTypes
(
pTableName
,
pColumns
,
alias
);
//every type has its function that accepts a columnName- and a value-parameter
//so let's dertermine once the corresponding funtion to its type for faster access
//(the function will only depend on the type and not change per datarow - so no need to determine the correct function per datarow)
var
colCallbackFn
=
colTypes
.
map
(
function
(
colType
){
if
(
SQLTYPES
.
isNumberType
(
colType
))
return
LiquiXTable
.
prototype
.
addNumberCol
;
else
if
(
SQLTYPES
.
isDateType
(
colType
))
{
var
value
=
""
;
for
(
j
=
0
;
j
<
pNewUUIDForIndexes
.
length
;
j
++
)
{
if
(
i
==
pNewUUIDForIndexes
[
j
])
{
value
=
util
.
getNewUUID
();
break
;
}
}
if
(
!
value
)
value
=
pRow
[
i
];
var
col
=
<
column
/>
;
col
.@
name
=
pColumns
[
i
];
if
(
colType
==
SQLTYPES
.
DATE
)
return
LiquiXTable
.
prototype
.
addDateCol
;
else
return
LiquiXTable
.
prototype
.
addDateTimeCol
;
}
else
if
(
SQLTYPES
.
isLOBType
(
colType
))
{
if
(
colType
==
SQLTYPES
.
BLOB
)
return
LiquiXTable
.
prototype
.
addBlobCol
;
else
return
LiquiXTable
.
prototype
.
addClobCol
;
}
else
return
LiquiXTable
.
prototype
.
addStrCol
;
});
var
columnLen
=
pColumns
.
length
;
var
changeLogXml
=
LiquiXmlUtils
.
databaseChangeLog
(
author
);
if
(
pIncludeClearTableDirective
)
changeLogXml
.
changeSet
.
appendChild
(
<
delete
tableName
=
{
pTableName
}
/>
)
;
dbData
.
forEach
(
function
(
row
)
{
var
tableXml
=
LiquiXTable
.
make
(
pTableName
);
if
(
pLobPath
)
tableXml
.
setLobBasePath
(
pLobPath
);
for
(
var
i
=
0
;
i
<
columnLen
;
i
++
)
{
var
colName
=
pColumns
[
i
];
var
value
=
row
[
i
];
var
fnToUse
=
colCallbackFn
[
i
];
if
(
fnToUse
!=
null
)
fnToUse
.
call
(
tableXml
,
colName
,
value
)
}
changeLogXml
.
changeSet
.
insert
+=
tableXml
.
xml
;
});
return
XML_HEADER_LINE
+
"
\n
"
+
changeLogXml
;
};
/**
* contains functions which create small fragments of XML-objects for liquibase-changesets
* Do not create an instance of this!
*
* @class
* @static
*/
function
LiquiXmlUtils
(){}
//TODO: comments
LiquiXmlUtils
.
databaseChangeLog
=
function
(
pAuthor
,
pChangeSetId
)
{
if
(
pChangeSetId
==
undefined
)
pChangeSetId
=
util
.
getNewUUID
();
var
dbcl
=
<
databaseChangeLog
xmlns
=
"
http://www.liquibase.org/xml/ns/dbchangelog
"
xmlns
:
ext
=
"
http://www.liquibase.org/xml/ns/dbchangelog-ext
"
xmlns
:
xsi
=
"
http://www.w3.org/2001/XMLSchema-instance
"
xsi
:
schemaLocation
=
"
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd
"
/>
;
// do not add value if null
if
(
value
)
{
if
(
SQLTYPES
.
isNumberType
(
types
[
i
]))
col
.@
valueNumeric
=
value
;
else
col
.@
value
=
value
;
}
dbcl
.
changeSet
=
<
changeSet
author
=
{
pAuthor
}
id
=
{
pChangeSetId
}
/>
;
return
dbcl
;
};
LiquiXmlUtils
.
colValue
=
function
(
name
,
value
,
valueAttribute
)
{
var
DO_NOT_ADD_EMPTY_VALUES
=
true
;
//clob and blob will ignore this setting and always skip empty values
if
(
DO_NOT_ADD_EMPTY_VALUES
&&
value
==
""
)
return
null
;
var
x
=
<
column
{
valueAttribute
}
=
{
value
}
/>
;
x
.@
name
=
name
;
return
x
;
};
LiquiXmlUtils
.
colStr
=
function
(
name
,
valueStr
)
{
return
LiquiXmlUtils
.
colValue
(
name
,
valueStr
,
"
value
"
);
};
LiquiXmlUtils
.
colDateTime
=
function
(
name
,
valueDate
,
type
)
{
if
(
valueDate
.
toString
()
===
parseInt
(
valueDate
,
10
).
toString
())
{
if
(
type
==
"
date
"
)
valueDate
=
datetime
.
toDate
(
valueDate
,
"
yyyy-MM-dd
"
);
else
valueDate
=
datetime
.
toDate
(
valueDate
,
"
yyyy-MM-dd'T'hh:mm:ss
"
);
}
//Unterscheiden zwischen datetime & date!!
return
LiquiXmlUtils
.
colValue
(
name
,
valueDate
,
"
valueDate
"
);
};
LiquiXmlUtils
.
colNumber
=
function
(
name
,
valueNumber
)
{
return
LiquiXmlUtils
.
colValue
(
name
,
valueNumber
,
"
valueNumeric
"
);
};
LiquiXmlUtils
.
tableIns
=
function
(
table
)
{
var
x
=
<
insert
tableName
=
{
table
}
/>
;
return
x
;
};
LiquiXmlUtils
.
_resolveId
=
function
(
pIdValue
)
{
return
pIdValue
;
};
/**
* represents a liquibase-insert-into-table changeset element (as XML) and provides functions which make it easier to add columns-entries with values
*
* @class
*/
function
LiquiXTable
(
pName
)
{
this
.
_name
=
pName
;
this
.
_mode
=
"
insert
"
;
this
.
setLobBasePath
(
""
);
this
.
xml
=
LiquiXmlUtils
.
tableIns
(
pName
);
}
LiquiXTable
.
make
=
function
(
pName
)
{
return
new
LiquiXTable
(
pName
);
};
LiquiXTable
.
prototype
.
setLobBasePath
=
function
(
pPath
)
{
//to build later the lob-path corretly it's necessary to always have the last symbol a folder-splitter-char
//but it's okay to have no lobPath at all IF no long clob value and no blob value will be added
if
(
pPath
)
{
var
lastChar
=
pPath
.
slice
(
-
1
);
if
(
lastChar
!=
"
\\
"
&&
lastChar
!=
"
/
"
)
pPath
=
pPath
+
"
/
"
;
}
node
.
appendChild
(
col
);
}
this
.
appendChild
(
node
);
},
xmlData
.
changeSet
);
return
xmlData
.
toXMLString
()
this
.
_lobBasePath
=
pPath
;
};
LiquiXTable
.
prototype
.
appendIfNotNull
=
function
(
xmlToAppend
)
{
if
(
xmlToAppend
!=
null
)
this
.
xml
[
this
.
_mode
]
+=
xmlToAppend
;
return
this
;
};
LiquiXTable
.
prototype
.
addStrCol
=
function
(
pColName
,
pValue
)
{
return
this
.
appendIfNotNull
(
LiquiXmlUtils
.
colStr
(
pColName
,
pValue
));
};
LiquiXTable
.
prototype
.
addClobCol
=
function
(
pColName
,
pValue
)
{
if
(
pValue
==
""
)
return
this
;
else
if
(
pValue
.
length
<=
1000
)
return
this
.
addStrCol
(
pColName
,
pValue
);
else
{
var
lobBasePath
=
this
.
_lobBasePath
;
if
(
!
lobBasePath
)
throw
new
Error
(
translate
.
withArguments
(
"
[%0]it was necessary to create a text-file from a clob-field but no lob-file-path was specified.
"
+
"
The lob-file-path is required when adding long clob-values. value length was %1.
"
,
[
"
LiquiXTable addClobCol
"
,
pValue
.
length
]));
var
relativeFolderPath
=
this
.
_name
+
"
/
"
+
pColName
+
"
/clobFiles/
"
;
var
fileName
=
util
.
getNewUUID
()
+
"
.txt
"
;
fileIO
.
mkdir
(
lobBasePath
+
relativeFolderPath
,
true
);
fileIO
.
storeData
(
lobBasePath
+
relativeFolderPath
+
fileName
,
pValue
,
util
.
DATA_TEXT
,
false
,
"
UTF8
"
);
return
this
.
appendIfNotNull
(
LiquiXmlUtils
.
colValue
(
pColName
,
relativeFolderPath
+
fileName
,
"
valueClobFile
"
));
}
};
LiquiXTable
.
prototype
.
addBlobCol
=
function
(
pColName
,
pValue
)
{
if
(
pValue
==
""
)
return
this
;
var
lobBasePath
=
this
.
_lobBasePath
;
if
(
!
lobBasePath
)
throw
new
Error
(
translate
.
withArguments
(
"
[%0]it was necessary to create a file from a blob-field but no lob-file-path was specified.
"
+
"
The lob-file-path is required when adding blob-values.
"
,
[
"
LiquiXTable addClobCol
"
]));
var
relativeFolderPath
=
this
.
_name
+
"
/
"
+
pColName
+
"
/blobFiles/
"
;
var
fileName
=
util
.
getNewUUID
();
fileIO
.
mkdir
(
lobBasePath
+
relativeFolderPath
,
true
);
fileIO
.
storeData
(
lobBasePath
+
relativeFolderPath
+
fileName
,
pValue
,
util
.
DATA_BINARY
,
false
);
return
this
.
appendIfNotNull
(
LiquiXmlUtils
.
colValue
(
pColName
,
relativeFolderPath
+
fileName
,
"
valueBlobFile
"
));
};
LiquiXTable
.
prototype
.
addIdCol
=
function
(
pColName
,
pValue
)
{
pValue
=
pValue
.
toString
();
return
this
.
appendIfNotNull
(
LiquiXmlUtils
.
colStr
(
pColName
,
LiquiXmlUtils
.
_resolveId
(
pValue
)));
};
LiquiXTable
.
prototype
.
addDateTimeCol
=
function
(
pColName
,
pValue
)
{
return
this
.
appendIfNotNull
(
LiquiXmlUtils
.
colDateTime
(
pColName
,
pValue
));
};
LiquiXTable
.
prototype
.
addDateCol
=
function
(
pColName
,
pValue
)
{
return
this
.
appendIfNotNull
(
LiquiXmlUtils
.
colDateTime
(
pColName
,
pValue
,
"
date
"
));
};
LiquiXTable
.
prototype
.
addNumberCol
=
function
(
pColName
,
pValue
)
{
return
this
.
appendIfNotNull
(
LiquiXmlUtils
.
colNumber
(
pColName
,
pValue
));
};
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment